summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml22
-rw-r--r--Makefile4
-rw-r--r--README.md9
-rw-r--r--RELEASE_NOTES.md20
-rw-r--r--cmd/podman/common/completion.go58
-rw-r--r--cmd/podman/common/create.go10
-rw-r--r--cmd/podman/common/create_opts.go12
-rw-r--r--cmd/podman/common/netflags.go2
-rw-r--r--cmd/podman/common/specgen.go4
-rw-r--r--cmd/podman/completion/completion.go2
-rw-r--r--cmd/podman/containers/cp.go318
-rw-r--r--cmd/podman/containers/create.go4
-rw-r--r--cmd/podman/containers/kill.go8
-rw-r--r--cmd/podman/containers/logs.go3
-rw-r--r--cmd/podman/containers/mount.go8
-rw-r--r--cmd/podman/containers/run.go11
-rw-r--r--cmd/podman/images/build.go3
-rw-r--r--cmd/podman/images/pull.go2
-rw-r--r--cmd/podman/images/sign.go1
-rw-r--r--cmd/podman/inspect/inspect.go2
-rw-r--r--cmd/podman/main.go5
-rw-r--r--cmd/podman/manifest/push.go2
-rw-r--r--cmd/podman/play/kube.go2
-rw-r--r--cmd/podman/root.go4
-rw-r--r--cmd/podman/system/connection/add.go61
-rw-r--r--cmd/podman/system/prune.go27
-rw-r--r--cmd/podman/system/service_abi.go11
-rw-r--r--cmd/podman/utils/utils.go35
-rw-r--r--cmd/podman/volumes/prune.go16
-rw-r--r--commands-demo.md2
-rwxr-xr-xcontrib/cirrus/ext_svc_check.sh2
-rw-r--r--contrib/cirrus/lib.sh6
-rwxr-xr-xcontrib/cirrus/logcollector.sh4
-rwxr-xr-xcontrib/cirrus/logformatter2
-rw-r--r--contrib/cirrus/required_host_ports.txt1
-rwxr-xr-xcontrib/cirrus/runner.sh12
-rwxr-xr-xcontrib/cirrus/setup_environment.sh39
-rw-r--r--contrib/podmanimage/stable/manual/Containerfile2
-rw-r--r--contrib/remote/containers.conf2
-rw-r--r--contrib/rootless-cni-infra/Containerfile2
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--contrib/systemd/system/podman.service2
-rw-r--r--contrib/tmpfile/podman.conf5
-rw-r--r--docs/Readme.md2
-rw-r--r--docs/source/_static/api.html2
-rw-r--r--docs/source/markdown/podman-build.1.md2
-rw-r--r--docs/source/markdown/podman-container-prune.1.md12
-rw-r--r--docs/source/markdown/podman-cp.1.md14
-rw-r--r--docs/source/markdown/podman-create.1.md4
-rw-r--r--docs/source/markdown/podman-generate-kube.1.md2
-rw-r--r--docs/source/markdown/podman-image-prune.1.md12
-rw-r--r--docs/source/markdown/podman-image-sign.1.md4
-rw-r--r--docs/source/markdown/podman-info.1.md151
-rw-r--r--docs/source/markdown/podman-kill.1.md8
-rw-r--r--docs/source/markdown/podman-play-kube.1.md2
-rw-r--r--docs/source/markdown/podman-ps.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md22
-rw-r--r--docs/source/markdown/podman-system-prune.1.md16
-rw-r--r--docs/source/markdown/podman-system-service.1.md2
-rw-r--r--docs/source/markdown/podman-volume-prune.1.md16
-rw-r--r--docs/source/markdown/podman.1.md6
-rw-r--r--go.mod20
-rw-r--r--go.sum57
-rwxr-xr-xhack/install_golangci.sh2
-rw-r--r--libpod/boltdb_state_linux.go2
-rw-r--r--libpod/container_api.go2
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_inspect.go7
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_internal_linux.go9
-rw-r--r--libpod/container_log.go2
-rw-r--r--libpod/container_top_unsupported.go2
-rw-r--r--libpod/container_validate.go2
-rw-r--r--libpod/define/container_inspect.go13
-rw-r--r--libpod/define/info.go11
-rw-r--r--libpod/events/events.go3
-rw-r--r--libpod/events/journal_linux.go23
-rw-r--r--libpod/events/logfile.go12
-rw-r--r--libpod/image/df.go2
-rw-r--r--libpod/image/image.go2
-rw-r--r--libpod/image/parts.go2
-rw-r--r--libpod/image/prune.go23
-rw-r--r--libpod/image/search.go2
-rw-r--r--libpod/image/utils.go58
-rw-r--r--libpod/info.go17
-rw-r--r--libpod/kube.go4
-rw-r--r--libpod/logs/log.go22
-rw-r--r--libpod/network/create_test.go2
-rw-r--r--libpod/network/netconflist.go6
-rw-r--r--libpod/network/netconflist_test.go6
-rw-r--r--libpod/networking_linux.go7
-rw-r--r--libpod/oci.go2
-rw-r--r--libpod/oci_attach_linux.go2
-rw-r--r--libpod/oci_conmon_exec_linux.go2
-rw-r--r--libpod/oci_conmon_linux.go53
-rw-r--r--libpod/options.go5
-rw-r--r--libpod/pod_top_linux.go2
-rw-r--r--libpod/reset.go37
-rw-r--r--libpod/rootless_cni_linux.go4
-rw-r--r--libpod/runtime_ctr.go27
-rw-r--r--libpod/runtime_img.go2
-rw-r--r--libpod/runtime_volume.go27
-rw-r--r--libpod/runtime_volume_linux.go2
-rw-r--r--libpod/state_test.go6
-rw-r--r--libpod/util.go39
-rw-r--r--libpod/volume.go14
-rw-r--r--nix/default.nix4
-rw-r--r--nix/nixpkgs.json11
-rw-r--r--pkg/annotations/annotations.go2
-rw-r--r--pkg/api/handlers/compat/containers.go49
-rw-r--r--pkg/api/handlers/compat/containers_archive.go97
-rw-r--r--pkg/api/handlers/compat/containers_create.go15
-rw-r--r--pkg/api/handlers/compat/containers_prune.go34
-rw-r--r--pkg/api/handlers/compat/events.go8
-rw-r--r--pkg/api/handlers/compat/images.go17
-rw-r--r--pkg/api/handlers/compat/images_search.go16
-rw-r--r--pkg/api/handlers/compat/info.go2
-rw-r--r--pkg/api/handlers/compat/networks.go6
-rw-r--r--pkg/api/handlers/compat/resize.go8
-rw-r--r--pkg/api/handlers/compat/volumes.go20
-rw-r--r--pkg/api/handlers/libpod/images.go81
-rw-r--r--pkg/api/handlers/libpod/images_pull.go4
-rw-r--r--pkg/api/handlers/libpod/system.go19
-rw-r--r--pkg/api/handlers/libpod/volumes.go28
-rw-r--r--pkg/api/handlers/utils/pods.go4
-rw-r--r--pkg/api/server/register_archive.go10
-rw-r--r--pkg/api/server/register_containers.go1
-rw-r--r--pkg/api/server/register_images.go2
-rw-r--r--pkg/api/server/server.go2
-rw-r--r--pkg/api/server/swagger.go3
-rw-r--r--pkg/autoupdate/autoupdate.go2
-rw-r--r--pkg/bindings/connection.go49
-rw-r--r--pkg/bindings/containers/archive.go92
-rw-r--r--pkg/bindings/containers/attach.go67
-rw-r--r--pkg/bindings/containers/checkpoint.go57
-rw-r--r--pkg/bindings/containers/commit.go33
-rw-r--r--pkg/bindings/containers/containers.go182
-rw-r--r--pkg/bindings/containers/create.go6
-rw-r--r--pkg/bindings/containers/diff.go6
-rw-r--r--pkg/bindings/containers/exec.go12
-rw-r--r--pkg/bindings/containers/healthcheck.go6
-rw-r--r--pkg/bindings/containers/logs.go32
-rw-r--r--pkg/bindings/containers/mount.go18
-rw-r--r--pkg/bindings/containers/types.go206
-rw-r--r--pkg/bindings/containers/types_attach_options.go136
-rw-r--r--pkg/bindings/containers/types_checkpoint_options.go168
-rw-r--r--pkg/bindings/containers/types_commit_options.go200
-rw-r--r--pkg/bindings/containers/types_create_options.go88
-rw-r--r--pkg/bindings/containers/types_diff_options.go88
-rw-r--r--pkg/bindings/containers/types_execinspect_options.go88
-rw-r--r--pkg/bindings/containers/types_execstart_options.go88
-rw-r--r--pkg/bindings/containers/types_execstartandattach_options.go186
-rw-r--r--pkg/bindings/containers/types_export_options.go88
-rw-r--r--pkg/bindings/containers/types_healthcheck_options.go88
-rw-r--r--pkg/bindings/containers/types_init_options.go88
-rw-r--r--pkg/bindings/containers/types_inspect_options.go104
-rw-r--r--pkg/bindings/containers/types_kill_options.go88
-rw-r--r--pkg/bindings/containers/types_list_options.go186
-rw-r--r--pkg/bindings/containers/types_log_options.go200
-rw-r--r--pkg/bindings/containers/types_mount_options.go88
-rw-r--r--pkg/bindings/containers/types_mountedcontainerpaths_options.go88
-rw-r--r--pkg/bindings/containers/types_pause_options.go88
-rw-r--r--pkg/bindings/containers/types_prune_options.go104
-rw-r--r--pkg/bindings/containers/types_remove_options.go120
-rw-r--r--pkg/bindings/containers/types_resizeexectty_options.go120
-rw-r--r--pkg/bindings/containers/types_resizetty_options.go120
-rw-r--r--pkg/bindings/containers/types_restart_options.go104
-rw-r--r--pkg/bindings/containers/types_restore_options.go200
-rw-r--r--pkg/bindings/containers/types_shouldrestart_options.go88
-rw-r--r--pkg/bindings/containers/types_start_options.go104
-rw-r--r--pkg/bindings/containers/types_stats_options.go104
-rw-r--r--pkg/bindings/containers/types_stop_options.go104
-rw-r--r--pkg/bindings/containers/types_top_options.go104
-rw-r--r--pkg/bindings/containers/types_unmount_options.go88
-rw-r--r--pkg/bindings/containers/types_unpause_options.go88
-rw-r--r--pkg/bindings/containers/types_wait_options.go105
-rw-r--r--pkg/bindings/generate/generate.go35
-rw-r--r--pkg/bindings/generate/types.go27
-rw-r--r--pkg/bindings/generate/types_kube_options.go104
-rw-r--r--pkg/bindings/generate/types_systemd_options.go200
-rw-r--r--pkg/bindings/generator/generator.go261
-rw-r--r--pkg/bindings/images/diff.go6
-rw-r--r--pkg/bindings/images/images.go211
-rw-r--r--pkg/bindings/images/pull.go26
-rw-r--r--pkg/bindings/images/rm.go45
-rw-r--r--pkg/bindings/images/types.go193
-rw-r--r--pkg/bindings/images/types_diff_options.go88
-rw-r--r--pkg/bindings/images/types_export_options.go120
-rw-r--r--pkg/bindings/images/types_get_options.go104
-rw-r--r--pkg/bindings/images/types_history_options.go88
-rw-r--r--pkg/bindings/images/types_import_options.go152
-rw-r--r--pkg/bindings/images/types_list_options.go120
-rw-r--r--pkg/bindings/images/types_load_options.go104
-rw-r--r--pkg/bindings/images/types_prune_options.go120
-rw-r--r--pkg/bindings/images/types_pull_options.go281
-rw-r--r--pkg/bindings/images/types_push_options.go280
-rw-r--r--pkg/bindings/images/types_remove_options.go120
-rw-r--r--pkg/bindings/images/types_search_options.go184
-rw-r--r--pkg/bindings/images/types_tag_options.go88
-rw-r--r--pkg/bindings/images/types_tree_options.go104
-rw-r--r--pkg/bindings/images/types_untag_options.go88
-rw-r--r--pkg/bindings/manifests/manifests.go52
-rw-r--r--pkg/bindings/manifests/types.go36
-rw-r--r--pkg/bindings/manifests/types_add_options.go216
-rw-r--r--pkg/bindings/manifests/types_create_options.go104
-rw-r--r--pkg/bindings/manifests/types_inspect_options.go88
-rw-r--r--pkg/bindings/manifests/types_push_options.go104
-rw-r--r--pkg/bindings/manifests/types_remove_options.go88
-rw-r--r--pkg/bindings/network/network.go80
-rw-r--r--pkg/bindings/network/types.go70
-rw-r--r--pkg/bindings/network/types_connect_options.go104
-rw-r--r--pkg/bindings/network/types_create_options.go265
-rw-r--r--pkg/bindings/network/types_disconnect_options.go104
-rw-r--r--pkg/bindings/network/types_inspect_options.go88
-rw-r--r--pkg/bindings/network/types_list_options.go104
-rw-r--r--pkg/bindings/network/types_remove_options.go104
-rw-r--r--pkg/bindings/play/play.go24
-rw-r--r--pkg/bindings/play/types.go32
-rw-r--r--pkg/bindings/play/types_kube_options.go280
-rw-r--r--pkg/bindings/pods/pods.go113
-rw-r--r--pkg/bindings/pods/types.go72
-rw-r--r--pkg/bindings/pods/types_create_options.go88
-rw-r--r--pkg/bindings/pods/types_inspect_options.go88
-rw-r--r--pkg/bindings/pods/types_kill_options.go104
-rw-r--r--pkg/bindings/pods/types_list_options.go104
-rw-r--r--pkg/bindings/pods/types_pause_options.go88
-rw-r--r--pkg/bindings/pods/types_prune_options.go88
-rw-r--r--pkg/bindings/pods/types_remove_options.go104
-rw-r--r--pkg/bindings/pods/types_restart_options.go88
-rw-r--r--pkg/bindings/pods/types_start_options.go88
-rw-r--r--pkg/bindings/pods/types_stats_options.go104
-rw-r--r--pkg/bindings/pods/types_stop_options.go104
-rw-r--r--pkg/bindings/pods/types_top_options.go104
-rw-r--r--pkg/bindings/pods/types_unpause_options.go88
-rw-r--r--pkg/bindings/system/info.go6
-rw-r--r--pkg/bindings/system/system.go53
-rw-r--r--pkg/bindings/system/types.go34
-rw-r--r--pkg/bindings/system/types_disk_options.go88
-rw-r--r--pkg/bindings/system/types_events_options.go152
-rw-r--r--pkg/bindings/system/types_info_options.go88
-rw-r--r--pkg/bindings/system/types_prune_options.go136
-rw-r--r--pkg/bindings/system/types_version_options.go88
-rw-r--r--pkg/bindings/test/attach_test.go17
-rw-r--r--pkg/bindings/test/auth_test.go42
-rw-r--r--pkg/bindings/test/common_test.go4
-rw-r--r--pkg/bindings/test/containers_test.go132
-rw-r--r--pkg/bindings/test/create_test.go2
-rw-r--r--pkg/bindings/test/exec_test.go4
-rw-r--r--pkg/bindings/test/images_test.go106
-rw-r--r--pkg/bindings/test/info_test.go12
-rw-r--r--pkg/bindings/test/manifests_test.go33
-rw-r--r--pkg/bindings/test/pods_test.go81
-rw-r--r--pkg/bindings/test/system_test.go106
-rw-r--r--pkg/bindings/test/volumes_test.go81
-rw-r--r--pkg/bindings/volumes/types.go32
-rw-r--r--pkg/bindings/volumes/types_create_options.go88
-rw-r--r--pkg/bindings/volumes/types_inspect_options.go88
-rw-r--r--pkg/bindings/volumes/types_list_options.go104
-rw-r--r--pkg/bindings/volumes/types_prune_options.go104
-rw-r--r--pkg/bindings/volumes/types_remove_options.go104
-rw-r--r--pkg/bindings/volumes/volumes.go45
-rw-r--r--pkg/cgroups/cgroups.go2
-rw-r--r--pkg/copy/copy.go220
-rw-r--r--pkg/copy/fileinfo.go57
-rw-r--r--pkg/copy/item.go588
-rw-r--r--pkg/domain/entities/container_ps.go2
-rw-r--r--pkg/domain/entities/containers.go25
-rw-r--r--pkg/domain/entities/engine_container.go12
-rw-r--r--pkg/domain/entities/engine_image.go5
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/domain/entities/reports/prune.go40
-rw-r--r--pkg/domain/entities/system.go15
-rw-r--r--pkg/domain/entities/volumes.go8
-rw-r--r--pkg/domain/filters/containers.go (renamed from libpod/filters/containers.go)32
-rw-r--r--pkg/domain/filters/helpers.go20
-rw-r--r--pkg/domain/filters/pods.go (renamed from libpod/filters/pods.go)2
-rw-r--r--pkg/domain/filters/volumes.go3
-rw-r--r--pkg/domain/infra/abi/archive.go172
-rw-r--r--pkg/domain/infra/abi/containers.go34
-rw-r--r--pkg/domain/infra/abi/containers_stat.go251
-rw-r--r--pkg/domain/infra/abi/cp.go70
-rw-r--r--pkg/domain/infra/abi/images.go85
-rw-r--r--pkg/domain/infra/abi/manifest.go17
-rw-r--r--pkg/domain/infra/abi/parse/parse.go6
-rw-r--r--pkg/domain/infra/abi/play.go18
-rw-r--r--pkg/domain/infra/abi/pods.go4
-rw-r--r--pkg/domain/infra/abi/system.go49
-rw-r--r--pkg/domain/infra/abi/volumes.go22
-rw-r--r--pkg/domain/infra/runtime_abi.go4
-rw-r--r--pkg/domain/infra/runtime_tunnel.go28
-rw-r--r--pkg/domain/infra/tunnel/containers.go301
-rw-r--r--pkg/domain/infra/tunnel/events.go4
-rw-r--r--pkg/domain/infra/tunnel/generate.go14
-rw-r--r--pkg/domain/infra/tunnel/healthcheck.go2
-rw-r--r--pkg/domain/infra/tunnel/helpers.go9
-rw-r--r--pkg/domain/infra/tunnel/images.go175
-rw-r--r--pkg/domain/infra/tunnel/manifest.go29
-rw-r--r--pkg/domain/infra/tunnel/network.go34
-rw-r--r--pkg/domain/infra/tunnel/play.go15
-rw-r--r--pkg/domain/infra/tunnel/pods.go75
-rw-r--r--pkg/domain/infra/tunnel/runtime.go6
-rw-r--r--pkg/domain/infra/tunnel/system.go11
-rw-r--r--pkg/domain/infra/tunnel/volumes.go20
-rw-r--r--pkg/errorhandling/errorhandling.go7
-rw-r--r--pkg/hooks/README.md2
-rw-r--r--pkg/hooks/exec/exec.go2
-rw-r--r--pkg/hooks/hooks.go2
-rw-r--r--pkg/netns/netns_linux.go2
-rw-r--r--pkg/ps/ps.go43
-rw-r--r--pkg/rootless/rootless_linux.go2
-rw-r--r--pkg/seccomp/seccomp.go2
-rw-r--r--pkg/signal/signal_linux.go1
-rw-r--r--pkg/signal/signal_linux_mipsx.go106
-rw-r--r--pkg/specgen/generate/container.go2
-rw-r--r--pkg/specgen/generate/kube/kube.go105
-rw-r--r--pkg/specgen/generate/oci.go2
-rw-r--r--pkg/specgen/generate/security.go6
-rw-r--r--pkg/specgen/generate/storage.go2
-rw-r--r--pkg/specgen/pod_validate.go2
-rw-r--r--pkg/specgen/specgen.go4
-rw-r--r--pkg/systemd/generate/common.go5
-rw-r--r--pkg/systemd/generate/containers.go10
-rw-r--r--pkg/systemd/generate/containers_test.go43
-rw-r--r--pkg/systemd/generate/pods.go8
-rw-r--r--pkg/systemd/generate/pods_test.go15
-rw-r--r--pkg/terminal/util.go9
-rw-r--r--pkg/util/utils_linux.go17
-rw-r--r--pkg/util/utils_supported.go2
-rw-r--r--pkg/util/utils_unsupported.go5
-rw-r--r--rootless.md2
-rw-r--r--test/apiv2/10-images.at2
-rw-r--r--test/apiv2/20-containers.at20
-rw-r--r--test/apiv2/30-volumes.at36
-rw-r--r--test/apiv2/35-networks.at8
-rw-r--r--test/apiv2/45-system.at67
-rw-r--r--test/compose/README.md47
-rw-r--r--test/compose/env_and_volume/README.md12
-rw-r--r--test/compose/env_and_volume/docker-compose.yml18
-rw-r--r--test/compose/env_and_volume/read/Dockerfile5
-rw-r--r--test/compose/env_and_volume/read/app.py10
-rw-r--r--test/compose/env_and_volume/tests.sh4
-rw-r--r--test/compose/env_and_volume/write/Dockerfile5
-rw-r--r--test/compose/env_and_volume/write/app.py13
-rw-r--r--test/compose/images/README.md5
-rw-r--r--test/compose/images/podman-python/Containerfile3
-rw-r--r--test/compose/mount_and_label/README.md9
-rw-r--r--test/compose/mount_and_label/docker-compose.yml10
-rw-r--r--test/compose/mount_and_label/frontend/Dockerfile5
-rw-r--r--test/compose/mount_and_label/frontend/app.py10
-rw-r--r--test/compose/mount_and_label/setup.sh2
-rw-r--r--test/compose/mount_and_label/teardown.sh1
-rw-r--r--test/compose/mount_and_label/tests.sh4
-rw-r--r--test/compose/port_map_diff_port/README.md9
-rw-r--r--test/compose/port_map_diff_port/docker-compose.yml6
-rw-r--r--test/compose/port_map_diff_port/frontend/Dockerfile5
-rw-r--r--test/compose/port_map_diff_port/frontend/app.py9
-rw-r--r--test/compose/port_map_diff_port/tests.sh3
-rw-r--r--test/compose/setup.sh.example3
-rw-r--r--test/compose/simple_port_map/README.md9
-rw-r--r--test/compose/simple_port_map/docker-compose.yml6
-rw-r--r--test/compose/simple_port_map/frontend/Dockerfile6
-rw-r--r--test/compose/simple_port_map/frontend/app.py10
-rw-r--r--test/compose/simple_port_map/tests.sh3
-rw-r--r--test/compose/teardown.sh.example4
-rwxr-xr-xtest/compose/test-compose345
-rw-r--r--test/e2e/common_test.go4
-rw-r--r--test/e2e/containers_conf_test.go2
-rw-r--r--test/e2e/cp_test.go3
-rw-r--r--test/e2e/create_test.go8
-rw-r--r--test/e2e/events_test.go43
-rw-r--r--test/e2e/exec_test.go15
-rw-r--r--test/e2e/exists_test.go1
-rw-r--r--test/e2e/generate_kube_test.go1
-rw-r--r--test/e2e/generate_systemd_test.go3
-rw-r--r--test/e2e/image_sign_test.go16
-rw-r--r--test/e2e/images_test.go22
-rw-r--r--test/e2e/kill_test.go55
-rw-r--r--test/e2e/login_logout_test.go10
-rw-r--r--test/e2e/logs_test.go22
-rw-r--r--test/e2e/mount_rootless_test.go2
-rw-r--r--test/e2e/network_connect_disconnect_test.go18
-rw-r--r--test/e2e/network_create_test.go3
-rw-r--r--test/e2e/play_kube_test.go94
-rw-r--r--test/e2e/pod_infra_container_test.go1
-rw-r--r--test/e2e/pod_kill_test.go1
-rw-r--r--test/e2e/pod_ps_test.go1
-rw-r--r--test/e2e/pod_stats_test.go8
-rw-r--r--test/e2e/prune_test.go60
-rw-r--r--test/e2e/ps_test.go51
-rw-r--r--test/e2e/pull_test.go6
-rw-r--r--test/e2e/rmi_test.go2
-rw-r--r--test/e2e/run_ns_test.go2
-rw-r--r--test/e2e/run_privileged_test.go51
-rw-r--r--test/e2e/run_selinux_test.go1
-rw-r--r--test/e2e/run_test.go8
-rw-r--r--test/e2e/runlabel_test.go6
-rw-r--r--test/e2e/search_test.go6
-rw-r--r--test/e2e/start_test.go23
-rw-r--r--test/e2e/stats_test.go2
-rw-r--r--test/e2e/systemd_test.go27
-rw-r--r--test/e2e/toolbox_test.go3
-rw-r--r--test/e2e/tree_test.go2
-rw-r--r--test/e2e/volume_create_test.go8
-rw-r--r--test/e2e/volume_prune_test.go60
-rw-r--r--test/framework/framework.go2
-rw-r--r--test/python/docker/test_containers.py2
-rw-r--r--test/system/030-run.bats70
-rw-r--r--test/system/035-logs.bats9
-rw-r--r--test/system/040-ps.bats39
-rw-r--r--test/system/065-cp.bats88
-rw-r--r--test/system/070-build.bats19
-rw-r--r--test/system/260-sdnotify.bats11
-rw-r--r--test/system/600-completion.bats57
-rw-r--r--test/system/helpers.bash43
-rw-r--r--test/utils/common_function_test.go4
-rw-r--r--test/utils/utils.go2
-rw-r--r--vendor/github.com/Microsoft/go-winio/go.mod2
-rw-r--r--vendor/github.com/Microsoft/go-winio/go.sum6
-rw-r--r--vendor/github.com/Microsoft/go-winio/pipe.go4
-rw-r--r--vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go159
-rw-r--r--vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go7
-rw-r--r--vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go81
-rw-r--r--vendor/github.com/Microsoft/go-winio/vhd/vhd.go341
-rw-r--r--vendor/github.com/Microsoft/go-winio/vhd/zvhd.go54
-rw-r--r--vendor/github.com/Microsoft/hcsshim/.gitattributes1
-rw-r--r--vendor/github.com/Microsoft/hcsshim/CODEOWNERS4
-rw-r--r--vendor/github.com/Microsoft/hcsshim/appveyor.yml2
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/attach.go38
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go26
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/detach.go26
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/export.go46
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/format.go26
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go197
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/import.go41
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go38
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/mount.go27
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/setup.go75
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/storage.go50
-rw-r--r--vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go319
-rw-r--r--vendor/github.com/Microsoft/hcsshim/go.mod12
-rw-r--r--vendor/github.com/Microsoft/hcsshim/go.sum46
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hcs/service.go49
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hcs/syscall.go5
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hcs/utils.go5
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go54
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go7
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go158
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go79
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_add_instance_request.go16
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_hv_socket_service_config.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_instance.go16
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_modify_operation.go17
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_operation_request.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_remove_instance_request.go14
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_system_info.go14
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_affinity.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_config.go18
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_operations.go18
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_property.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go17
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/device.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go16
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_address.go17
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_service_config.go6
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/logical_processor.go18
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/memory.go2
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/memory_2.go2
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/modification_request.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/processor_topology.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/property_type.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/service_properties.go18
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/schema2/vm_processor_limits.go22
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go22
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go24
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayer.go12
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go4
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go13
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go34
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/wclayer/wclayer.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/devices.go13
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/errors.go15
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/filesystem.go110
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go185
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/logon.go30
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/memory.go11
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/net.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/path.go11
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go3
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/processor.go7
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/utils.go60
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go5
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go294
-rw-r--r--vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go11
-rw-r--r--vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go584
-rw-r--r--vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt46
-rw-r--r--vendor/github.com/containerd/cgroups/stats/v1/metrics.proto15
-rw-r--r--vendor/github.com/containers/buildah/.cirrus.yml2
-rw-r--r--vendor/github.com/containers/buildah/Makefile10
-rw-r--r--vendor/github.com/containers/buildah/copier/copier.go193
-rw-r--r--vendor/github.com/containers/buildah/copier/syscall_unix.go2
-rw-r--r--vendor/github.com/containers/buildah/go.mod6
-rw-r--r--vendor/github.com/containers/buildah/go.sum10
-rw-r--r--vendor/github.com/containers/buildah/install.md59
-rw-r--r--vendor/github.com/containers/buildah/new.go18
-rw-r--r--vendor/github.com/containers/buildah/pkg/cli/common.go4
-rw-r--r--vendor/github.com/containers/buildah/pkg/parse/parse.go19
-rw-r--r--vendor/github.com/containers/buildah/run_linux.go60
-rw-r--r--vendor/github.com/containers/buildah/troubleshooting.md2
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go16
-rw-r--r--vendor/github.com/containers/common/pkg/config/containers.conf24
-rw-r--r--vendor/github.com/containers/common/pkg/config/default.go24
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/default_linux.go3
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/seccomp.json3
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go10
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/supported.go2
-rw-r--r--vendor/github.com/containers/common/version/version.go2
-rw-r--r--vendor/github.com/containers/psgo/internal/capabilities/capabilities.go2
-rw-r--r--vendor/github.com/containers/psgo/internal/dev/tty.go5
-rw-r--r--vendor/github.com/containers/psgo/internal/proc/status.go2
-rw-r--r--vendor/github.com/containers/psgo/internal/process/process.go4
-rw-r--r--vendor/github.com/containers/psgo/psgo.go24
-rw-r--r--vendor/github.com/containers/storage/.cirrus.yml101
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/go.mod10
-rw-r--r--vendor/github.com/containers/storage/go.sum47
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go8
-rw-r--r--vendor/github.com/containers/storage/storage.conf4
-rw-r--r--vendor/github.com/containers/storage/store.go6
-rw-r--r--vendor/github.com/google/uuid/uuid.go10
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md25
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockdec.go2
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockenc.go1
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decodeheader.go202
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_best.go484
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder_options.go20
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/doc.go3
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go (renamed from vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go)2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go (renamed from vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go)2
-rw-r--r--vendor/github.com/vishvananda/netlink/.travis.yml7
-rw-r--r--vendor/github.com/vishvananda/netlink/addr.go1
-rw-r--r--vendor/github.com/vishvananda/netlink/addr_linux.go35
-rw-r--r--vendor/github.com/vishvananda/netlink/class.go56
-rw-r--r--vendor/github.com/vishvananda/netlink/class_linux.go29
-rw-r--r--vendor/github.com/vishvananda/netlink/conntrack_linux.go116
-rw-r--r--vendor/github.com/vishvananda/netlink/filter.go9
-rw-r--r--vendor/github.com/vishvananda/netlink/filter_linux.go20
-rw-r--r--vendor/github.com/vishvananda/netlink/go.mod4
-rw-r--r--vendor/github.com/vishvananda/netlink/go.sum10
-rw-r--r--vendor/github.com/vishvananda/netlink/handle_unspecified.go2
-rw-r--r--vendor/github.com/vishvananda/netlink/inet_diag.go30
-rw-r--r--vendor/github.com/vishvananda/netlink/ipset_linux.go335
-rw-r--r--vendor/github.com/vishvananda/netlink/link.go50
-rw-r--r--vendor/github.com/vishvananda/netlink/link_linux.go198
-rw-r--r--vendor/github.com/vishvananda/netlink/neigh_linux.go12
-rw-r--r--vendor/github.com/vishvananda/netlink/netlink_unspecified.go6
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/addr_linux.go14
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go5
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/ipset_linux.go222
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/link_linux.go67
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/nl_linux.go28
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/parse_attr.go67
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/syscall.go7
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/tc_linux.go111
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux.go2
-rw-r--r--vendor/github.com/vishvananda/netlink/qdisc.go24
-rw-r--r--vendor/github.com/vishvananda/netlink/qdisc_linux.go41
-rw-r--r--vendor/github.com/vishvananda/netlink/rdma_link_linux.go46
-rw-r--r--vendor/github.com/vishvananda/netlink/route.go51
-rw-r--r--vendor/github.com/vishvananda/netlink/route_linux.go119
-rw-r--r--vendor/github.com/vishvananda/netlink/rule.go14
-rw-r--r--vendor/github.com/vishvananda/netlink/rule_linux.go66
-rw-r--r--vendor/github.com/vishvananda/netlink/socket_linux.go92
-rw-r--r--vendor/github.com/vishvananda/netlink/tcp.go18
-rw-r--r--vendor/github.com/vishvananda/netlink/tcp_linux.go393
-rw-r--r--vendor/github.com/vishvananda/netns/go.mod2
-rw-r--r--vendor/github.com/vishvananda/netns/go.sum2
-rw-r--r--vendor/github.com/vishvananda/netns/netns.go19
-rw-r--r--vendor/github.com/vishvananda/netns/netns_linux.go87
-rw-r--r--vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_gc_x86.go2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_s390x.s2
-rw-r--r--vendor/golang.org/x/sys/cpu/cpu_x86.s2
-rw-r--r--vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_aix_ppc64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_darwin_386.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_darwin_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_darwin_arm.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_darwin_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_freebsd_386.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_freebsd_arm.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_386.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_arm.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_mips64x.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_mipsx.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_riscv64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_linux_s390x.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_netbsd_386.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_netbsd_arm.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_openbsd_386.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_openbsd_arm.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/asm_solaris_amd64.s2
-rw-r--r--vendor/golang.org/x/sys/unix/endian_big.go2
-rw-r--r--vendor/golang.org/x/sys/unix/endian_little.go2
-rw-r--r--vendor/golang.org/x/sys/unix/mkerrors.sh2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_dragonfly.go13
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux.go87
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux_gc.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_unix_gc.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go2
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux.go6
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go2
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go10
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_386.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux.go18
-rw-r--r--vendor/golang.org/x/sys/windows/dll_windows.go3
-rw-r--r--vendor/golang.org/x/sys/windows/security_windows.go14
-rw-r--r--vendor/golang.org/x/sys/windows/syscall_windows.go8
-rw-r--r--vendor/golang.org/x/sys/windows/types_windows.go48
-rw-r--r--vendor/golang.org/x/sys/windows/zsyscall_windows.go79
-rw-r--r--vendor/modules.txt33
649 files changed, 23445 insertions, 4173 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 0fa51be63..cbe8bc757 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -26,11 +26,11 @@ env:
####
FEDORA_NAME: "fedora-33"
PRIOR_FEDORA_NAME: "fedora-32"
- UBUNTU_NAME: "ubuntu-20"
- PRIOR_UBUNTU_NAME: "ubuntu-19"
+ UBUNTU_NAME: "ubuntu-2010"
+ PRIOR_UBUNTU_NAME: "ubuntu-2004"
# Google-cloud VM Images
- IMAGE_SUFFIX: "c5402398833246208"
+ IMAGE_SUFFIX: "c6233039174893568"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
@@ -434,6 +434,21 @@ apiv2_test_task:
podman_system_info_script: '$SCRIPT_BASE/logcollector.sh podman'
time_script: '$SCRIPT_BASE/logcollector.sh time'
+compose_test_task:
+ name: "compose test on $DISTRO_NV"
+ alias: compose_test
+ depends_on:
+ - validate
+ gce_instance: *standardvm
+ env:
+ <<: *stdenvars
+ TEST_FLAVOR: compose
+ clone_script: *noop # Comes from cache
+ gopath_cache: *ro_gopath_cache
+ setup_script: *setup
+ main_script: *main
+ always: *logs_artifacts
+
# Execute the podman integration tests on all primary platforms and release
# versions, as root, without involving the podman-remote client.
@@ -619,6 +634,7 @@ success_task:
- docker-py_test
- unit_test
- apiv2_test
+ - compose_test
- local_integration_test
- remote_integration_test
- rootless_integration_test
diff --git a/Makefile b/Makefile
index 610449e9d..5f058a710 100644
--- a/Makefile
+++ b/Makefile
@@ -176,7 +176,7 @@ gofmt: ## Verify the source code gofmt
test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go)
$(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp
-.PHONY: test/goecho/goechoe
+.PHONY: test/goecho/goecho
test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go)
$(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho
@@ -226,7 +226,7 @@ bin/podman.cross.%: .gopathok
# Update nix/nixpkgs.json its latest stable commit
.PHONY: nixpkgs
nixpkgs:
- @nix run -f channel:nixos-20.03 nix-prefetch-git -c nix-prefetch-git \
+ @nix run -f channel:nixos-20.09 nix-prefetch-git -c nix-prefetch-git \
--no-deepClone https://github.com/nixos/nixpkgs > nix/nixpkgs.json
# Build statically linked binary
diff --git a/README.md b/README.md
index 3c25e53cb..89dd012c7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers.
Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes.
-* [Latest Version: 2.2.0](https://github.com/containers/podman/releases/latest)
+* [Latest Version: 2.2.1](https://github.com/containers/podman/releases/latest)
* Latest Remote client for Windows
* Latest Remote client for MacOs
* Latest Static Remote client for Linux
@@ -38,7 +38,7 @@ Podman presently only supports running containers on Linux. However, we are buil
## Communications
-If you think you've identified a security issue in the project, please *DO NOT* report the issue publicly via the Github issue tracker, mailing list, or IRC.
+If you think you've identified a security issue in the project, please *DO NOT* report the issue publicly via the GitHub issue tracker, mailing list, or IRC.
Instead, send an email with as many details as possible to `security@lists.podman.io`. This is a private mailing list for the core maintainers.
For general questions and discussion, please use the
@@ -177,9 +177,8 @@ familiar container cli commands. For more details, see the
[Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools).
## Podman Former API (Varlink)
-Podman formerly offered a [Varlink-based API](https://github.com/containers/podman/blob/master/docs/tutorials/varlink_remote_client.md)
-for remote management of containers. However, this API was replaced by the REST API.
-Varlink support has been removed as of the 3.0 release.
+Podman formerly offered a Varlink-based API for remote management of containers. However, this API
+was replaced by the REST API. Varlink support has been removed as of the 3.0 release.
For more details, you can see [this blog](https://podman.io/blogs/2020/01/17/podman-new-api.html).
## Static Binary Builds
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index a1027b465..ce1abecad 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -51,7 +51,7 @@
- Fixed a bug where rootless Podman could hang when the `newuidmap` binary was not installed ([#7776](https://github.com/containers/podman/issues/7776)).
- Fixed a bug where the `--pull` option to `podman run`, `podman create`, and `podman build` did not match Docker's behavior.
- Fixed a bug where sysctl settings from the `containers.conf` configuration file were applied, even if the container did not join the namespace associated with a sysctl.
-- Fixed a bug where Podman would not return the text of errors encounted when trying to run a healthcheck for a container.
+- Fixed a bug where Podman would not return the text of errors encountered when trying to run a healthcheck for a container.
- Fixed a bug where Podman was accidentally setting the `containers` environment variable in addition to the expected `container` environment variable.
- Fixed a bug where rootless Podman using CNI networking did not properly clean up DNS entries for removed containers ([#7789](https://github.com/containers/podman/issues/7789)).
- Fixed a bug where the `podman untag --all` command was not supported with remote Podman.
@@ -181,7 +181,7 @@
- The `podman run` and `podman create` commands can now specify options to slirp4netns by using the `--network` option as follows: `--net slirp4netns:opt1,opt2`. This allows for, among other things, switching the port forwarder used by slirp4netns away from rootlessport.
- The `podman ps` command now features a new option, `--storage`, to show containers from Buildah, CRI-O and other applications.
- The `podman run` and `podman create` commands now feature a `--sdnotify` option to control the behavior of systemd's sdnotify with containers, enabling improved support for Podman in `Type=notify` units.
-- The `podman run` command now features a `--preserve-fds` opton to pass file descriptors from the host into the container ([#6458](https://github.com/containers/podman/issues/6458)).
+- The `podman run` command now features a `--preserve-fds` option to pass file descriptors from the host into the container ([#6458](https://github.com/containers/podman/issues/6458)).
- The `podman run` and `podman create` commands can now create overlay volume mounts, by adding the `:O` option to a bind mount (e.g. `-v /test:/test:O`). Overlay volume mounts will mount a directory into a container from the host and allow changes to it, but not write those changes back to the directory on the host.
- The `podman play kube` command now supports the Socket HostPath type ([#7112](https://github.com/containers/podman/issues/7112)).
- The `podman play kube` command now supports read-only mounts.
@@ -269,7 +269,7 @@
- Fixed a bug where endpoints that hijacked would do perform the hijack too early, before being ready to send and receive data ([#7195](https://github.com/containers/podman/issues/7195)).
- Fixed a bug where Pod endpoints that can operate on multiple containers at once (e.g. Kill, Pause, Unpause, Stop) would not forward errors from individual containers that failed.
- The Compat List endpoint for networks now supports filtering results ([#7462](https://github.com/containers/podman/issues/7462)).
-- Fixed a bug where the Top endpoint for pods would return both a 500 and 404 when run on a non-existant pod.
+- Fixed a bug where the Top endpoint for pods would return both a 500 and 404 when run on a nonexistent pod.
- Fixed a bug where Pull endpoints did not stream progress back to the client.
- The Version endpoints (Libpod and Compat) now provide version in a format compatible with Docker.
- All non-hijacking responses to API requests should not include headers with the version of the server.
@@ -310,7 +310,7 @@
- Fixed a bug where the `podman generate systemd` command would panic on an invalid restart policy being specified ([#7271](https://github.com/containers/podman/issues/7271)).
- Fixed a bug where the `podman images` command could take a very long time (several minutes) to complete when a large number of images were present.
- Fixed a bug where the `podman logs` command with the `--tail` flag would not work properly when a large amount of output would be printed ([#7230](https://github.com/containers/podman/issues/7230)).
-- Fixed a bug where the `podman exec` command with remote Podman would not return a non-zero exit code when the exec session failed to start (e.g. invoking a non-existent command) ([#6893](https://github.com/containers/podman/issues/6893)).
+- Fixed a bug where the `podman exec` command with remote Podman would not return a non-zero exit code when the exec session failed to start (e.g. invoking a nonexistent command) ([#6893](https://github.com/containers/podman/issues/6893)).
- Fixed a bug where the `podman load` command with remote Podman would did not honor user-specified tags ([#7124](https://github.com/containers/podman/issues/7124)).
- Fixed a bug where the `podman system service` command, when run as a non-root user by Systemd, did not properly handle the Podman pause process and would not restart properly as a result ([#7180](https://github.com/containers/podman/issues/7180)).
- Fixed a bug where the `--publish` flag to `podman create`, `podman run`, and `podman pod create` did not properly handle a host IP of 0.0.0.0 (attempting to bind to literal 0.0.0.0, instead of all IPs on the system) ([#7104](https://github.com/containers/podman/issues/7014)).
@@ -411,7 +411,7 @@
### Bugfixes
- Fixed a bug where the `podman ps` command would not truncate long container commands, resulting in display issues as the column could become extremely wide (the `--no-trunc` flag can be used to print the full command).
-- Fixed a bug where `podman pod` commands operationg on multiple containers (e.g. `podman pod stop` and `podman pod kill`) would not print errors from individual containers, but only a warning that some containers had failed.
+- Fixed a bug where `podman pod` commands operating on multiple containers (e.g. `podman pod stop` and `podman pod kill`) would not print errors from individual containers, but only a warning that some containers had failed.
- Fixed a bug where the `podman system service` command would panic if a connection to the Events endpoint hung up early ([#6805](https://github.com/containers/libpod/issues/6805)).
- Fixed a bug where rootless Podman would create anonymous and named volumes with the wrong owner for containers run with the `--user` directive.
- Fixed a bug where the `TMPDIR` environment variable (used for storing temporary files while pulling images) was not being defaulted (if unset) to `/var/tmp`.
@@ -425,7 +425,7 @@
### API
- Fixed a bug where the timestamp format for Libpod image list endpoint was incorrect - the format has been switched to Unix time.
-- Fixed a bug where the compatability Create endpoint did not handle empty entrypoints properly.
+- Fixed a bug where the compatibility Create endpoint did not handle empty entrypoints properly.
- Fixed a bug where the compatibility network remove endpoint would improperly handle errors where the network was not found.
- Fixed a bug where containers would be created with improper permissions because of a umask issue ([#6787](https://github.com/containers/libpod/issues/6787)).
@@ -455,7 +455,7 @@
- Fixed a bug where the `label` option to `--security-opt` would only be shown once in `podman inspect`, even if provided multiple times.
### API
-- Fixed a bug where network endpoint URLs in the compatability API were mistakenly suffixed with `/json`.
+- Fixed a bug where network endpoint URLs in the compatibility API were mistakenly suffixed with `/json`.
- Fixed a bug where the Libpod volume creation endpoint returned 200 instead of 201 on success.
### Misc
@@ -485,7 +485,7 @@
- Named and anonymous volumes and `tmpfs` filesystems added to containers are no longer mounted `noexec` by default.
### Bugfixes
-- Fixed a bug where the `podman exec` command would log to journald when run in containers loggined to journald ([#6555](https://github.com/containers/podman/issues/6555)).
+- Fixed a bug where the `podman exec` command would log to journald when run in containers logged to journald ([#6555](https://github.com/containers/podman/issues/6555)).
- Fixed a bug where the `podman auto-update` command would not preserve the OS and architecture of the original image when pulling a replacement ([#6613](https://github.com/containers/podman/issues/6613)).
- Fixed a bug where the `podman cp` command could create an extra `merged` directory when copying into an existing directory ([#6596](https://github.com/containers/podman/issues/6596)).
- Fixed a bug where the `podman pod stats` command would crash on pods run with `--network=host` ([#5652](https://github.com/containers/podman/issues/5652)).
@@ -521,7 +521,7 @@
### Misc
- Rootless containers will now automatically set their ulimits to the maximum allowed for the user running the container, to match the behavior of containers run as root
-- Packages managed by the core Podman team will no longer include a default `libpod.conf`, instead defaulting to `containers.conf`. The default libpod.conf will remain available in the Github repository until the release of Podman 2.0
+- Packages managed by the core Podman team will no longer include a default `libpod.conf`, instead defaulting to `containers.conf`. The default libpod.conf will remain available in the GitHub repository until the release of Podman 2.0
- The default Podman CNI network configuration now sets HairpinMode to allow containers to access other containers via ports published on the host
- Updated containers/common to v0.8.4
@@ -1105,7 +1105,7 @@
### Bugfixes
- Fixed a bug where `podman cp` would not copy folders ([#2836](https://github.com/containers/podman/issues/2836))
-- Fixed a bug where Podman would panic when the Varlink API attempted too pull a non-existent image ([#2860](https://github.com/containers/podman/issues/2860))
+- Fixed a bug where Podman would panic when the Varlink API attempted too pull a nonexistent image ([#2860](https://github.com/containers/podman/issues/2860))
- Fixed a bug where `podman rmi` sometimes did not produce an event when images were deleted
- Fixed a bug where Podman would panic when the Varlink API passed improperly-formatted options when attempting to build ([#2869](https://github.com/containers/podman/issues/2869))
- Fixed a bug where `podman images` would not print a header if no images were present ([#2877](https://github.com/containers/podman/pull/2877))
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index f792b2713..83fe0723c 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -313,6 +313,10 @@ func completeKeyValues(toComplete string, k keyValueCompletion) ([]string, cobra
return suggestions, directive
}
+func getBoolCompletion(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
+}
+
/* Autocomplete Functions for cobra ValidArgsFunction */
// AutocompleteContainers - Autocomplete all container names.
@@ -797,6 +801,39 @@ func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string
return volumes, directive
}
+// AutocompleteNetworkFlag - Autocomplete network flag options.
+func AutocompleteNetworkFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "ns:": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return nil, cobra.ShellCompDirectiveDefault
+ },
+ "bridge": nil,
+ "none": nil,
+ "host": nil,
+ "private": nil,
+ "slirp4netns:": func(s string) ([]string, cobra.ShellCompDirective) {
+ skv := keyValueCompletion{
+ "allow_host_loopback=": getBoolCompletion,
+ "cidr=": nil,
+ "enable_ipv6=": getBoolCompletion,
+ "outbound_addr=": nil,
+ "outbound_addr6=": nil,
+ "port_handler=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"rootlesskit", "slirp4netns"}, cobra.ShellCompDirectiveNoFileComp
+ },
+ }
+ return completeKeyValues(s, skv)
+ },
+ }
+
+ networks, _ := getNetworks(cmd, toComplete)
+ suggestions, dir := completeKeyValues(toComplete, kv)
+ // add slirp4netns here it does not work correct if we add it to the kv map
+ suggestions = append(suggestions, "slirp4netns")
+ return append(networks, suggestions...), dir
+}
+
// AutocompleteJSONFormat - Autocomplete format flag option.
// -> "json"
func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
@@ -974,17 +1011,14 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
// AutocompleteImageFilters - Autocomplete image ls --filter options.
func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- getBool := func(_ string) ([]string, cobra.ShellCompDirective) {
- return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
- }
getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
kv := keyValueCompletion{
"before=": getImg,
"since=": getImg,
"label=": nil,
"reference=": nil,
- "dangling=": getBool,
- "readonly=": getBool,
+ "dangling=": getBoolCompletion,
+ "readonly=": getBoolCompletion,
}
return completeKeyValues(toComplete, kv)
}
@@ -1004,14 +1038,12 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete str
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
}
kv := keyValueCompletion{
- "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
- "driver=": local,
- "scope=": local,
- "label=": nil,
- "opt=": nil,
- "dangling=": func(_ string) ([]string, cobra.ShellCompDirective) {
- return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
- },
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "driver=": local,
+ "scope=": local,
+ "label=": nil,
+ "opt=": nil,
+ "dangling=": getBoolCompletion,
}
return completeKeyValues(toComplete, kv)
}
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 14086ace4..bbd4f6bae 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -642,7 +642,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
storageOptFlagName := "storage-opt"
createFlags.StringSliceVar(
- &cf.StoreageOpt,
+ &cf.StorageOpt,
storageOptFlagName, []string{},
"Storage driver options per container",
)
@@ -671,7 +671,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
sysctlFlagName, []string{},
"Sysctl options",
)
- //TODO: Add function for systctl completion.
+ //TODO: Add function for sysctl completion.
_ = cmd.RegisterFlagCompletionFunc(sysctlFlagName, completion.AutocompleteNone)
systemdFlagName := "systemd"
@@ -696,13 +696,13 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
"Allocate a pseudo-TTY for container",
)
- timezonezFlagName := "tz"
+ timezoneFlagName := "tz"
createFlags.StringVar(
&cf.Timezone,
- timezonezFlagName, containerConfig.TZ(),
+ timezoneFlagName, containerConfig.TZ(),
"Set timezone in container",
)
- _ = cmd.RegisterFlagCompletionFunc(timezonezFlagName, completion.AutocompleteNone) //TODO: add timezone completion
+ _ = cmd.RegisterFlagCompletionFunc(timezoneFlagName, completion.AutocompleteNone) //TODO: add timezone completion
umaskFlagName := "umask"
createFlags.StringVar(
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index e975def0a..9635f4135 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -98,7 +98,7 @@ type ContainerCLIOpts struct {
SignaturePolicy string
StopSignal string
StopTimeout uint
- StoreageOpt []string
+ StorageOpt []string
SubUIDName string
SubGIDName string
Sysctl []string
@@ -310,7 +310,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
// on speculation by Matt and I. We think that these come into play later
// like with start. We believe this is just a difference in podman/compat
cliOpts := ContainerCLIOpts{
- // Attach: nil, // dont need?
+ // Attach: nil, // don't need?
Authfile: "",
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
@@ -321,11 +321,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
CPUShares: uint64(cc.HostConfig.CPUShares),
- // CPUS: 0, // dont need?
+ // CPUS: 0, // don't need?
CPUSetCPUs: cc.HostConfig.CpusetCpus,
CPUSetMems: cc.HostConfig.CpusetMems,
- // Detach: false, // dont need
- // DetachKeys: "", // dont need
+ // Detach: false, // don't need
+ // DetachKeys: "", // don't need
Devices: devices,
DeviceCGroupRule: nil,
DeviceReadBPs: readBps,
@@ -359,7 +359,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
Rm: cc.HostConfig.AutoRemove,
SecurityOpt: cc.HostConfig.SecurityOpt,
StopSignal: cc.Config.StopSignal,
- StoreageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
+ StorageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
Systemd: "true", // podman default
TmpFS: stringMaptoArray(cc.HostConfig.Tmpfs),
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index cae52ccaa..9cb4ed550 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -63,7 +63,7 @@ func DefineNetFlags(cmd *cobra.Command) {
networkFlagName, containerConfig.NetNS(),
"Connect a container to a network",
)
- _ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks)
+ _ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworkFlag)
networkAliasFlagName := "network-alias"
netFlags.StringSlice(
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index c416d0d7b..287836d9f 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -488,9 +488,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.ConmonPidFile = c.ConmonPIDFile
// TODO
- // ouitside of specgen and oci though
+ // outside of specgen and oci though
// defaults to true, check spec/storage
- // s.readon = c.ReadOnlyTmpFS
+ // s.readonly = c.ReadOnlyTmpFS
// TODO convert to map?
// check if key=value and convert
sysmap := make(map[string]string)
diff --git a/cmd/podman/completion/completion.go b/cmd/podman/completion/completion.go
index 84942a508..b615b33d0 100644
--- a/cmd/podman/completion/completion.go
+++ b/cmd/podman/completion/completion.go
@@ -32,7 +32,7 @@ var (
Example: `podman completion bash
podman completion zsh -f _podman
podman completion fish --no-desc`,
- //dont show this command to users
+ //don't show this command to users
Hidden: true,
}
)
diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go
index 9b0a01a2f..69b61a06c 100644
--- a/cmd/podman/containers/cp.go
+++ b/cmd/podman/containers/cp.go
@@ -1,19 +1,34 @@
package containers
import (
+ "io"
+ "io/ioutil"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ buildahCopiah "github.com/containers/buildah/copier"
"github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/registry"
+ "github.com/containers/podman/v2/pkg/copy"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/errorhandling"
+ "github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/idtools"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var (
- cpDescription = `Command copies the contents of SRC_PATH to the DEST_PATH.
+ cpDescription = `Copy the contents of SRC_PATH to the DEST_PATH.
- You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container. If "-" is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT. The CONTAINER can be a running or stopped container. The SRC_PATH or DEST_PATH can be a file or directory.
+ You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container. If "-" is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT. The CONTAINER can be a running or stopped container. The SRC_PATH or DEST_PATH can be a file or a directory.
`
cpCommand = &cobra.Command{
- Use: "cp [options] [CONTAINER:]SRC_PATH [CONTAINER:]DEST_PATH",
+ Use: "cp [CONTAINER:]SRC_PATH [CONTAINER:]DEST_PATH",
Short: "Copy files/folders between a container and the local filesystem",
Long: cpDescription,
Args: cobra.ExactArgs(2),
@@ -39,19 +54,21 @@ var (
func cpFlags(cmd *cobra.Command) {
flags := cmd.Flags()
- flags.BoolVar(&cpOpts.Extract, "extract", false, "Extract the tar file into the destination directory.")
- flags.BoolVar(&cpOpts.Pause, "pause", true, "Pause the container while copying")
+ flags.BoolVar(&cpOpts.Extract, "extract", false, "Deprecated...")
+ flags.BoolVar(&cpOpts.Pause, "pause", true, "Deprecated")
+ _ = flags.MarkHidden("extract")
+ _ = flags.MarkHidden("pause")
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode},
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: cpCommand,
})
cpFlags(cpCommand)
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode},
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerCpCommand,
Parent: containerCmd,
})
@@ -59,5 +76,290 @@ func init() {
}
func cp(cmd *cobra.Command, args []string) error {
- return registry.ContainerEngine().ContainerCp(registry.GetContext(), args[0], args[1], cpOpts)
+ // Parse user input.
+ sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(args[0], args[1])
+ if err != nil {
+ return err
+ }
+
+ if len(sourceContainerStr) > 0 {
+ return copyFromContainer(sourceContainerStr, sourcePath, destPath)
+ }
+
+ return copyToContainer(destContainerStr, destPath, sourcePath)
+}
+
+// containerMustExist returns an error if the specified container does not
+// exist.
+func containerMustExist(container string) error {
+ exists, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), container, entities.ContainerExistsOptions{})
+ if err != nil {
+ return err
+ }
+ if !exists.Value {
+ return errors.Errorf("container %q does not exist", container)
+ }
+ return nil
+}
+
+// doCopy executes the two functions in parallel to copy data from A to B and
+// joins the errors if any.
+func doCopy(funcA func() error, funcB func() error) error {
+ errChan := make(chan error)
+ go func() {
+ errChan <- funcA()
+ }()
+ var copyErrors []error
+ copyErrors = append(copyErrors, funcB())
+ copyErrors = append(copyErrors, <-errChan)
+ return errorhandling.JoinErrors(copyErrors)
+}
+
+// copyFromContainer copies from the containerPath on the container to hostPath.
+func copyFromContainer(container string, containerPath string, hostPath string) error {
+ if err := containerMustExist(container); err != nil {
+ return err
+ }
+
+ if hostPath == "-" {
+ hostPath = os.Stdout.Name()
+ }
+
+ containerInfo, err := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
+ if err != nil {
+ return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ }
+
+ var hostBaseName string
+ hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
+ if hostInfoErr != nil {
+ if strings.HasSuffix(hostPath, "/") {
+ return errors.Wrapf(hostInfoErr, "%q could not be found on the host", hostPath)
+ }
+ // If it doesn't exist, then let's have a look at the parent dir.
+ parentDir := filepath.Dir(hostPath)
+ hostInfo, err = copy.ResolveHostPath(parentDir)
+ if err != nil {
+ return errors.Wrapf(hostInfoErr, "%q could not be found on the host", hostPath)
+ }
+ // If the specified path does not exist, we need to assume that
+ // it'll be created while copying. Hence, we use it as the
+ // base path.
+ hostBaseName = filepath.Base(hostPath)
+ } else {
+ // If the specified path exists on the host, we must use its
+ // base path as it may have changed due to symlink evaluations.
+ hostBaseName = filepath.Base(hostInfo.LinkTarget)
+ }
+
+ reader, writer := io.Pipe()
+ hostCopy := func() error {
+ defer reader.Close()
+ if hostInfo.LinkTarget == os.Stdout.Name() {
+ _, err := io.Copy(os.Stdout, reader)
+ return err
+ }
+
+ groot, err := user.Current()
+ if err != nil {
+ return err
+ }
+
+ // Set the {G,U}ID. Let's be tolerant towards the different
+ // operating systems and only log the errors, so we can debug
+ // if necessary.
+ idPair := idtools.IDPair{}
+ if i, err := strconv.Atoi(groot.Uid); err == nil {
+ idPair.UID = i
+ } else {
+ logrus.Debugf("Error converting UID %q to int: %v", groot.Uid, err)
+ }
+ if i, err := strconv.Atoi(groot.Gid); err == nil {
+ idPair.GID = i
+ } else {
+ logrus.Debugf("Error converting GID %q to int: %v", groot.Gid, err)
+ }
+
+ putOptions := buildahCopiah.PutOptions{
+ ChownDirs: &idPair,
+ ChownFiles: &idPair,
+ }
+ if !containerInfo.IsDir && (!hostInfo.IsDir || hostInfoErr != nil) {
+ // If we're having a file-to-file copy, make sure to
+ // rename accordingly.
+ putOptions.Rename = map[string]string{filepath.Base(containerInfo.LinkTarget): hostBaseName}
+ }
+ dir := hostInfo.LinkTarget
+ if !hostInfo.IsDir {
+ dir = filepath.Dir(dir)
+ }
+ if err := buildahCopiah.Put(dir, "", putOptions, reader); err != nil {
+ return errors.Wrap(err, "error copying to host")
+ }
+ return nil
+ }
+
+ containerCopy := func() error {
+ defer writer.Close()
+ copyFunc, err := registry.ContainerEngine().ContainerCopyToArchive(registry.GetContext(), container, containerInfo.LinkTarget, writer)
+ if err != nil {
+ return err
+ }
+ if err := copyFunc(); err != nil {
+ return errors.Wrap(err, "error copying from container")
+ }
+ return nil
+ }
+ return doCopy(containerCopy, hostCopy)
+}
+
+// copyToContainer copies the hostPath to containerPath on the container.
+func copyToContainer(container string, containerPath string, hostPath string) error {
+ if err := containerMustExist(container); err != nil {
+ return err
+ }
+
+ isStdin := false
+ if hostPath == "-" {
+ hostPath = os.Stdin.Name()
+ isStdin = true
+ } else if hostPath == os.Stdin.Name() {
+ isStdin = true
+ }
+
+ // Make sure that host path exists.
+ hostInfo, err := copy.ResolveHostPath(hostPath)
+ if err != nil {
+ return errors.Wrapf(err, "%q could not be found on the host", hostPath)
+ }
+
+ // If the path on the container does not exist. We need to make sure
+ // that it's parent directory exists. The destination may be created
+ // while copying.
+ var containerBaseName string
+ containerInfo, containerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
+ if containerInfoErr != nil {
+ if strings.HasSuffix(containerPath, "/") {
+ return errors.Wrapf(containerInfoErr, "%q could not be found on container %s", containerPath, container)
+ }
+ if isStdin {
+ return errors.New("destination must be a directory when copying from stdin")
+ }
+ // NOTE: containerInfo may actually be set. That happens when
+ // the container path is a symlink into nirvana. In that case,
+ // we must use the symlinked path instead.
+ path := containerPath
+ if containerInfo != nil {
+ containerBaseName = filepath.Base(containerInfo.LinkTarget)
+ path = containerInfo.LinkTarget
+ } else {
+ containerBaseName = filepath.Base(containerPath)
+ }
+
+ parentDir, err := containerParentDir(container, path)
+ if err != nil {
+ return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
+ }
+ containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
+ if err != nil {
+ return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ }
+ } else {
+ // If the specified path exists on the container, we must use
+ // its base path as it may have changed due to symlink
+ // evaluations.
+ containerBaseName = filepath.Base(containerInfo.LinkTarget)
+ }
+
+ var stdinFile string
+ if isStdin {
+ if !containerInfo.IsDir {
+ return errors.New("destination must be a directory when copying from stdin")
+ }
+
+ // Copy from stdin to a temporary file *before* throwing it
+ // over the wire. This allows for proper client-side error
+ // reporting.
+ tmpFile, err := ioutil.TempFile("", "")
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(tmpFile, os.Stdin)
+ if err != nil {
+ return err
+ }
+ if err = tmpFile.Close(); err != nil {
+ return err
+ }
+ if !archive.IsArchivePath(tmpFile.Name()) {
+ return errors.New("source must be a (compressed) tar archive when copying from stdin")
+ }
+ stdinFile = tmpFile.Name()
+ }
+
+ reader, writer := io.Pipe()
+ hostCopy := func() error {
+ defer writer.Close()
+ if isStdin {
+ stream, err := os.Open(stdinFile)
+ if err != nil {
+ return err
+ }
+ defer stream.Close()
+ _, err = io.Copy(writer, stream)
+ return err
+ }
+
+ getOptions := buildahCopiah.GetOptions{
+ // Unless the specified path ends with ".", we want to copy the base directory.
+ KeepDirectoryNames: !strings.HasSuffix(hostPath, "."),
+ }
+ if !hostInfo.IsDir && (!containerInfo.IsDir || containerInfoErr != nil) {
+ // If we're having a file-to-file copy, make sure to
+ // rename accordingly.
+ getOptions.Rename = map[string]string{filepath.Base(hostInfo.LinkTarget): containerBaseName}
+ }
+ if err := buildahCopiah.Get("/", "", getOptions, []string{hostInfo.LinkTarget}, writer); err != nil {
+ return errors.Wrap(err, "error copying from host")
+ }
+ return nil
+ }
+
+ containerCopy := func() error {
+ defer reader.Close()
+ target := containerInfo.FileInfo.LinkTarget
+ if !containerInfo.IsDir {
+ target = filepath.Dir(target)
+ }
+
+ copyFunc, err := registry.ContainerEngine().ContainerCopyFromArchive(registry.GetContext(), container, target, reader)
+ if err != nil {
+ return err
+ }
+ if err := copyFunc(); err != nil {
+ return errors.Wrap(err, "error copying to container")
+ }
+ return nil
+ }
+
+ return doCopy(hostCopy, containerCopy)
+}
+
+// containerParentDir returns the parent directory of the specified path on the
+// container. If the path is relative, it will be resolved relative to the
+// container's working directory (or "/" if the work dir isn't set).
+func containerParentDir(container string, containerPath string) (string, error) {
+ if filepath.IsAbs(containerPath) {
+ return filepath.Dir(containerPath), nil
+ }
+ inspectData, _, err := registry.ContainerEngine().ContainerInspect(registry.GetContext(), []string{container}, entities.InspectOptions{})
+ if err != nil {
+ return "", err
+ }
+ if len(inspectData) != 1 {
+ return "", errors.Errorf("inspecting container %q: expected 1 data item but got %d", container, len(inspectData))
+ }
+ workDir := filepath.Join("/", inspectData[0].Config.WorkingDir)
+ workDir = filepath.Join(workDir, containerPath)
+ return filepath.Dir(workDir), nil
}
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 3d87c71a9..420813ba9 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -171,7 +171,7 @@ func createInit(c *cobra.Command) error {
}
cliVals.UserNS = c.Flag("userns").Value.String()
// if user did not modify --userns flag and did turn on
- // uid/gid mappsings, set userns flag to "private"
+ // uid/gid mappings, set userns flag to "private"
if !c.Flag("userns").Changed && cliVals.UserNS == "host" {
if len(cliVals.UIDMap) > 0 ||
len(cliVals.GIDMap) > 0 ||
@@ -239,7 +239,7 @@ func pullImage(imageName string) (string, error) {
if cliVals.Platform != "" {
if cliVals.OverrideArch != "" || cliVals.OverrideOS != "" {
- return "", errors.Errorf("--platform option can not be specified with --overide-arch or --override-os")
+ return "", errors.Errorf("--platform option can not be specified with --override-arch or --override-os")
}
split := strings.SplitN(cliVals.Platform, "/", 2)
cliVals.OverrideOS = split[0]
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go
index 4640229a9..28040e08a 100644
--- a/cmd/podman/containers/kill.go
+++ b/cmd/podman/containers/kill.go
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
+ "github.com/containers/common/pkg/completion"
"github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
@@ -22,7 +23,7 @@ var (
Long: killDescription,
RunE: kill,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
ValidArgsFunction: common.AutocompleteContainersRunning,
Example: `podman kill mywebserver
@@ -32,7 +33,7 @@ var (
containerKillCommand = &cobra.Command{
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
Use: killCommand.Use,
Short: killCommand.Short,
@@ -57,6 +58,9 @@ func killFlags(cmd *cobra.Command) {
signalFlagName := "signal"
flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container")
_ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal)
+ cidfileFlagName := "cidfile"
+ flags.StringArrayVar(&killOptions.CIDFiles, cidfileFlagName, []string{}, "Read the container ID from the file")
+ _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
}
func init() {
diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go
index d4ede370a..9b562afd8 100644
--- a/cmd/podman/containers/logs.go
+++ b/cmd/podman/containers/logs.go
@@ -122,6 +122,7 @@ func logs(_ *cobra.Command, args []string) error {
}
logsOptions.Since = since
}
- logsOptions.Writer = os.Stdout
+ logsOptions.StdoutWriter = os.Stdout
+ logsOptions.StderrWriter = os.Stderr
return registry.ContainerEngine().ContainerLogs(registry.GetContext(), args, logsOptions.ContainerLogsOptions)
}
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index fb2101d64..c92b19a19 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -39,7 +39,7 @@ var (
ValidArgsFunction: common.AutocompleteContainers,
}
- containerMountCommmand = &cobra.Command{
+ containerMountCommand = &cobra.Command{
Use: mountCommand.Use,
Short: mountCommand.Short,
Long: mountCommand.Long,
@@ -76,11 +76,11 @@ func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
- Command: containerMountCommmand,
+ Command: containerMountCommand,
Parent: containerCmd,
})
- mountFlags(containerMountCommmand)
- validate.AddLatestFlag(containerMountCommmand, &mountOpts.Latest)
+ mountFlags(containerMountCommand)
+ validate.AddLatestFlag(containerMountCommand, &mountOpts.Latest)
}
func mount(_ *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 6ff1b929d..46bfb4143 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -3,7 +3,6 @@ package containers
import (
"fmt"
"os"
- "strconv"
"strings"
"github.com/containers/common/pkg/completion"
@@ -15,7 +14,6 @@ import (
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/specgen"
- "github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -108,15 +106,6 @@ func run(cmd *cobra.Command, args []string) error {
return err
}
- if rootless.IsRootless() && !registry.IsRemote() {
- userspec := strings.SplitN(cliVals.User, ":", 2)[0]
- if uid, err := strconv.ParseInt(userspec, 10, 32); err == nil {
- if err := util.CheckRootlessUIDRange(int(uid)); err != nil {
- return err
- }
- }
- }
-
if af := cliVals.Authfile; len(af) > 0 {
if _, err := os.Stat(af); err != nil {
return err
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index fbea1e3d8..3aca104e3 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -221,7 +221,8 @@ func build(cmd *cobra.Command, args []string) error {
var logfile *os.File
if cmd.Flag("logfile").Changed {
- logfile, err := os.OpenFile(buildOpts.Logfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
+ var err error
+ logfile, err = os.OpenFile(buildOpts.Logfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
return err
}
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go
index f8e1ee226..2d881a906 100644
--- a/cmd/podman/images/pull.go
+++ b/cmd/podman/images/pull.go
@@ -139,7 +139,7 @@ func imagePull(cmd *cobra.Command, args []string) error {
}
if platform != "" {
if pullOptions.OverrideArch != "" || pullOptions.OverrideOS != "" {
- return errors.Errorf("--platform option can not be specified with --overide-arch or --override-os")
+ return errors.Errorf("--platform option can not be specified with --override-arch or --override-os")
}
split := strings.SplitN(platform, "/", 2)
pullOptions.OverrideOS = split[0]
diff --git a/cmd/podman/images/sign.go b/cmd/podman/images/sign.go
index 342536f7c..859d51d51 100644
--- a/cmd/podman/images/sign.go
+++ b/cmd/podman/images/sign.go
@@ -47,6 +47,7 @@ func init() {
certDirFlagName := "cert-dir"
flags.StringVar(&signOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys")
_ = signCommand.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault)
+ flags.BoolVarP(&signOptions.All, "all", "a", false, "Sign all the manifests of the multi-architecture image")
}
func sign(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index cc48b7ae4..76613ae71 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -51,7 +51,7 @@ func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions {
_ = cmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone)
typeFlagName := "type"
- flags.StringVarP(&opts.Type, typeFlagName, "t", AllType, fmt.Sprintf("Specify inspect-oject type (%q, %q or %q)", ImageType, ContainerType, AllType))
+ flags.StringVarP(&opts.Type, typeFlagName, "t", AllType, fmt.Sprintf("Specify inspect-object type (%q, %q or %q)", ImageType, ContainerType, AllType))
_ = cmd.RegisterFlagCompletionFunc(typeFlagName, common.AutocompleteInspectType)
validate.AddLatestFlag(cmd, &opts.Latest)
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index c3aaf84a8..f076d13f3 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -31,11 +31,6 @@ func main() {
return
}
- // Hard code TMPDIR functions to use /var/tmp, if user did not override
- if _, ok := os.LookupEnv("TMPDIR"); !ok {
- os.Setenv("TMPDIR", "/var/tmp")
- }
-
rootCmd = parseCommands()
Execute()
diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go
index 89faa42a2..96fea4a21 100644
--- a/cmd/podman/manifest/push.go
+++ b/cmd/podman/manifest/push.go
@@ -107,7 +107,7 @@ func push(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("tls-verify") {
manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(!manifestPushOpts.TLSVerifyCLI)
}
- if err := registry.ImageEngine().ManifestPush(registry.Context(), args, manifestPushOpts.ManifestPushOptions); err != nil {
+ if err := registry.ImageEngine().ManifestPush(registry.Context(), args[0], args[1], manifestPushOpts.ManifestPushOptions); err != nil {
return err
}
return nil
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index 5e227d05a..db7280b1d 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -61,7 +61,7 @@ func init() {
networkFlagName := "network"
flags.StringVar(&kubeOptions.Network, networkFlagName, "", "Connect pod to CNI network(s)")
- _ = kubeCmd.RegisterFlagCompletionFunc(networkFlagName, common.AutocompleteNetworks)
+ _ = kubeCmd.RegisterFlagCompletionFunc(networkFlagName, common.AutocompleteNetworkFlag)
logDriverFlagName := "log-driver"
flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, "", "Logging driver for the container")
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 0830a62a5..1f613a4c5 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -178,6 +178,10 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
return err
}
}
+ // Hard code TMPDIR functions to use /var/tmp, if user did not override
+ if _, ok := os.LookupEnv("TMPDIR"); !ok {
+ os.Setenv("TMPDIR", "/var/tmp")
+ }
if !registry.IsRemote() {
if cmd.Flag("cpu-profile").Changed {
diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go
index 57e747451..da5f652c8 100644
--- a/cmd/podman/system/connection/add.go
+++ b/cmd/podman/system/connection/add.go
@@ -168,19 +168,17 @@ func getUserInfo(uri *url.URL) (*url.Userinfo, error) {
}
func getUDS(cmd *cobra.Command, uri *url.URL) (string, error) {
- var authMethods []ssh.AuthMethod
- passwd, set := uri.User.Password()
- if set {
- authMethods = append(authMethods, ssh.Password(passwd))
- }
+ var signers []ssh.Signer
+ passwd, passwdSet := uri.User.Password()
if cmd.Flags().Changed("identity") {
value := cmd.Flag("identity").Value.String()
- auth, err := terminal.PublicKey(value, []byte(passwd))
+ s, err := terminal.PublicKey(value, []byte(passwd))
if err != nil {
return "", errors.Wrapf(err, "failed to read identity %q", value)
}
- authMethods = append(authMethods, auth)
+ signers = append(signers, s)
+ logrus.Debugf("SSH Ident Key %q %s %s", value, ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
}
if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
@@ -190,16 +188,51 @@ func getUDS(cmd *cobra.Command, uri *url.URL) (string, error) {
if err != nil {
return "", err
}
- a := agent.NewClient(c)
- authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers))
- }
-
- if len(authMethods) == 0 {
- pass, err := terminal.ReadPassword(fmt.Sprintf("%s's login password:", uri.User.Username()))
+ agentSigners, err := agent.NewClient(c).Signers()
if err != nil {
return "", err
}
- authMethods = append(authMethods, ssh.Password(string(pass)))
+
+ signers = append(signers, agentSigners...)
+
+ if logrus.IsLevelEnabled(logrus.DebugLevel) {
+ for _, s := range agentSigners {
+ logrus.Debugf("SSH Agent Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ }
+ }
+
+ var authMethods []ssh.AuthMethod
+ if len(signers) > 0 {
+ var dedup = make(map[string]ssh.Signer)
+ // Dedup signers based on fingerprint, ssh-agent keys override CONTAINER_SSHKEY
+ for _, s := range signers {
+ fp := ssh.FingerprintSHA256(s.PublicKey())
+ if _, found := dedup[fp]; found {
+ logrus.Debugf("Dedup SSH Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ dedup[fp] = s
+ }
+
+ var uniq []ssh.Signer
+ for _, s := range dedup {
+ uniq = append(uniq, s)
+ }
+
+ authMethods = append(authMethods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
+ return uniq, nil
+ }))
+ }
+
+ if passwdSet {
+ authMethods = append(authMethods, ssh.Password(passwd))
+ }
+
+ if len(authMethods) == 0 {
+ authMethods = append(authMethods, ssh.PasswordCallback(func() (string, error) {
+ pass, err := terminal.ReadPassword(fmt.Sprintf("%s's login password:", uri.User.Username()))
+ return string(pass), err
+ }))
}
cfg := &ssh.ClientConfig{
diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go
index f57689584..87bb947ed 100644
--- a/cmd/podman/system/prune.go
+++ b/cmd/podman/system/prune.go
@@ -12,12 +12,14 @@ import (
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/pkg/domain/entities"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
+ "github.com/docker/go-units"
"github.com/spf13/cobra"
)
var (
- pruneOptions = entities.SystemPruneOptions{}
-
+ pruneOptions = entities.SystemPruneOptions{}
+ filters []string
pruneDescription = fmt.Sprintf(`
podman system prune
@@ -46,10 +48,15 @@ func init() {
flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation. The default is false")
flags.BoolVarP(&pruneOptions.All, "all", "a", false, "Remove all unused data")
flags.BoolVar(&pruneOptions.Volume, "volumes", false, "Prune volumes")
+ filterFlagName := "filter"
+ flags.StringArrayVar(&filters, filterFlagName, []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
+ _ = pruneCommand.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
}
func prune(cmd *cobra.Command, args []string) error {
+ var err error
+
// Prompt for confirmation if --force is not set
if !force {
reader := bufio.NewReader(os.Stdin)
@@ -74,13 +81,17 @@ Are you sure you want to continue? [y/N] `, volumeString)
}
}
- // TODO: support for filters in system prune
+ pruneOptions.Filters, err = dfilters.ParseFilterArgumentsIntoFilters(filters)
+ if err != nil {
+ return err
+ }
+
response, err := registry.ContainerEngine().SystemPrune(context.Background(), pruneOptions)
if err != nil {
return err
}
// Print container prune results
- err = utils.PrintContainerPruneResults(response.ContainerPruneReport, true)
+ err = utils.PrintContainerPruneResults(response.ContainerPruneReports, true)
if err != nil {
return err
}
@@ -91,13 +102,17 @@ Are you sure you want to continue? [y/N] `, volumeString)
}
// Print Volume prune results
if pruneOptions.Volume {
- err = utils.PrintVolumePruneResults(response.VolumePruneReport, true)
+ err = utils.PrintVolumePruneResults(response.VolumePruneReports, true)
if err != nil {
return err
}
}
// Print Images prune results
- utils.PrintImagePruneResults(response.ImagePruneReport, true)
+ err = utils.PrintImagePruneResults(response.ImagePruneReports, true)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("Total reclaimed space: %s\n", units.HumanSize((float64)(response.ReclaimedSpace)))
return nil
}
diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go
index 8c52616be..ed35fbb04 100644
--- a/cmd/podman/system/service_abi.go
+++ b/cmd/podman/system/service_abi.go
@@ -5,6 +5,7 @@ package system
import (
"context"
"net"
+ "os"
"strings"
api "github.com/containers/podman/v2/pkg/api/server"
@@ -13,6 +14,7 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
+ "golang.org/x/sys/unix"
)
func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entities.PodmanConfig) error {
@@ -34,6 +36,15 @@ func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entiti
listener = &l
}
+ // Close stdin, so shortnames will not prompt
+ devNullfile, err := os.Open(os.DevNull)
+ if err != nil {
+ return err
+ }
+ defer devNullfile.Close()
+ if err := unix.Dup2(int(devNullfile.Fd()), int(os.Stdin.Fd())); err != nil {
+ return err
+ }
rt, err := infra.GetRuntime(context.Background(), flags, cfg)
if err != nil {
return err
diff --git a/cmd/podman/utils/utils.go b/cmd/podman/utils/utils.go
index 2ca2c4c92..f42243f69 100644
--- a/cmd/podman/utils/utils.go
+++ b/cmd/podman/utils/utils.go
@@ -5,6 +5,7 @@ import (
"os"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
// IsDir returns true if the specified path refers to a directory.
@@ -41,21 +42,21 @@ func PrintPodPruneResults(podPruneReports []*entities.PodPruneReport, heading bo
return errs.PrintErrors()
}
-func PrintContainerPruneResults(containerPruneReport *entities.ContainerPruneReport, heading bool) error {
+func PrintContainerPruneResults(containerPruneReports []*reports.PruneReport, heading bool) error {
var errs OutputErrors
- if heading && (len(containerPruneReport.ID) > 0 || len(containerPruneReport.Err) > 0) {
+ if heading && (len(containerPruneReports) > 0) {
fmt.Println("Deleted Containers")
}
- for k := range containerPruneReport.ID {
- fmt.Println(k)
- }
- for _, v := range containerPruneReport.Err {
- errs = append(errs, v)
+ for _, v := range containerPruneReports {
+ fmt.Println(v.Id)
+ if v.Err != nil {
+ errs = append(errs, v.Err)
+ }
}
return errs.PrintErrors()
}
-func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, heading bool) error {
+func PrintVolumePruneResults(volumePruneReport []*reports.PruneReport, heading bool) error {
var errs OutputErrors
if heading && len(volumePruneReport) > 0 {
fmt.Println("Deleted Volumes")
@@ -70,18 +71,16 @@ func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, he
return errs.PrintErrors()
}
-func PrintImagePruneResults(imagePruneReport *entities.ImagePruneReport, heading bool) error {
- if heading && (len(imagePruneReport.Report.Id) > 0 || len(imagePruneReport.Report.Err) > 0) {
+func PrintImagePruneResults(imagePruneReports []*reports.PruneReport, heading bool) error {
+ if heading {
fmt.Println("Deleted Images")
}
- for _, i := range imagePruneReport.Report.Id {
- fmt.Println(i)
- }
- for _, e := range imagePruneReport.Report.Err {
- fmt.Fprint(os.Stderr, e.Error()+"\n")
- }
- if imagePruneReport.Size > 0 {
- fmt.Fprintf(os.Stdout, "Size: %d\n", imagePruneReport.Size)
+ for _, r := range imagePruneReports {
+ fmt.Println(r.Id)
+ if r.Err != nil {
+ fmt.Fprint(os.Stderr, r.Err.Error()+"\n")
+ }
}
+
return nil
}
diff --git a/cmd/podman/volumes/prune.go b/cmd/podman/volumes/prune.go
index d1370120b..0f3ba9ef6 100644
--- a/cmd/podman/volumes/prune.go
+++ b/cmd/podman/volumes/prune.go
@@ -8,10 +8,12 @@ import (
"strings"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/spf13/cobra"
)
@@ -28,6 +30,7 @@ var (
RunE: prune,
ValidArgsFunction: completion.AutocompleteNone,
}
+ filter = []string{}
)
func init() {
@@ -37,10 +40,17 @@ func init() {
Parent: volumeCmd,
})
flags := pruneCommand.Flags()
+
+ filterFlagName := "filter"
+ flags.StringArrayVar(&filter, filterFlagName, []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
+ _ = pruneCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
flags.BoolP("force", "f", false, "Do not prompt for confirmation")
}
func prune(cmd *cobra.Command, args []string) error {
+ var (
+ pruneOptions = entities.VolumePruneOptions{}
+ )
// Prompt for confirmation if --force is not set
force, err := cmd.Flags().GetBool("force")
if err != nil {
@@ -58,7 +68,11 @@ func prune(cmd *cobra.Command, args []string) error {
return nil
}
}
- responses, err := registry.ContainerEngine().VolumePrune(context.Background())
+ pruneOptions.Filters, err = filters.ParseFilterArgumentsIntoFilters(filter)
+ if err != nil {
+ return err
+ }
+ responses, err := registry.ContainerEngine().VolumePrune(context.Background(), pruneOptions)
if err != nil {
return err
}
diff --git a/commands-demo.md b/commands-demo.md
index 967fe5beb..e91609b0f 100644
--- a/commands-demo.md
+++ b/commands-demo.md
@@ -48,7 +48,7 @@
| [podman-network(1)](https://podman.readthedocs.io/en/latest/network.html) | Manage Podman CNI networks |
| [podman-network-create(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-create.1.html) | Create a CNI network |
| [podman-network-connect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-connect.1.html) | Connect a container to a CNI network |
-| [podman-network-disconnect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-dosconnect.1.html) | Disconnect a container from a CNI network |
+| [podman-network-disconnect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-disconnect.1.html) | Disconnect a container from a CNI network |
| [podman-network-inspect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-inspect.1.html) | Displays the raw CNI network configuration for one or more networks |
| [podman-network-ls(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-ls.1.html) | Display a summary of CNI networks |
| [podman-network-rm(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-rm.1.html) | Remove one or more CNI networks |
diff --git a/contrib/cirrus/ext_svc_check.sh b/contrib/cirrus/ext_svc_check.sh
index b89e3d753..92ac4e93a 100755
--- a/contrib/cirrus/ext_svc_check.sh
+++ b/contrib/cirrus/ext_svc_check.sh
@@ -6,7 +6,7 @@ set -eo pipefail
# by connecting to a set of essential external servers and failing
# if any cannot be reached. It's intended for use early on in the
# podman CI system, to help prevent wasting time on tests that can't
-# succeede due to some outage or another.
+# succeed due to some outage or another.
# shellcheck source=./contrib/cirrus/lib.sh
source $(dirname $0)/lib.sh
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 01e75d9a6..bc9a95310 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -41,8 +41,8 @@ fi
OS_RELEASE_ID="$(source /etc/os-release; echo $ID)"
# GCE image-name compatible string representation of distribution _major_ version
-OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | cut -d '.' -f 1)"
-# Combined to ease soe usage
+OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | tr -d '.')"
+# Combined to ease some usage
OS_REL_VER="${OS_RELEASE_ID}-${OS_RELEASE_VER}"
# This is normally set from .cirrus.yml but default is necessary when
# running under hack/get_ci_vm.sh since it cannot infer the value.
@@ -87,7 +87,7 @@ CIRRUS_BUILD_ID=${CIRRUS_BUILD_ID:-$RANDOM$(date +%s)} # must be short and uniq
# The starting place for linting and code validation
EPOCH_TEST_COMMIT="$CIRRUS_BASE_SHA"
-# Regex defining all CI-releated env. vars. necessary for all possible
+# Regex defining all CI-related env. vars. necessary for all possible
# testing operations on all platforms and versions. This is necessary
# to avoid needlessly passing through global/system values across
# contexts, such as host->container or root->rootless user
diff --git a/contrib/cirrus/logcollector.sh b/contrib/cirrus/logcollector.sh
index 7bf651b36..323015cef 100755
--- a/contrib/cirrus/logcollector.sh
+++ b/contrib/cirrus/logcollector.sh
@@ -53,7 +53,7 @@ case $1 in
slirp4netns \
)
case $OS_RELEASE_ID in
- fedora*)
+ fedora)
cat /etc/fedora-release
PKG_LST_CMD='rpm -q --qf=%{N}-%{V}-%{R}-%{ARCH}\n'
PKG_NAMES+=(\
@@ -61,7 +61,7 @@ case $1 in
libseccomp \
)
;;
- ubuntu*)
+ ubuntu)
cat /etc/issue
PKG_LST_CMD='dpkg-query --show --showformat=${Package}-${Version}-${Architecture}\n'
PKG_NAMES+=(\
diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter
index bcafbc473..3fa0e5618 100755
--- a/contrib/cirrus/logformatter
+++ b/contrib/cirrus/logformatter
@@ -506,7 +506,7 @@ END_SYNOPSIS
# PR 1234 - title of the pr
my $pr_title = escapeHTML(_env_replace("{CIRRUS_CHANGE_TITLE}"));
- $s .= _tr("Github PR", sprintf("%s - %s",
+ $s .= _tr("GitHub PR", sprintf("%s - %s",
_a("{CIRRUS_PR}", "https://{CIRRUS_REPO_CLONE_HOST}/{CIRRUS_REPO_FULL_NAME}/pull/{CIRRUS_PR}"),
$pr_title));
diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt
index 85a6c26be..140e2c32f 100644
--- a/contrib/cirrus/required_host_ports.txt
+++ b/contrib/cirrus/required_host_ports.txt
@@ -5,7 +5,6 @@ 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
diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh
index fa921f3e4..7f9afd1fd 100755
--- a/contrib/cirrus/runner.sh
+++ b/contrib/cirrus/runner.sh
@@ -41,7 +41,7 @@ function _run_automation() {
req_env_vars CI DEST_BRANCH IMAGE_SUFFIX TEST_FLAVOR TEST_ENVIRON \
PODBIN_NAME PRIV_NAME DISTRO_NV CONTAINER USER HOME \
UID AUTOMATION_LIB_PATH SCRIPT_BASE OS_RELEASE_ID \
- OS_RELEASE_VER CG_FS_TYPE
+ CG_FS_TYPE
bigto ooe.sh dnf install -y ShellCheck # small/quick addition
$SCRIPT_BASE/shellcheck.sh
}
@@ -64,15 +64,13 @@ function _run_unit() {
}
function _run_apiv2() {
- # TODO Remove once VM's with dependency
- if [[ "$OS_RELEASE_ID" == "fedora" ]]; then
- dnf install -y python3-docker
- else
- apt-get -qq -y install python3-docker
- fi
make localapiv2 |& logformatter
}
+function _run_compose() {
+ ./test/compose/test-compose |& logformatter
+}
+
function _run_int() {
dotest integration
}
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index da175cc05..5c6f05ac0 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -47,6 +47,11 @@ echo -e "\n# Begin single-use VM global variables (${BASH_SOURCE[0]})" \
done <<<"$(passthrough_envars)"
) >> "/etc/ci_environment"
+#####
+##### FIXME. /etc/containers/storage.conf should have a driver name set
+##### Remove when VMs updated
+sed 's/^driver.*=.*""/driver = "overlay"/g' -i /etc/containers/storage.conf
+
# This is a possible manual maintenance gaff, check to be sure everything matches.
# shellcheck disable=SC2154
[[ "$DISTRO_NV" == "$OS_REL_VER" ]] || \
@@ -68,7 +73,9 @@ case "$CG_FS_TYPE" in
if ((CONTAINER==0)); then
warn "Forcing testing with runc instead of crun"
if [[ "$OS_RELEASE_ID" == "ubuntu" ]]; then
- echo "OCI_RUNTIME=/usr/lib/cri-o-runc/sbin/runc" >> /etc/ci_environment
+ # Need b/c using cri-o-runc package from OBS
+ echo "OCI_RUNTIME=/usr/lib/cri-o-runc/sbin/runc" \
+ >> /etc/ci_environment
else
echo "OCI_RUNTIME=runc" >> /etc/ci_environment
fi
@@ -97,8 +104,8 @@ fi
# Which distribution are we testing on.
case "$OS_RELEASE_ID" in
- ubuntu*) ;;
- fedora*)
+ ubuntu) ;;
+ fedora)
if ((CONTAINER==0)); then
msg "Configuring / Expanding host storage."
# VM is setup to allow flexibility in testing alternate storage.
@@ -118,10 +125,15 @@ esac
# shellcheck disable=SC2154
case "$TEST_ENVIRON" in
host)
- if [[ "$OS_RELEASE_ID" == "fedora" ]]; then
- # The e2e tests wrongly guess `--cgroup-manager cgroupfs`
+ # The e2e tests wrongly guess `--cgroup-manager` option
+ # shellcheck disable=SC2154
+ if [[ "$CG_FS_TYPE" == "cgroup2fs" ]] || [[ "$PRIV_NAME" == "root" ]]
+ then
warn "Forcing CGROUP_MANAGER=systemd"
echo "CGROUP_MANAGER=systemd" >> /etc/ci_environment
+ else
+ warn "Forcing CGROUP_MANAGER=cgroupfs"
+ echo "CGROUP_MANAGER=cgroupfs" >> /etc/ci_environment
fi
;;
container)
@@ -133,25 +145,21 @@ case "$TEST_ENVIRON" in
modprobe ip6table_nat || :
modprobe iptable_nat || :
else
- # The e2e tests wrongly guess `--cgroup-manager systemd`
warn "Forcing CGROUP_MANAGER=cgroupfs"
echo "CGROUP_MANAGER=cgroupfs" >> /etc/ci_environment
- fi
- ;;
- *) die_unknown TEST_ENVIRON
-esac
-# Required to be defined by caller: Are we testing as root or a regular user
-# shellcheck disable=SC2154
-case "$PRIV_NAME" in
- root)
- if [[ "$TEST_ENVIRON" == "container" ]] && ((container)); then
# There's no practical way to detect userns w/in a container
# affected/related tests are sensitive to this variable.
warn "Disabling usernamespace integration testing"
echo "SKIP_USERNS=1" >> /etc/ci_environment
fi
;;
+ *) die_unknown TEST_ENVIRON
+esac
+
+# Required to be defined by caller: Are we testing as root or a regular user
+case "$PRIV_NAME" in
+ root) ;;
rootless)
# Needs to exist for setup_rootless()
ROOTLESS_USER="${ROOTLESS_USER:-some${RANDOM}dude}"
@@ -190,6 +198,7 @@ case "$TEST_FLAVOR" in
build) make clean ;;
unit) ;;
apiv2) ;& # use next item
+ compose) ;&
int) ;&
sys) ;&
bindings) ;&
diff --git a/contrib/podmanimage/stable/manual/Containerfile b/contrib/podmanimage/stable/manual/Containerfile
index f9ae57dbf..fb4d1adc0 100644
--- a/contrib/podmanimage/stable/manual/Containerfile
+++ b/contrib/podmanimage/stable/manual/Containerfile
@@ -9,7 +9,7 @@
# the RPM name would need to be adjusted before a run as
# appropriate.
#
-# To use, first copy an rpm file from bohdi to `/root/tmp`
+# To use, first copy an rpm file from bodhi to `/root/tmp`
# and then run:
# 'podman build -f ./Containerfile -t quay.io/podman/stable:v1.7.0 .'
#
diff --git a/contrib/remote/containers.conf b/contrib/remote/containers.conf
index 45f58171a..9b0b62c42 100644
--- a/contrib/remote/containers.conf
+++ b/contrib/remote/containers.conf
@@ -7,5 +7,5 @@
# Default Remote URI to access the Podman service.
# Examples:
# remote rootless ssh://engineering.lab.company.com/run/user/1000/podman/podman.sock
-# remote rootfull ssh://root@10.10.1.136:22/run/podman/podman.sock
+# remote rootful ssh://root@10.10.1.136:22/run/podman/podman.sock
# remote_uri= ""
diff --git a/contrib/rootless-cni-infra/Containerfile b/contrib/rootless-cni-infra/Containerfile
index dd80fda28..871e06a6c 100644
--- a/contrib/rootless-cni-infra/Containerfile
+++ b/contrib/rootless-cni-infra/Containerfile
@@ -2,7 +2,7 @@ ARG GOLANG_VERSION=1.15
ARG ALPINE_VERSION=3.12
ARG CNI_VERSION=v0.8.0
ARG CNI_PLUGINS_VERSION=v0.8.7
-ARG DNSNAME_VESION=v1.0.0
+ARG DNSNAME_VERSION=v1.0.0
FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS golang-base
RUN apk add --no-cache git
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 3be44a3a3..db79ebede 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -90,8 +90,8 @@ Recommends: crun
Recommends: container-selinux
Recommends: slirp4netns
Recommends: fuse-overlayfs
-%endif
Recommends: xz
+%endif
# vendored libraries
# awk '{print "Provides: bundled(golang("$1")) = "$2}' vendor.conf | sort
diff --git a/contrib/systemd/system/podman.service b/contrib/systemd/system/podman.service
index 9b5a1a87f..7e5195e7a 100644
--- a/contrib/systemd/system/podman.service
+++ b/contrib/systemd/system/podman.service
@@ -6,7 +6,7 @@ Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
[Service]
-Type=notify
+Type=exec
KillMode=process
Environment=LOGGING="--log-level=info"
ExecStart=/usr/bin/podman $LOGGING system service
diff --git a/contrib/tmpfile/podman.conf b/contrib/tmpfile/podman.conf
index d769671e3..e7cad4066 100644
--- a/contrib/tmpfile/podman.conf
+++ b/contrib/tmpfile/podman.conf
@@ -1,4 +1,5 @@
# /tmp/podman-run-* directory can contain content for Podman containers that have run
# for many days. This following line prevents systemd from removing this content.
-x /tmp/podman-run-.*
-d /run/podman 0700 root root
+x /tmp/podman-run-*
+D! /run/podman 0700 root root
+D! /var/lib/cni/networks
diff --git a/docs/Readme.md b/docs/Readme.md
index ae0067be6..e0918cd54 100644
--- a/docs/Readme.md
+++ b/docs/Readme.md
@@ -45,7 +45,7 @@ because the client (i.e. your web browser) is fetching content from multiple loc
do not share a common domain, accessing the API section may show a stack-trace similar to
the following:
-![Javascript Stack Trace Image](../contrib/cirrus/swagger_stack_trace.png)
+![JavaScript Stack Trace Image](../contrib/cirrus/swagger_stack_trace.png)
If reloading the page, or clearing your local cache does not fix the problem, it is
likely caused by broken metadata needed to protect clients from cross-site-scripting
diff --git a/docs/source/_static/api.html b/docs/source/_static/api.html
index 8b9d66e0d..11fbb85a0 100644
--- a/docs/source/_static/api.html
+++ b/docs/source/_static/api.html
@@ -18,7 +18,7 @@
</style>
</head>
<body>
- <redoc spec-url='https://storage.googleapis.com/libpod-master-releases/swagger-latest-master.yaml'></redoc>
+ <redoc spec-url='https://storage.googleapis.com/libpod-master-releases/swagger-latest-master.yaml' sort-props-alphabetically></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
</body>
</html>
diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md
index c71f4fae9..67513e386 100644
--- a/docs/source/markdown/podman-build.1.md
+++ b/docs/source/markdown/podman-build.1.md
@@ -40,7 +40,7 @@ container images. This `buildah` code creates `buildah` containers for the
`RUN` options in container storage. In certain situations, when the
`podman build` crashes or users kill the `podman build` process, these external
containers can be left in container storage. Use the `podman ps --all --storage`
-command to see these contaienrs. External containers can be removed with the
+command to see these containers. External containers can be removed with the
`podman rm --storage` command.
## OPTIONS
diff --git a/docs/source/markdown/podman-container-prune.1.md b/docs/source/markdown/podman-container-prune.1.md
index 4b4effb0b..b199f9ebb 100644
--- a/docs/source/markdown/podman-container-prune.1.md
+++ b/docs/source/markdown/podman-container-prune.1.md
@@ -15,6 +15,17 @@ podman-container-prune - Remove all stopped containers from local storage
Provide filter values.
+The --filter flag format is of “key=value”. If there is more than one filter, then pass multiple flags (e.g., --filter "foo=bar" --filter "bif=baz")
+
+Supported filters:
+
+- `until` (_timestamp_) - only remove containers and images created before given timestamp
+- `label` (label=_key_, label=_key=value_, label!=_key_, or label!=_key=value_) - only remove containers and images, with (or without, in case label!=... is used) the specified labels.
+
+The until filter can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+
+The label filter accepts two formats. One is the label=... (label=_key_ or label=_key=value_), which removes containers with the specified labels. The other format is the label!=... (label!=_key_ or label!=_key=value_), which removes containers without the specified labels.
+
#### **--force**, **-f**
Do not provide an interactive prompt for container removal.
@@ -63,3 +74,4 @@ podman(1), podman-ps
## HISTORY
December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
+December 2020, converted filter information from docs.docker.com documentation by Dan Walsh (dwalsh at redhat dot com)
diff --git a/docs/source/markdown/podman-cp.1.md b/docs/source/markdown/podman-cp.1.md
index 241a74c42..56511c244 100644
--- a/docs/source/markdown/podman-cp.1.md
+++ b/docs/source/markdown/podman-cp.1.md
@@ -4,9 +4,9 @@
podman\-cp - Copy files/folders between a container and the local filesystem
## SYNOPSIS
-**podman cp** [*options*] [*container*:]*src_path* [*container*:]*dest_path*
+**podman cp** [*container*:]*src_path* [*container*:]*dest_path*
-**podman container cp** [*options*] [*container*:]*src_path* [*container*:]*dest_path*
+**podman container cp** [*container*:]*src_path* [*container*:]*dest_path*
## DESCRIPTION
Copy the contents of **src_path** to the **dest_path**. You can copy from the container's filesystem to the local machine or the reverse, from the local filesystem to the container.
@@ -59,14 +59,6 @@ Using `-` as the *src_path* streams the contents of STDIN as a tar archive. The
## OPTIONS
-#### **--extract**
-
-If the source is a tar archive, extract it to the provided destination (must be a directory). If the source is not a tar archive, follow the above rules.
-
-#### **--pause**
-
-Pause the container while copying into it to avoid potential security issues around symlinks. Defaults to *true*. On rootless containers with cgroups V1, defaults to false.
-
## ALTERNATIVES
Podman has much stronger capabilities than just `podman cp` to achieve copy files between host and container.
@@ -112,8 +104,6 @@ podman cp containerID:/myapp/ /myapp/
podman cp containerID:/home/myuser/. /home/myuser/
-podman cp --extract /home/myuser/myfiles.tar.gz containerID:/myfiles
-
podman cp - containerID:/myfiles.tar.gz < myfiles.tar.gz
## SEE ALSO
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index b5f5591a9..8deaa8540 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -803,10 +803,6 @@ To generate systemd unit files, please see *podman generate systemd*
Automatically remove the container when it exits. The default is *false*.
-Note that the container will not be removed when it could not be created or
-started successfully. This allows the user to inspect the container after
-failure.
-
#### **--rootfs**
If specified, the first argument refers to an exploded container on the file system.
diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md
index ed2143388..019bae539 100644
--- a/docs/source/markdown/podman-generate-kube.1.md
+++ b/docs/source/markdown/podman-generate-kube.1.md
@@ -28,7 +28,7 @@ random port is assigned by Podman in the specification.
Create Kubernetes Pod YAML for a container called `some-mariadb` .
```
$ sudo podman generate kube some-mariadb
-# Generation of Kubenetes YAML is still under development!
+# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
diff --git a/docs/source/markdown/podman-image-prune.1.md b/docs/source/markdown/podman-image-prune.1.md
index d8558d244..73024ffb8 100644
--- a/docs/source/markdown/podman-image-prune.1.md
+++ b/docs/source/markdown/podman-image-prune.1.md
@@ -22,6 +22,17 @@ Remove dangling images and images that have no associated containers.
Provide filter values.
+The --filter flag format is of “key=value”. If there is more than one filter, then pass multiple flags (e.g., --filter "foo=bar" --filter "bif=baz")
+
+Supported filters:
+
+- `until` (_timestamp_) - only remove containers and images created before given timestamp
+- `label` (label=_key_, label=_key=value_, label!=_key_, or label!=_key=value_) - only remove containers and images, with (or without, in case label!=... is used) the specified labels.
+
+The until filter can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+
+The label filter accepts two formats. One is the label=... (label=_key_ or label=_key=value_), which removes images with the specified labels. The other format is the label!=... (label!=_key_ or label!=_key=value_), which removes images without the specified labels.
+
#### **--force**, **-f**
Do not provide an interactive prompt for container removal.
@@ -93,3 +104,4 @@ podman(1), podman-images
## HISTORY
December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
+December 2020, converted filter information from docs.docker.com documentation by Dan Walsh (dwalsh at redhat dot com)
diff --git a/docs/source/markdown/podman-image-sign.1.md b/docs/source/markdown/podman-image-sign.1.md
index 7a924b80b..3e52bde30 100644
--- a/docs/source/markdown/podman-image-sign.1.md
+++ b/docs/source/markdown/podman-image-sign.1.md
@@ -19,6 +19,10 @@ By default, the signature will be written into `/var/lib/containers/sigstore` fo
Print usage statement.
+#### **--all**, **-a**
+
+Sign all the manifests of the multi-architecture image (default false).
+
#### **--cert-dir**=*path*
Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md
index dd01a0f49..4af51d3eb 100644
--- a/docs/source/markdown/podman-info.1.md
+++ b/docs/source/markdown/podman-info.1.md
@@ -31,17 +31,18 @@ Run podman info with plain text response:
$ podman info
host:
arch: amd64
- buildahVersion: 1.15.0
- cgroupVersion: v1
+ buildahVersion: 1.19.0-dev
+ cgroupManager: systemd
+ cgroupVersion: v2
conmon:
- package: conmon-2.0.16-2.fc32.x86_64
+ package: conmon-2.0.22-2.fc33.x86_64
path: /usr/bin/conmon
- version: 'conmon version 2.0.16, commit: 1044176f7dd177c100779d1c63931d6022e419bd'
+ version: 'conmon version 2.0.22, commit: 1be6c73605006a85f7ed60b7f76a51e28eb67e01'
cpus: 8
distribution:
distribution: fedora
- version: "32"
- eventLogger: file
+ version: "33"
+ eventLogger: journald
hostname: localhost.localdomain
idMappings:
gidmap:
@@ -58,33 +59,41 @@ host:
- container_id: 1
host_id: 100000
size: 65536
- kernel: 5.6.11-300.fc32.x86_64
+ kernel: 5.9.11-200.fc33.x86_64
linkmode: dynamic
- memFree: 1401929728
- memTotal: 16416161792
+ memFree: 837505024
+ memTotal: 16416481280
ociRuntime:
- name: runc
- package: containerd.io-1.2.10-3.2.fc31.x86_64
- path: /usr/bin/runc
+ name: crun
+ package: crun-0.16-1.fc33.x86_64
+ path: /usr/bin/crun
version: |-
- runc version 1.0.0-rc8+dev
- commit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
- spec: 1.0.1-dev
+ crun version 0.16
+ commit: eb0145e5ad4d8207e84a327248af76663d4e50dd
+ spec: 1.0.0
+ +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
os: linux
remoteSocket:
- exists: false
- path: /run/user/1000/podman/podman.sock
- rootless: true
+ exists: true
+ path: /run/user/3267/podman/podman.sock
+ security:
+ apparmorEnabled: false
+ capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
+ rootless: true
+ seccompEnabled: true
+ selinuxEnabled: true
slirp4netns:
executable: /bin/slirp4netns
- package: slirp4netns-1.0.0-1.fc32.x86_64
+ package: slirp4netns-1.1.4-4.dev.giteecccdb.fc33.x86_64
version: |-
- slirp4netns version 1.0.0
- commit: a3be729152a33e692cd28b52f664defbf2e7810a
- libslirp: 4.2.0
- swapFree: 8291610624
- swapTotal: 8296329216
- uptime: 52h 29m 39.78s (Approximately 2.17 days)
+ slirp4netns version 1.1.4+dev
+ commit: eecccdb96f587b11d7764556ffacfeaffe4b6e11
+ libslirp: 4.3.1
+ SLIRP_CONFIG_VERSION_MAX: 3
+ libseccomp: 2.5.0
+ swapFree: 6509203456
+ swapTotal: 12591292416
+ uptime: 264h 14m 32.73s (Approximately 11.00 days)
registries:
search:
- registry.fedoraproject.org
@@ -94,19 +103,19 @@ registries:
store:
configFile: /home/dwalsh/.config/containers/storage.conf
containerStore:
- number: 2
+ number: 3
paused: 0
running: 0
- stopped: 2
+ stopped: 3
graphDriverName: overlay
graphOptions:
overlay.mount_program:
Executable: /home/dwalsh/bin/fuse-overlayfs
Package: Unknown
Version: |-
- fusermount3 version: 3.9.1
+ fusermount3 version: 3.9.3
fuse-overlayfs: version 0.7.2
- FUSE library version 3.9.1
+ FUSE library version 3.9.3
using FUSE kernel interface version 7.31
graphRoot: /home/dwalsh/.local/share/containers/storage
graphStatus:
@@ -115,36 +124,38 @@ store:
Supports d_type: "true"
Using metacopy: "false"
imageStore:
- number: 7
+ number: 77
runRoot: /run/user/3267/containers
volumePath: /home/dwalsh/.local/share/containers/storage/volumes
version:
- Built: 1589899246
- BuiltTime: Tue May 19 10:40:46 2020
- GitCommit: c3678ce3289f4195f3f16802411e795c6a587c9f-dirty
- GoVersion: go1.14.2
+ APIVersion: 3.0.0
+ Built: 1608562922
+ BuiltTime: Mon Dec 21 10:02:02 2020
+ GitCommit: d6925182cdaf94225908a386d02eae8fd3e01123-dirty
+ GoVersion: go1.15.5
OsArch: linux/amd64
- APIVersion: 1
- Version: 2.0.0
+ Version: 3.0.0-dev
+
```
Run podman info with JSON formatted response:
```
{
"host": {
"arch": "amd64",
- "buildahVersion": "1.15.0",
- "cgroupVersion": "v1",
+ "buildahVersion": "1.19.0-dev",
+ "cgroupManager": "systemd",
+ "cgroupVersion": "v2",
"conmon": {
- "package": "conmon-2.0.16-2.fc32.x86_64",
+ "package": "conmon-2.0.22-2.fc33.x86_64",
"path": "/usr/bin/conmon",
- "version": "conmon version 2.0.16, commit: 1044176f7dd177c100779d1c63931d6022e419bd"
+ "version": "conmon version 2.0.22, commit: 1be6c73605006a85f7ed60b7f76a51e28eb67e01"
},
"cpus": 8,
"distribution": {
"distribution": "fedora",
- "version": "32"
+ "version": "33"
},
- "eventLogger": "file",
+ "eventLogger": "journald",
"hostname": "localhost.localdomain",
"idMappings": {
"gidmap": [
@@ -172,45 +183,51 @@ Run podman info with JSON formatted response:
}
]
},
- "kernel": "5.6.11-300.fc32.x86_64",
- "memFree": 1380356096,
- "memTotal": 16416161792,
+ "kernel": "5.9.11-200.fc33.x86_64",
+ "memFree": 894574592,
+ "memTotal": 16416481280,
"ociRuntime": {
- "name": "runc",
- "package": "containerd.io-1.2.10-3.2.fc31.x86_64",
- "path": "/usr/bin/runc",
- "version": "runc version 1.0.0-rc8+dev\ncommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657\nspec: 1.0.1-dev"
+ "name": "crun",
+ "package": "crun-0.16-1.fc33.x86_64",
+ "path": "/usr/bin/crun",
+ "version": "crun version 0.16\ncommit: eb0145e5ad4d8207e84a327248af76663d4e50dd\nspec: 1.0.0\n+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL"
},
"os": "linux",
"remoteSocket": {
- "path": "/run/user/1000/podman/podman.sock",
- "exists": false
+ "path": "/run/user/3267/podman/podman.sock",
+ "exists": true
+ },
+ "security": {
+ "apparmorEnabled": false,
+ "capabilities": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT",
+ "rootless": true,
+ "seccompEnabled": true,
+ "selinuxEnabled": true
},
- "rootless": true,
"slirp4netns": {
"executable": "/bin/slirp4netns",
- "package": "slirp4netns-1.0.0-1.fc32.x86_64",
- "version": "slirp4netns version 1.0.0\ncommit: a3be729152a33e692cd28b52f664defbf2e7810a\nlibslirp: 4.2.0"
+ "package": "slirp4netns-1.1.4-4.dev.giteecccdb.fc33.x86_64",
+ "version": "slirp4netns version 1.1.4+dev\ncommit: eecccdb96f587b11d7764556ffacfeaffe4b6e11\nlibslirp: 4.3.1\nSLIRP_CONFIG_VERSION_MAX: 3\nlibseccomp: 2.5.0"
},
- "swapFree": 8291610624,
- "swapTotal": 8296329216,
- "uptime": "52h 27m 39.38s (Approximately 2.17 days)",
+ "swapFree": 6509203456,
+ "swapTotal": 12591292416,
+ "uptime": "264h 13m 12.39s (Approximately 11.00 days)",
"linkmode": "dynamic"
},
"store": {
"configFile": "/home/dwalsh/.config/containers/storage.conf",
"containerStore": {
- "number": 2,
+ "number": 3,
"paused": 0,
"running": 0,
- "stopped": 2
+ "stopped": 3
},
"graphDriverName": "overlay",
"graphOptions": {
"overlay.mount_program": {
"Executable": "/home/dwalsh/bin/fuse-overlayfs",
"Package": "Unknown",
- "Version": "fusermount3 version: 3.9.1\nfuse-overlayfs: version 0.7.2\nFUSE library version 3.9.1\nusing FUSE kernel interface version 7.31"
+ "Version": "fusermount3 version: 3.9.3\nfuse-overlayfs: version 0.7.2\nFUSE library version 3.9.3\nusing FUSE kernel interface version 7.31"
}
},
"graphRoot": "/home/dwalsh/.local/share/containers/storage",
@@ -221,7 +238,7 @@ Run podman info with JSON formatted response:
"Using metacopy": "false"
},
"imageStore": {
- "number": 7
+ "number": 77
},
"runRoot": "/run/user/3267/containers",
"volumePath": "/home/dwalsh/.local/share/containers/storage/volumes"
@@ -235,12 +252,12 @@ Run podman info with JSON formatted response:
]
},
"version": {
- "APIVersion": 1,
- "Version": "2.0.0",
- "GoVersion": "go1.14.2",
- "GitCommit": "c3678ce3289f4195f3f16802411e795c6a587c9f-dirty",
- "BuiltTime": "Tue May 19 10:40:46 2020",
- "Built": 1589899246,
+ "APIVersion": "3.0.0",
+ "Version": "3.0.0-dev",
+ "GoVersion": "go1.15.5",
+ "GitCommit": "d6925182cdaf94225908a386d02eae8fd3e01123-dirty",
+ "BuiltTime": "Mon Dec 21 10:02:02 2020",
+ "Built": 1608562922,
"OsArch": "linux/amd64"
}
}
diff --git a/docs/source/markdown/podman-kill.1.md b/docs/source/markdown/podman-kill.1.md
index 5956c03da..96c01ac09 100644
--- a/docs/source/markdown/podman-kill.1.md
+++ b/docs/source/markdown/podman-kill.1.md
@@ -16,6 +16,10 @@ The main process inside each container specified will be sent SIGKILL, or any si
Signal all running containers. This does not include paused containers.
+#### **--cidfile**
+
+Read container ID from the specified file and remove the container. Can be specified multiple times.
+
#### **--latest**, **-l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
@@ -40,6 +44,10 @@ podman kill --latest
podman kill --signal KILL -a
+podman kill --cidfile /home/user/cidfile-1
+
+podman kill --cidfile /home/user/cidfile-1 --cidfile ./cidfile-2
+
## SEE ALSO
podman(1), podman-stop(1)
diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md
index 67584ffcc..2de261f66 100644
--- a/docs/source/markdown/podman-play-kube.1.md
+++ b/docs/source/markdown/podman-play-kube.1.md
@@ -15,6 +15,8 @@ Ideally the input file would be one created by Podman (see podman-generate-kube(
Note: HostPath volume types created by play kube will be given an SELinux private label (Z)
+Note: If the `:latest` tag is used, Podman will attempt to pull the image from a registry. If the image was built locally with Podman or Buildah, it will have `localhost` as the domain, in that case, Podman will use the image from the local store even if it has the `:latest` tag.
+
## OPTIONS
#### **--authfile**=*path*
diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md
index b94964f6c..28212b92c 100644
--- a/docs/source/markdown/podman-ps.1.md
+++ b/docs/source/markdown/podman-ps.1.md
@@ -57,6 +57,8 @@ Valid filters are listed below:
| since | [ID] or [Name] Containers created since this container |
| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
| health | [Status] healthy or unhealthy |
+| pod | [Pod] name or full or partial ID of pod |
+
#### **--format**=*format*
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 3241cf9f7..674079a9d 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -394,6 +394,13 @@ Run the container in a new user namespace using the supplied mapping. This optio
This option can be passed several times to map different ranges. If calling **podman run** as an unprivileged user, the user needs to have the right to use the mapping. See **subuid**(5).
The example maps gids **0-1999** in the container to the gids **30000-31999** on the host: **--gidmap=0:30000:2000**.
+**Important note:** The new user namespace mapping based on **--gidmap** is based on the initial mapping made in the _/etc/subgid_ file.
+Assuming there is a _/etc/subgid_ mapping **groupname:100000:65536**, then **groupname** is initially mapped to a namespace starting with
+gid **100000** for **65536** ids. From here the **--gidmap** mapping to the new namespace starts from **0** again, but is based on the initial mapping.
+Meaning **groupname** is initially mapped to gid **100000** which is referenced as **0** in the following **--gidmap** mapping. In terms of the example
+above: The group **groupname** is mapped to group **100000** of the initial namespace then the
+**30000**st id of this namespace (which is gid 130000 in this namespace) is mapped to container namespace group id **0**. (groupname -> 100000 / 30000 -> 0)
+
#### **--group-add**=*group*
Add additional groups to run as
@@ -840,10 +847,6 @@ To generate systemd unit files, please see **podman generate systemd**.
Automatically remove the container when it exits. The default is **false**.
-Note that the container will not be removed when it could not be created or
-started successfully. This allows the user to inspect the container after
-failure.
-
#### **--rmi**=*true|false*
After exit of the container, remove the image unless another
@@ -950,7 +953,7 @@ For the IPC namespace, the following sysctls are allowed:
Note: if you use the **--ipc=host** option, the above sysctls will not be allowed.
-For the network namespace, the following ysctls areallowed:
+For the network namespace, the following sysctls are allowed:
- Sysctls beginning with net.\*
@@ -1030,6 +1033,15 @@ as an unprivileged user, the user needs to have the right to use the mapping. Se
The following example maps uids 0-1999 in the container to the uids 30000-31999 on the host: **--uidmap=0:30000:2000**.
+**Important note:** The new user namespace mapping based on **--uidmap** is based on the initial mapping made in the _/etc/subuid_ file.
+Assuming there is a _/etc/subuid_ mapping **username:100000:65536**, then **username** is initially mapped to a namespace starting with
+uid **100000** for **65536** ids. From here the **--uidmap** mapping to the new namespace starts from **0** again, but is based on the initial mapping.
+Meaning **username** is initially mapped to uid **100000** which is referenced as **0** in the following **--uidmap** mapping. In terms of the example
+above: The user **username** is mapped to user **100000** of the initial namespace then the
+**30000**st id of this namespace (which is uid 130000 in this namespace) is mapped to container namespace user id **0**. (username -> 100000 / 30000 -> 0)
+
+_Note_: A minimal mapping has to have at least container uid **0** mapped to the parent user namespace.
+
#### **--ulimit**=*option*
Ulimit options. You can use **host** to copy the current configuration from the host.
diff --git a/docs/source/markdown/podman-system-prune.1.md b/docs/source/markdown/podman-system-prune.1.md
index 431a11267..791503a2c 100644
--- a/docs/source/markdown/podman-system-prune.1.md
+++ b/docs/source/markdown/podman-system-prune.1.md
@@ -18,6 +18,21 @@ By default, volumes are not removed to prevent important data from being deleted
Recursively remove all unused pod, container, image and volume data (Maximum 50 iterations.)
+#### **--filter**=*filters*
+
+Provide filter values.
+
+The --filter flag format is of “key=value”. If there is more than one filter, then pass multiple flags (e.g., --filter "foo=bar" --filter "bif=baz")
+
+Supported filters:
+
+- `until` (_timestamp_) - only remove containers and images created before given timestamp
+- `label` (label=_key_, label=_key=value_, label!=_key_, or label!=_key=value_) - only remove containers and images, with (or without, in case label!=... is used) the specified labels.
+
+The until filter can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+
+The label filter accepts two formats. One is the label=... (label=_key_ or label=_key=value_), which removes containers and images with the specified labels. The other format is the label!=... (label!=_key_ or label!=_key=value_), which removes containers and images without the specified labels.
+
#### **--force**, **-f**
Do not prompt for confirmation
@@ -35,3 +50,4 @@ podman(1), podman-image-prune(1), podman-container-prune(1), podman-pod-prune(1)
## HISTORY
February 2019, Originally compiled by Dan Walsh (dwalsh at redhat dot com)
+December 2020, converted filter information from docs.docker.com documentation by Dan Walsh (dwalsh at redhat dot com)
diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md
index 1fdecfa5c..0905830c5 100644
--- a/docs/source/markdown/podman-system-service.1.md
+++ b/docs/source/markdown/podman-system-service.1.md
@@ -9,7 +9,7 @@ podman\-system\-service - Run an API service
## DESCRIPTION
The **podman system service** command creates a listening service that will answer API calls for Podman. You may
optionally provide an endpoint for the API in URI form. For example, *unix://tmp/foobar.sock* or *tcp:localhost:8080*.
-If no endpoint is provided, defaults will be used. The default endpoint for a rootfull
+If no endpoint is provided, defaults will be used. The default endpoint for a rootful
service is *unix:/run/podman/podman.sock* and rootless is *unix:/$XDG_RUNTIME_DIR/podman/podman.sock* (for
example *unix:/run/user/1000/podman/podman.sock*)
diff --git a/docs/source/markdown/podman-volume-prune.1.md b/docs/source/markdown/podman-volume-prune.1.md
index b5f1b7e94..9477cb5d5 100644
--- a/docs/source/markdown/podman-volume-prune.1.md
+++ b/docs/source/markdown/podman-volume-prune.1.md
@@ -8,7 +8,8 @@ podman\-volume\-prune - Remove all unused volumes
## DESCRIPTION
-Removes all unused volumes. You will be prompted to confirm the removal of all the
+Removes unused volumes. By default all unused volumes will be removed, the **--filter** flag can
+be used to filter specific volumes. You will be prompted to confirm the removal of all the
unused volumes. To bypass the confirmation, use the **--force** flag.
@@ -18,6 +19,17 @@ unused volumes. To bypass the confirmation, use the **--force** flag.
Do not prompt for confirmation.
+#### **--filter**
+
+Filter volumes to be pruned. Volumes can be filtered by the following attributes:
+
+- dangling
+- driver
+- label
+- name
+- opt
+- scope
+
#### **--help**
Print usage statement
@@ -29,6 +41,8 @@ Print usage statement
$ podman volume prune
$ podman volume prune --force
+
+$ podman volume prune --filter label=mylabel=mylabelvalue
```
## SEE ALSO
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 7da01d389..2688c1720 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -44,7 +44,9 @@ Path of the conmon binary (Default path is configured in `containers.conf`)
#### **--events-backend**=*type*
-Backend to use for storing events. Allowed values are **file**, **journald**, and **none**.
+Backend to use for storing events. Allowed values are **file**, **journald**, and
+**none**. When *file* is specified, the events are stored under a subdirectory
+of the *tmpdir* location (see **--tmpdir** below).
#### **--help**, **-h**
@@ -291,7 +293,7 @@ When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.con
Non root users of Podman can create the `$HOME/.config/containers/registries.conf` file to be used instead of the system defaults.
-**storage.conf** (`/etc/containers/storage.conf`, `$HOME/.config/contaners/storage.conf`)
+**storage.conf** (`/etc/containers/storage.conf`, `$HOME/.config/containers/storage.conf`)
storage.conf is the storage configuration file for all tools using containers/storage
diff --git a/go.mod b/go.mod
index a4a3df590..0398c5bad 100644
--- a/go.mod
+++ b/go.mod
@@ -9,13 +9,13 @@ require (
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/containernetworking/cni v0.8.0
- github.com/containernetworking/plugins v0.8.7
- github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c
- github.com/containers/common v0.31.0
+ github.com/containernetworking/plugins v0.9.0
+ github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c
+ github.com/containers/common v0.31.2
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.9.0
- github.com/containers/psgo v1.5.1
- github.com/containers/storage v1.24.1
+ github.com/containers/psgo v1.5.2
+ github.com/containers/storage v1.24.4
github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c
github.com/cyphar/filepath-securejoin v0.2.2
@@ -29,7 +29,7 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/godbus/dbus/v5 v5.0.3
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
- github.com/google/uuid v1.1.2
+ github.com/google/uuid v1.1.3
github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0
github.com/hashicorp/go-multierror v1.1.0
@@ -45,7 +45,7 @@ require (
github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b
github.com/opencontainers/runtime-spec v1.0.3-0.20200817204227-f9c09b4ea1df
github.com/opencontainers/runtime-tools v0.9.0
- github.com/opencontainers/selinux v1.7.0
+ github.com/opencontainers/selinux v1.8.0
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
@@ -57,17 +57,17 @@ require (
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible // indirect
- github.com/vishvananda/netlink v1.1.0
+ github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852
go.etcd.io/bbolt v1.3.5
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
- golang.org/x/sys v0.0.0-20201112073958-5cba982894dd
+ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3
google.golang.org/appengine v1.6.6 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
k8s.io/api v0.0.0-20190620084959-7cf5895f2711
- k8s.io/apimachinery v0.20.0
+ k8s.io/apimachinery v0.20.1
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
)
diff --git a/go.sum b/go.sum
index 806ebaaa1..b5a64b01e 100644
--- a/go.sum
+++ b/go.sum
@@ -25,9 +25,13 @@ github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tT
github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc=
github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331 h1:3YnB7Hpmh1lPecPE8doMOtYCrMdrpedZOvxfuNES/Vk=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk=
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14 h1:lbPVK25c1cu5xTLITwpUcxoA9vKrKErASPYygvouJns=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -65,6 +69,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -73,6 +78,8 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -91,11 +98,13 @@ github.com/containernetworking/cni v0.8.0 h1:BT9lpgGoH4jw3lFC7Odz2prU5ruiYKcgAjM
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.7 h1:bU7QieuAp+sACI2vCzESJ3FoT860urYP+lThyZkb/2M=
github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0=
-github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c h1:vyc2iYz9b2vfDiigpLyhiXNqXITt/dmDk74HpHzlQow=
-github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c/go.mod h1:B+0OkXUogxdwsEy4ax3a5/vDtJjL6vCisiV6frQZJ4A=
-github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
-github.com/containers/common v0.31.0 h1:SRnjfoqbjfaojpY9YJq9JBPEslwB5hoXJbaE+5zMFwM=
+github.com/containernetworking/plugins v0.9.0 h1:c+1gegKhR7+d0Caum9pEHugZlyhXPOG6v3V6xJgIGCI=
+github.com/containernetworking/plugins v0.9.0/go.mod h1:dbWv4dI0QrBGuVgj+TuVQ6wJRZVOhrCQj91YyC92sxg=
+github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c h1:DnJiPjBKeoZbzjkUA6YMf/r5ShYpNacK+EcQ/ui1Mxo=
+github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c/go.mod h1:hvIoL3urgYPL0zX8XlK05aWP6qfUnBNqTrsedsYw6OY=
github.com/containers/common v0.31.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
+github.com/containers/common v0.31.2 h1:sNYwvLA4B7SpEiAWTUvkItPlCrUa2vcxh0FTKXKoC3Q=
+github.com/containers/common v0.31.2/go.mod h1:Fehe82hQfJQvDspnRrV9rcdAWG3IalNHEt0F6QWNBHQ=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ=
@@ -105,11 +114,14 @@ github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDpl
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c=
github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
-github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA=
-github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
+github.com/containers/psgo v1.5.2 h1:3aoozst/GIwsrr/5jnFy3FrJay98uujPCu9lTuSZ/Cw=
+github.com/containers/psgo v1.5.2/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI=
-github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc=
github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
+github.com/containers/storage v1.24.3 h1:8UB4S62l4hrU6Yw3dbsLCJtLg7Ofo39IN2HdckBIX4E=
+github.com/containers/storage v1.24.3/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
+github.com/containers/storage v1.24.4 h1:QJn/C/4eNbYNpxYdnIn1u4lElIB7V9IesRraLf68JjY=
+github.com/containers/storage v1.24.4/go.mod h1:Y793GKrV3RVM1Jt4QejXtCJHGUPLrDvQ9LAbCyJ9OKs=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@@ -254,6 +266,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.3 h1:twObb+9XcuH5B9V1TBCvvvZoO6iEdILi2a76PYn5rJI=
+github.com/google/uuid v1.1.3/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
@@ -323,6 +337,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.4 h1:kz40R/YWls3iqT9zX9AHN3WoVsrAWVyui5sxuLqiXqU=
+github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -430,6 +446,7 @@ github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT5
github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b h1:wjSgG2Z5xWv1wpAI7JbwKR9aJH0p4HJ+ROZ7ViKh9qU=
github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b/go.mod h1:ZuXhqlr4EiRYgDrBDNfSbE4+n9JX4+V107NwAmF7sZA=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200710190001-3e4195d92445/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200817204227-f9c09b4ea1df h1:5AW5dMFSXVH4Mg3WYe4z7ui64bK8n66IoWK8i6T4QZ8=
@@ -437,10 +454,9 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200817204227-f9c09b4ea1df/go.m
github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
-github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
-github.com/opencontainers/selinux v1.7.0 h1:I3Qiu8dbuWHHHfwd4id7zXivJ1qWixGQx8nTvQsKnjs=
-github.com/opencontainers/selinux v1.7.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
+github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/openshift/imagebuilder v1.1.8 h1:gjiIl8pbNj0eC4XWvFJHATdDvYm64p9/pLDLQWoLZPA=
github.com/openshift/imagebuilder v1.1.8/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
@@ -547,18 +563,20 @@ github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/vbauerster/mpb/v5 v5.3.0 h1:vgrEJjUzHaSZKDRRxul5Oh4C72Yy/5VEMb0em+9M0mQ=
github.com/vbauerster/mpb/v5 v5.3.0/go.mod h1:4yTkvAb8Cm4eylAp6t0JRq6pXDkFJ4krUlDqWYkakAs=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
-github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
-github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
@@ -681,23 +699,30 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637 h1:O5hKNaGxIT4A8OTMnuh6UpmBdI3SAPxlZ3g0olDrJVM=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -821,8 +846,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
-k8s.io/apimachinery v0.20.0 h1:jjzbTJRXk0unNS71L7h3lxGDH/2HPxMPaQY+MjECKL8=
-k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.1 h1:LAhz8pKbgR8tUwn7boK+b2HZdt7MiTu2mkYtFMUjTRQ=
+k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
diff --git a/hack/install_golangci.sh b/hack/install_golangci.sh
index 57cdd2e4d..617679751 100755
--- a/hack/install_golangci.sh
+++ b/hack/install_golangci.sh
@@ -12,6 +12,6 @@ if [ ! -x "$BIN" ]; then
echo "Installing golangci-lint v$VERSION into $GOBIN"
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOBIN v$VERSION
else
- # Prints it's own file name as part of --verison output
+ # Prints its own file name as part of --version output
echo "Using existing $(dirname $BIN)/$($BIN --version)"
fi
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
index e39b151f7..65efd5703 100644
--- a/libpod/boltdb_state_linux.go
+++ b/libpod/boltdb_state_linux.go
@@ -28,7 +28,7 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) er
newState.NetNS = ns
} else {
if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
- return errors.Wrapf(err, "error joning network namespace of container %s", ctr.ID())
+ return errors.Wrapf(err, "error joining network namespace of container %s", ctr.ID())
}
logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err)
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 1b33f16b4..c3e1a23d2 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -571,7 +571,7 @@ func (c *Container) Cleanup(ctx context.Context) error {
// Batch starts a batch operation on the given container
// All commands in the passed function will execute under the same lock and
-// without syncronyzing state after each operation
+// without synchronizing state after each operation
// This will result in substantial performance benefits when running numerous
// commands on the same container
// Note that the container passed into the Batch function cannot be removed
diff --git a/libpod/container_config.go b/libpod/container_config.go
index c95be9b55..93ac8807d 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -151,7 +151,7 @@ type ContainerRootFSConfig struct {
// ContainerSecurityConfig is an embedded sub-config providing security configuration
// to the container.
type ContainerSecurityConfig struct {
- // Pirivileged is whether the container is privileged. Privileged
+ // Privileged is whether the container is privileged. Privileged
// containers have lessened security and increased access to the system.
// Note that this does NOT directly correspond to Podman's --privileged
// flag - most of the work of that flag is done in creating the OCI spec
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 2ce3e8e68..51474471b 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/driver"
"github.com/containers/podman/v2/pkg/util"
+ units "github.com/docker/go-units"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/runtime-tools/validate"
@@ -124,8 +125,6 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
HostnamePath: hostnamePath,
HostsPath: hostsPath,
StaticDir: config.StaticDir,
- LogPath: config.LogPath,
- LogTag: config.LogTag,
OCIRuntime: config.OCIRuntime,
ConmonPidFile: config.ConmonPidFile,
Name: config.Name,
@@ -354,6 +353,10 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
logConfig := new(define.InspectLogConfig)
logConfig.Type = c.config.LogDriver
+ logConfig.Path = c.config.LogPath
+ logConfig.Size = units.HumanSize(float64(c.config.LogSize))
+ logConfig.Tag = c.config.LogTag
+
hostConfig.LogConfig = logConfig
restartPolicy := new(define.InspectRestartPolicy)
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index c751d775d..540230c26 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -884,9 +884,9 @@ func (c *Container) startDependencies(ctx context.Context) error {
// getAllDependencies is a precursor to starting dependencies.
// To start a container with all of its dependencies, we need to recursively find all dependencies
// a container has, as well as each of those containers' dependencies, and so on
-// To do so, keep track of containers already visisted (so there aren't redundant state lookups),
+// To do so, keep track of containers already visited (so there aren't redundant state lookups),
// and recursively search until we have reached the leafs of every dependency node.
-// Since we need to start all dependencies for our original container to successfully start, we propegate any errors
+// Since we need to start all dependencies for our original container to successfully start, we propagate any errors
// in looking up dependencies.
// Note: this function is currently meant as a robust solution to a narrow problem: start an infra-container when
// a container in the pod is run. It has not been tested for performance past one level, so expansion of recursive start
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 1bf044f9d..05b149e03 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -424,11 +424,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
if c.config.User != "" {
- if rootless.IsRootless() {
- if err := util.CheckRootlessUIDRange(execUser.Uid); err != nil {
- return nil, err
- }
- }
// User and Group must go together
g.SetProcessUID(uint32(execUser.Uid))
g.SetProcessGID(uint32(execUser.Gid))
@@ -1664,7 +1659,7 @@ func (c *Container) getHosts() string {
// generateGroupEntry generates an entry or entries into /etc/group as
// required by container configuration.
-// Generatlly speaking, we will make an entry under two circumstances:
+// Generally speaking, we will make an entry under two circumstances:
// 1. The container is started as a specific user:group, and that group is both
// numeric, and does not already exist in /etc/group.
// 2. It is requested that Libpod add the group that launched Podman to
@@ -1942,7 +1937,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
needGroup = false
}
- // Next, check if we already made the files. If we didn, don't need to
+ // Next, check if we already made the files. If we didn't, don't need to
// do anything more.
if needPasswd {
passwdPath := filepath.Join(c.config.StaticDir, "passwd")
diff --git a/libpod/container_log.go b/libpod/container_log.go
index 03cb09052..e58503bd3 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -23,7 +23,7 @@ func (r *Runtime) Log(ctx context.Context, containers []*Container, options *log
return nil
}
-// ReadLog reads a containers log based on the input options and returns loglines over a channel.
+// ReadLog reads a containers log based on the input options and returns log lines over a channel.
func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
switch c.LogDriver() {
case define.NoLogging:
diff --git a/libpod/container_top_unsupported.go b/libpod/container_top_unsupported.go
index f911837d2..866fe106f 100644
--- a/libpod/container_top_unsupported.go
+++ b/libpod/container_top_unsupported.go
@@ -14,7 +14,7 @@ func (c *Container) Top(descriptors []string) ([]string, error) {
// the container. The output data can be controlled via the `descriptors`
// argument which expects format descriptors and supports all AIXformat
// descriptors of ps (1) plus some additional ones to for instance inspect the
-// set of effective capabilities. Eeach element in the returned string slice
+// set of effective capabilities. Each element in the returned string slice
// is a tab-separated string.
//
// For more details, please refer to github.com/containers/psgo.
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index fa809436e..57bb929dd 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -88,7 +88,7 @@ func (c *Container) validate() error {
return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if using image's /etc/hosts")
}
- // Check named volume, overlay volume and image volume destination conflits
+ // Check named volume, overlay volume and image volume destination conflist
destinations := make(map[string]bool)
for _, vol := range c.config.NamedVolumes {
// Don't check if they already exist.
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 775965477..c61f7c159 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -82,10 +82,15 @@ type InspectRestartPolicy struct {
}
// InspectLogConfig holds information about a container's configured log driver
-// and is presently unused. It is retained for Docker compatibility.
type InspectLogConfig struct {
Type string `json:"Type"`
Config map[string]string `json:"Config"` //idk type, TODO
+ // Path specifies a path to the log file
+ Path string `json:"Path"`
+ // Tag specifies a custom log tag for the container
+ Tag string `json:"Tag"`
+ // Size specifies a maximum size of the container log
+ Size string `json:"Size"`
}
// InspectBlkioWeightDevice holds information about the relative weight
@@ -152,7 +157,7 @@ type InspectMount struct {
// "volume" and "bind".
Type string `json:"Type"`
// The name of the volume. Empty for bind mounts.
- Name string `json:"Name,omptempty"`
+ Name string `json:"Name,omitempty"`
// The source directory for the volume.
Source string `json:"Source"`
// The destination directory for the volume. Specified as a path within
@@ -547,7 +552,7 @@ type InspectBasicNetworkConfig struct {
// GlobalIPv6PrefixLen is the length of the subnet mask of this network.
GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"`
// SecondaryIPv6Addresses is a list of extra IPv6 Addresses that the
- // container has been assigned in this networ.
+ // container has been assigned in this network.
SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty"`
// MacAddress is the MAC address for the interface in this network.
MacAddress string `json:"MacAddress"`
@@ -620,8 +625,6 @@ type InspectContainerData struct {
StaticDir string `json:"StaticDir"`
OCIConfigPath string `json:"OCIConfigPath,omitempty"`
OCIRuntime string `json:"OCIRuntime,omitempty"`
- LogPath string `json:"LogPath"`
- LogTag string `json:"LogTag"`
ConmonPidFile string `json:"ConmonPidFile"`
Name string `json:"Name"`
RestartCount int32 `json:"RestartCount"`
diff --git a/libpod/define/info.go b/libpod/define/info.go
index f0e05801c..00146da48 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -12,6 +12,15 @@ type Info struct {
}
//HostInfo describes the libpod host
+type SecurityInfo struct {
+ AppArmorEnabled bool `json:"apparmorEnabled"`
+ DefaultCapabilities string `json:"capabilities"`
+ Rootless bool `json:"rootless"`
+ SECCOMPEnabled bool `json:"seccompEnabled"`
+ SELinuxEnabled bool `json:"selinuxEnabled"`
+}
+
+//HostInfo describes the libpod host
type HostInfo struct {
Arch string `json:"arch"`
BuildahVersion string `json:"buildahVersion"`
@@ -29,8 +38,8 @@ type HostInfo struct {
OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
OS string `json:"os"`
RemoteSocket *RemoteSocket `json:"remoteSocket,omitempty"`
- Rootless bool `json:"rootless"`
RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
+ Security SecurityInfo `json:"security"`
Slirp4NetNS SlirpInfo `json:"slirp4netns,omitempty"`
SwapFree int64 `json:"swapFree"`
SwapTotal int64 `json:"swapTotal"`
diff --git a/libpod/events/events.go b/libpod/events/events.go
index 4e7267af3..aa0401b62 100644
--- a/libpod/events/events.go
+++ b/libpod/events/events.go
@@ -216,8 +216,5 @@ func (e EventLogFile) getTail(options ReadOptions) (*tail.Tail, error) {
reopen = false
}
stream := options.Stream
- if len(options.Until) > 0 {
- stream = false
- }
return tail.TailFile(e.options.LogFilePath, tail.Config{ReOpen: reopen, Follow: stream, Location: &seek, Logger: tail.DiscardingLogger, Poll: true})
}
diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go
index 9a514e302..8b7e448b1 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -8,6 +8,7 @@ import (
"strconv"
"time"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/coreos/go-systemd/v22/journal"
"github.com/coreos/go-systemd/v22/sdjournal"
"github.com/pkg/errors"
@@ -72,11 +73,22 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return errors.Wrapf(err, "failed to generate event options")
}
+ var untilTime time.Time
+ if len(options.Until) > 0 {
+ untilTime, err = util.ParseInputTime(options.Until)
+ if err != nil {
+ return err
+ }
+ }
j, err := sdjournal.NewJournal()
if err != nil {
return err
}
-
+ defer func() {
+ if err := j.Close(); err != nil {
+ logrus.Errorf("Unable to close journal :%v", err)
+ }
+ }()
// match only podman journal entries
podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"}
if err := j.AddMatch(podmanJournal.String()); err != nil {
@@ -104,7 +116,6 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return errors.Wrap(err, "failed to get journal cursor")
}
-
for {
select {
case <-ctx.Done():
@@ -122,10 +133,14 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
return errors.Wrap(err, "failed to get journal cursor")
}
if prevCursor == newCursor {
- if len(options.Until) > 0 || !options.Stream {
+ if !options.Stream || (len(options.Until) > 0 && time.Now().After(untilTime)) {
break
}
- _ = j.Wait(sdjournal.IndefiniteWait)
+ t := sdjournal.IndefiniteWait
+ if len(options.Until) > 0 {
+ t = time.Until(untilTime)
+ }
+ _ = j.Wait(t)
continue
}
prevCursor = newCursor
diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go
index 57e38b815..05ae3ce52 100644
--- a/libpod/events/logfile.go
+++ b/libpod/events/logfile.go
@@ -4,7 +4,9 @@ import (
"context"
"fmt"
"os"
+ "time"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
)
@@ -51,6 +53,16 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return err
}
+ if len(options.Until) > 0 {
+ untilTime, err := util.ParseInputTime(options.Until)
+ if err != nil {
+ return err
+ }
+ go func() {
+ time.Sleep(time.Until(untilTime))
+ t.Stop()
+ }()
+ }
funcDone := make(chan bool)
copy := true
go func() {
diff --git a/libpod/image/df.go b/libpod/image/df.go
index 84cf7af9e..231d28df4 100644
--- a/libpod/image/df.go
+++ b/libpod/image/df.go
@@ -51,7 +51,7 @@ func (ir *Runtime) DiskUsage(ctx context.Context, images []*Image) ([]DiskUsageS
return stats, nil
}
-// diskUsageForImage returns the disk-usage statistics for the spcified image.
+// diskUsageForImage returns the disk-usage statistics for the specified image.
func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) (*DiskUsageStat, error) {
stat := DiskUsageStat{
ID: image.ID(),
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 5c3f3b9e4..a9082b2c6 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -497,7 +497,7 @@ func (ir *Runtime) getLocalImage(inputName string) (string, *storage.Image, erro
return inputName, repoImage, nil
}
- return "", nil, errors.Wrapf(ErrNoSuchImage, err.Error())
+ return "", nil, err
}
// ID returns the image ID as a string
diff --git a/libpod/image/parts.go b/libpod/image/parts.go
index d6c98783b..08421320c 100644
--- a/libpod/image/parts.go
+++ b/libpod/image/parts.go
@@ -50,7 +50,7 @@ func decompose(input string) (imageParts, error) {
// suspiciousRefNameTagValuesForSearch returns a "tag" value used in a previous implementation.
// This exists only to preserve existing behavior in heuristic code; it’s dubious that that behavior is correct,
-// gespecially for the tag value.
+// especially for the tag value.
func (ip *imageParts) suspiciousRefNameTagValuesForSearch() (string, string, string) {
registry := reference.Domain(ip.unnormalizedRef)
imageName := reference.Path(ip.unnormalizedRef)
diff --git a/libpod/image/prune.go b/libpod/image/prune.go
index b38265a7e..3c06a89c2 100644
--- a/libpod/image/prune.go
+++ b/libpod/image/prune.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/timetype"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -110,7 +111,8 @@ func (ir *Runtime) GetPruneImages(ctx context.Context, all bool, filterFuncs []I
// PruneImages prunes dangling and optionally all unused images from the local
// image store
-func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
+func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
filterFuncs := make([]ImageFilter, 0, len(filter))
for _, f := range filter {
filterSplit := strings.SplitN(f, "=", 2)
@@ -125,7 +127,6 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
filterFuncs = append(filterFuncs, generatedFunc)
}
- pruned := []string{}
prev := 0
for {
toPrune, err := ir.GetPruneImages(ctx, all, filterFuncs)
@@ -143,6 +144,13 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
if err != nil {
return nil, err
}
+ nameOrID := img.ID()
+ s, err := img.Size(ctx)
+ imgSize := *s
+ if err != nil {
+ logrus.Warnf("Failed to collect image size for: %s, %s", nameOrID, err)
+ imgSize = 0
+ }
if err := img.Remove(ctx, false); err != nil {
if errors.Cause(err) == storage.ErrImageUsedByContainer {
logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage (e.g., Buildah, CRI-O, etc.) maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", img.ID(), err)
@@ -151,13 +159,18 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
return nil, errors.Wrap(err, "failed to prune image")
}
defer img.newImageEvent(events.Prune)
- nameOrID := img.ID()
+
if len(repotags) > 0 {
nameOrID = repotags[0]
}
- pruned = append(pruned, nameOrID)
+
+ preports = append(preports, &reports.PruneReport{
+ Id: nameOrID,
+ Err: nil,
+ Size: uint64(imgSize),
+ })
}
}
- return pruned, nil
+ return preports, nil
}
diff --git a/libpod/image/search.go b/libpod/image/search.go
index b9acf4a20..6020fbca9 100644
--- a/libpod/image/search.go
+++ b/libpod/image/search.go
@@ -26,7 +26,7 @@ const (
type SearchResult struct {
// Index is the image index (e.g., "docker.io" or "quay.io")
Index string
- // Name is the canoncical name of the image (e.g., "docker.io/library/alpine").
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
Name string
// Description of the image.
Description string
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index 7429a7f10..5e7fed5c6 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -20,7 +20,11 @@ import (
// a match on name:tag
func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) {
_, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch()
- var results []*storage.Image
+ type Candidate struct {
+ name string
+ image *Image
+ }
+ var candidates []Candidate
for _, image := range images {
for _, name := range image.Names() {
d, err := decompose(name)
@@ -29,23 +33,53 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er
continue
}
_, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch()
- if dName == searchName && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
- results = append(results, image.image)
+ if dSuspiciousTagValueForSearch != searchSuspiciousTagValueForSearch {
continue
}
- // account for registry:/somedir/image
- if strings.HasSuffix(dName, "/"+searchName) && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
- results = append(results, image.image)
- continue
+ if dName == searchName || strings.HasSuffix(dName, "/"+searchName) {
+ candidates = append(candidates, Candidate{
+ name: name,
+ image: image,
+ })
}
}
}
- if len(results) == 0 {
- return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
- } else if len(results) > 1 {
- return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName)
+ if len(candidates) == 0 {
+
+ return nil, errors.Wrapf(define.ErrNoSuchImage, "unable to find a name and tag match for %s in repotags", searchName)
+ }
+
+ // If more then one candidate and the candidates all have same name
+ // and only one is read/write return it.
+ // Othewise return error with the list of candidates
+ if len(candidates) > 1 {
+ var (
+ rwImage *Image
+ rwImageCnt int
+ )
+ names := make(map[string]bool)
+ for _, c := range candidates {
+ names[c.name] = true
+ if !c.image.IsReadOnly() {
+ rwImageCnt++
+ rwImage = c.image
+ }
+ }
+ // If only one name used and have read/write image return it
+ if len(names) == 1 && rwImageCnt == 1 {
+ return rwImage.image, nil
+ }
+ keys := []string{}
+ for k := range names {
+ keys = append(keys, k)
+ }
+ if rwImageCnt > 1 {
+ return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/write images %s", strings.Join(keys, ","))
+ } else {
+ return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/only images %s", strings.Join(keys, ","))
+ }
}
- return results[0], nil
+ return candidates[0].image.image, nil
}
// getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc.
diff --git a/libpod/info.go b/libpod/info.go
index 2f64a107e..1b3550abd 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,6 +13,8 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/common/pkg/apparmor"
+ "github.com/containers/common/pkg/seccomp"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/linkmode"
"github.com/containers/podman/v2/pkg/cgroups"
@@ -20,6 +22,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/system"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -98,10 +101,16 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
MemFree: mi.MemFree,
MemTotal: mi.MemTotal,
OS: runtime.GOOS,
- Rootless: rootless.IsRootless(),
- Slirp4NetNS: define.SlirpInfo{},
- SwapFree: mi.SwapFree,
- SwapTotal: mi.SwapTotal,
+ Security: define.SecurityInfo{
+ AppArmorEnabled: apparmor.IsEnabled(),
+ DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","),
+ Rootless: rootless.IsRootless(),
+ SECCOMPEnabled: seccomp.IsEnabled(),
+ SELinuxEnabled: selinux.GetEnabled(),
+ },
+ Slirp4NetNS: define.SlirpInfo{},
+ SwapFree: mi.SwapFree,
+ SwapTotal: mi.SwapTotal,
}
// CGroups version
diff --git a/libpod/kube.go b/libpod/kube.go
index bf041112a..753c58099 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -403,7 +403,7 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) {
- // TjDO when named volumes are supported in play kube, also parse named volumes here
+ // TODO when named volumes are supported in play kube, also parse named volumes here
_, mounts := c.sortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts))
@@ -524,7 +524,7 @@ func capAddDrop(caps *specs.LinuxCapabilities) (*v1.Capabilities, error) {
defaultCaps = append(defaultCaps, g.Config.Process.Capabilities.Inheritable...)
defaultCaps = append(defaultCaps, g.Config.Process.Capabilities.Permitted...)
- // Combine all the container's capabilities into a slic
+ // Combine all the container's capabilities into a slice
containerCaps := append(caps.Ambient, caps.Bounding...)
containerCaps = append(containerCaps, caps.Effective...)
containerCaps = append(containerCaps, caps.Inheritable...)
diff --git a/libpod/logs/log.go b/libpod/logs/log.go
index a9554088b..2637c8524 100644
--- a/libpod/logs/log.go
+++ b/libpod/logs/log.go
@@ -73,7 +73,7 @@ func GetLogFile(path string, options *LogOptions) (*tail.Tail, []*LogLine, error
Whence: whence,
}
- t, err := tail.TailFile(path, tail.Config{MustExist: true, Poll: true, Follow: options.Follow, Location: &seek, Logger: tail.DiscardingLogger})
+ t, err := tail.TailFile(path, tail.Config{MustExist: true, Poll: true, Follow: options.Follow, Location: &seek, Logger: tail.DiscardingLogger, ReOpen: options.Follow})
return t, logTail, err
}
@@ -137,7 +137,7 @@ func getTailLog(path string, tail int) ([]*LogLine, error) {
nllCounter++
}
}
- // if we have enough loglines, we can hangup
+ // if we have enough log lines, we can hangup
if nllCounter >= tail {
break
}
@@ -161,7 +161,7 @@ func getTailLog(path string, tail int) ([]*LogLine, error) {
return tailLog, nil
}
-// String converts a logline to a string for output given whether a detail
+// String converts a log line to a string for output given whether a detail
// bool is specified.
func (l *LogLine) String(options *LogOptions) string {
var out string
@@ -210,3 +210,19 @@ func NewLogLine(line string) (*LogLine, error) {
func (l *LogLine) Partial() bool {
return l.ParseLogType == PartialLogType
}
+
+func (l *LogLine) Write(stdout io.Writer, stderr io.Writer, logOpts *LogOptions) {
+ switch l.Device {
+ case "stdout":
+ if stdout != nil {
+ fmt.Fprintln(stdout, l.String(logOpts))
+ }
+ case "stderr":
+ if stderr != nil {
+ fmt.Fprintln(stderr, l.String(logOpts))
+ }
+ default:
+ // Warn the user if the device type does not match. Most likely the file is corrupted.
+ logrus.Warnf("unknown Device type '%s' in log file from Container %s", l.Device, l.CID)
+ }
+}
diff --git a/libpod/network/create_test.go b/libpod/network/create_test.go
index 16188e497..0b828e635 100644
--- a/libpod/network/create_test.go
+++ b/libpod/network/create_test.go
@@ -61,7 +61,7 @@ func Test_validateBridgeOptions(t *testing.T) {
isIPv6: true,
},
{
- name: "IPv6 subnet, range and gateway without IPv6 option (PODMAN SUPPORTS IT UNLIKE DOCKEr)",
+ name: "IPv6 subnet, range and gateway without IPv6 option (PODMAN SUPPORTS IT UNLIKE DOCKER)",
subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
ipRange: net.IPNet{IP: net.ParseIP("2001:DB8:0:0:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))},
gateway: net.ParseIP("2001:DB8::2"),
diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go
index d61b96ecb..bf7d03501 100644
--- a/libpod/network/netconflist.go
+++ b/libpod/network/netconflist.go
@@ -60,7 +60,7 @@ func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu in
return &hostLocalBridge
}
-// NewIPAMHostLocalConf creates a new IPAMHostLocal configfuration
+// NewIPAMHostLocalConf creates a new IPAMHostLocal configuration
func NewIPAMHostLocalConf(routes []IPAMRoute, ipamRanges [][]IPAMLocalHostRangeConf) (IPAMHostLocalConf, error) {
ipamConf := IPAMHostLocalConf{
PluginType: "host-local",
@@ -95,6 +95,10 @@ func NewIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw net.IP) ([]
}
if gw != nil {
hostRange.Gateway = gw.String()
+ } else {
+ // Add first ip in subnet as gateway. It is not required
+ // by cni but should be included because of network inspect.
+ hostRange.Gateway = CalcGatewayIP(subnet).String()
}
ranges = append(ranges, hostRange)
return ranges, nil
diff --git a/libpod/network/netconflist_test.go b/libpod/network/netconflist_test.go
index 6bf1a9777..5ff733f0f 100644
--- a/libpod/network/netconflist_test.go
+++ b/libpod/network/netconflist_test.go
@@ -51,7 +51,8 @@ func TestNewIPAMLocalHostRange(t *testing.T) {
subnet: &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)},
want: []IPAMLocalHostRangeConf{
{
- Subnet: "192.168.0.0/24",
+ Subnet: "192.168.0.0/24",
+ Gateway: "192.168.0.1",
},
},
},
@@ -74,7 +75,8 @@ func TestNewIPAMLocalHostRange(t *testing.T) {
subnet: &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
want: []IPAMLocalHostRangeConf{
{
- Subnet: "2001:db8::/48",
+ Subnet: "2001:db8::/48",
+ Gateway: "2001:db8::1",
},
},
},
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index bf27989bf..be6867399 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -247,6 +247,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
func (r *Runtime) setupSlirp4netns(ctr *Container) error {
path := r.config.Engine.NetworkCmdPath
slirpOptions := r.config.Engine.NetworkCmdOptions
+ noPivotRoot := r.config.Engine.NoPivotRoot
if path == "" {
var err error
path, err = exec.LookPath("slirp4netns")
@@ -351,7 +352,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
if slirpFeatures.HasMTU {
cmdArgs = append(cmdArgs, "--mtu", "65520")
}
- if slirpFeatures.HasEnableSandbox {
+ if !noPivotRoot && slirpFeatures.HasEnableSandbox {
cmdArgs = append(cmdArgs, "--enable-sandbox")
}
if slirpFeatures.HasEnableSeccomp {
@@ -424,7 +425,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
}
// workaround for https://github.com/rootless-containers/slirp4netns/pull/153
- if slirpFeatures.HasEnableSandbox {
+ if !noPivotRoot && slirpFeatures.HasEnableSandbox {
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
}
@@ -1155,7 +1156,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
return c.save()
}
-// ConnnectNetwork connects a container to a given network
+// ConnectNetwork connects a container to a given network
func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) error {
networks, err := c.networksByNameIndex()
if err != nil {
diff --git a/libpod/oci.go b/libpod/oci.go
index 924c32510..157c42c38 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -56,7 +56,7 @@ type OCIRuntime interface {
// a header prepended as follows: 1-byte STREAM (0, 1, 2 for STDIN,
// STDOUT, STDERR), 3 null (0x00) bytes, 4-byte big endian length.
// If a cancel channel is provided, it can be used to asynchronously
- // termninate the attach session. Detach keys, if given, will also cause
+ // terminate the attach session. Detach keys, if given, will also cause
// the attach session to be terminated if provided via the STDIN
// channel. If they are not provided, the default detach keys will be
// used instead. Detach keys of "" will disable detaching via keyboard.
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go
index 149ee813b..fbc95510e 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_attach_linux.go
@@ -83,7 +83,7 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
// Attach to the given container's exec session
// attachFd and startFd must be open file descriptors
// attachFd must be the output side of the fd. attachFd is used for two things:
-// conmon will first send a nonse value across the pipe indicating it has set up its side of the console socket
+// conmon will first send a nonce value across the pipe indicating it has set up its side of the console socket
// this ensures attachToExec gets all of the output of the called process
// conmon will then send the exit code of the exec process, or an error in the exec session
// startFd must be the input side of the fd.
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index f8e7020f7..4546acefb 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -387,7 +387,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
finalEnv = append(finalEnv, fmt.Sprintf("%s=%s", k, v))
}
- processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID)
+ processFile, err := prepareProcessExec(c, options, finalEnv, sessionID)
if err != nil {
return nil, nil, err
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 307b9bc54..e7cb5a802 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -47,7 +47,7 @@ import (
const (
// This is Conmon's STDIO_BUF_SIZE. I don't believe we have access to it
- // directly from the Go cose, so const it here
+ // directly from the Go code, so const it here
bufferSize = conmonConfig.BufSize
)
@@ -69,6 +69,7 @@ type ConmonOCIRuntime struct {
supportsKVM bool
supportsNoCgroups bool
sdNotify bool
+ enableKeyring bool
}
// Make a new Conmon-based OCI runtime with the given options.
@@ -107,6 +108,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
runtime.noPivot = runtimeCfg.Engine.NoPivotRoot
runtime.reservePorts = runtimeCfg.Engine.EnablePortReservation
runtime.sdNotify = runtimeCfg.Engine.SDNotify
+ runtime.enableKeyring = runtimeCfg.Containers.EnableKeyring
// TODO: probe OCI runtime for feature and enable automatically if
// available.
@@ -191,6 +193,11 @@ func hasCurrentUserMapped(ctr *Container) bool {
// CreateContainer creates a container.
func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) error {
+ // always make the run dir accessible to the current user so that the PID files can be read without
+ // being in the rootless user namespace.
+ if err := makeAccessible(ctr.state.RunDir, 0, 0); err != nil {
+ return err
+ }
if !hasCurrentUserMapped(ctr) {
for _, i := range []string{ctr.state.RunDir, ctr.runtime.config.Engine.TmpDir, ctr.config.StaticDir, ctr.state.Mountpoint, ctr.runtime.config.Engine.VolumePath} {
if err := makeAccessible(i, ctr.RootUID(), ctr.RootGID()); err != nil {
@@ -1021,6 +1028,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
args = append(args, "-i")
}
+ if !r.enableKeyring {
+ args = append(args, "--no-new-keyring")
+ }
if ctr.config.ConmonPidFile != "" {
args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile)
}
@@ -1180,26 +1190,36 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
// prepareProcessExec returns the path of the process.json used in runc exec -p
// caller is responsible to close the returned *os.File if needed.
-func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, sessionID string) (*os.File, error) {
+func prepareProcessExec(c *Container, options *ExecOptions, env []string, sessionID string) (*os.File, error) {
f, err := ioutil.TempFile(c.execBundlePath(sessionID), "exec-process-")
if err != nil {
return nil, err
}
- pspec := c.config.Spec.Process
+ pspec := new(spec.Process)
+ if err := JSONDeepCopy(c.config.Spec.Process, pspec); err != nil {
+ return nil, err
+ }
pspec.SelinuxLabel = c.config.ProcessLabel
- pspec.Args = cmd
+ pspec.Args = options.Cmd
+ for _, cap := range options.CapAdd {
+ pspec.Capabilities.Bounding = append(pspec.Capabilities.Bounding, cap)
+ pspec.Capabilities.Effective = append(pspec.Capabilities.Effective, cap)
+ pspec.Capabilities.Inheritable = append(pspec.Capabilities.Inheritable, cap)
+ pspec.Capabilities.Permitted = append(pspec.Capabilities.Permitted, cap)
+ pspec.Capabilities.Ambient = append(pspec.Capabilities.Ambient, cap)
+ }
// We need to default this to false else it will inherit terminal as true
// from the container.
pspec.Terminal = false
- if tty {
+ if options.Terminal {
pspec.Terminal = true
}
if len(env) > 0 {
pspec.Env = append(pspec.Env, env...)
}
- if cwd != "" {
- pspec.Cwd = cwd
+ if options.Cwd != "" {
+ pspec.Cwd = options.Cwd
}
@@ -1207,6 +1227,7 @@ func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, se
var sgids []uint32
// if the user is empty, we should inherit the user that the container is currently running with
+ user := options.User
if user == "" {
user = c.config.User
addGroups = c.config.Groups
@@ -1413,7 +1434,7 @@ func startCommandGivenSelinux(cmd *exec.Cmd) error {
}
// moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup
-// it then signals for conmon to start by sending nonse data down the start fd
+// it then signals for conmon to start by sending nonce data down the start fd
func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File) error {
mustCreateCgroup := true
@@ -1433,6 +1454,14 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
}
if mustCreateCgroup {
+ // Usually rootless users are not allowed to configure cgroupfs.
+ // There are cases though, where it is allowed, e.g. if the cgroup
+ // is manually configured and chowned). Avoid detecting all
+ // such cases and simply use a lower log level.
+ logLevel := logrus.WarnLevel
+ if rootless.IsRootless() {
+ logLevel = logrus.InfoLevel
+ }
// TODO: This should be a switch - we are not guaranteed that
// there are only 2 valid cgroup managers
cgroupParent := ctr.CgroupParent()
@@ -1447,17 +1476,17 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
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)
+ logrus.StandardLogger().Logf(logLevel, "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)
+ logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
} else if err := control.AddPid(cmd.Process.Pid); err != nil {
// we need to remove this defer and delete the cgroup once conmon exits
// maybe need a conmon monitor?
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
}
}
}
@@ -1564,7 +1593,7 @@ func readConmonPipeData(pipe *os.File, ociLog string) (int, error) {
return data, nil
}
-// writeConmonPipeData writes nonse data to a pipe
+// writeConmonPipeData writes nonce data to a pipe
func writeConmonPipeData(pipe *os.File) error {
someData := []byte{0}
_, err := pipe.Write(someData)
diff --git a/libpod/options.go b/libpod/options.go
index bd12c0c34..8100eee62 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -502,6 +502,7 @@ func WithEventsLogger(logger string) RuntimeOption {
}
rt.config.Engine.EventsLogger = logger
+ rt.config.Engine.EventsLogFilePath = filepath.Join(rt.config.Engine.TmpDir, "events", "events.log")
return nil
}
@@ -750,7 +751,7 @@ func WithStopTimeout(timeout uint) CtrCreateOption {
}
}
-// WithIDMappings sets the idmappsings for the container
+// WithIDMappings sets the idmappings for the container
func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
@@ -1592,7 +1593,7 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption {
volume.config.Options = make(map[string]string)
for key, value := range options {
switch key {
- case "type", "device", "o":
+ case "type", "device", "o", "UID", "GID":
volume.config.Options[key] = value
default:
return errors.Wrapf(define.ErrInvalidArg, "unrecognized volume option %q is not supported with local driver", key)
diff --git a/libpod/pod_top_linux.go b/libpod/pod_top_linux.go
index 0e42c62df..07e1a0d80 100644
--- a/libpod/pod_top_linux.go
+++ b/libpod/pod_top_linux.go
@@ -15,7 +15,7 @@ import (
// the pod. The output data can be controlled via the `descriptors`
// argument which expects format descriptors and supports all AIXformat
// descriptors of ps (1) plus some additional ones to for instance inspect the
-// set of effective capabilities. Eeach element in the returned string slice
+// set of effective capabilities. Each element in the returned string slice
// is a tab-separated string.
//
// For more details, please refer to github.com/containers/psgo.
diff --git a/libpod/reset.go b/libpod/reset.go
index 6d2842723..24efeed40 100644
--- a/libpod/reset.go
+++ b/libpod/reset.go
@@ -77,18 +77,35 @@ func (r *Runtime) Reset(ctx context.Context) error {
}
}
+ xdgRuntimeDir := filepath.Clean(os.Getenv("XDG_RUNTIME_DIR"))
_, prevError := r.store.Shutdown(true)
- if err := os.RemoveAll(r.store.GraphRoot()); err != nil {
+ graphRoot := filepath.Clean(r.store.GraphRoot())
+ if graphRoot == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime graph root dir %s, since it is the same as XDG_RUNTIME_DIR", graphRoot)
+ } else {
+ if err := os.RemoveAll(graphRoot); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
- if err := os.RemoveAll(r.store.RunRoot()); err != nil {
+ runRoot := filepath.Clean(r.store.RunRoot())
+ if runRoot == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime root dir %s, since it is the same as XDG_RUNTIME_DIR", runRoot)
+ } else {
+ if err := os.RemoveAll(runRoot); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
@@ -98,13 +115,19 @@ func (r *Runtime) Reset(ctx context.Context) error {
if tempDir == runtimeDir {
tempDir = filepath.Join(tempDir, "containers")
}
- if err := os.RemoveAll(tempDir); err != nil {
+ if filepath.Clean(tempDir) == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime tmpdir %s, since it is the same as XDG_RUNTIME_DIR", tempDir)
+ } else {
+ if err := os.RemoveAll(tempDir); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
-
if storageConfPath, err := storage.DefaultConfigFile(rootless.IsRootless()); err == nil {
if _, err = os.Stat(storageConfPath); err == nil {
fmt.Printf("A storage.conf file exists at %s\n", storageConfPath)
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 2c2977f9f..ce8a87759 100644
--- a/libpod/rootless_cni_linux.go
+++ b/libpod/rootless_cni_linux.go
@@ -100,7 +100,7 @@ func DeallocRootlessCNI(ctx context.Context, c *Container) error {
}
var errs *multierror.Error
for _, nw := range networks {
- err := rootlessCNIInfraCallDelloc(infra, c.ID(), nw)
+ err := rootlessCNIInfraCallDealloc(infra, c.ID(), nw)
if err != nil {
errs = multierror.Append(errs, err)
}
@@ -154,7 +154,7 @@ func rootlessCNIInfraCallAlloc(infra *Container, id, nw, k8sPodName string) (*cn
return &cniRes, nil
}
-func rootlessCNIInfraCallDelloc(infra *Container, id, nw string) error {
+func rootlessCNIInfraCallDealloc(infra *Container, id, nw string) error {
logrus.Debugf("rootless CNI: dealloc %q, %q", id, nw)
_, err := rootlessCNIInfraExec(infra, "dealloc", id, nw)
return err
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 14b537ca2..f22e48746 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/cgroups"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
@@ -884,9 +885,8 @@ func (r *Runtime) GetExecSessionContainer(id string) (*Container, error) {
// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
// can be provided to be more granular.
-func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
- pruneErrors := make(map[string]error)
- prunedContainers := make(map[string]int64)
+func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
// We add getting the exited and stopped containers via a filter
containerStateFilter := func(c *Container) bool {
if c.PodID() != "" {
@@ -906,23 +906,28 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
filterFuncs = append(filterFuncs, containerStateFilter)
delContainers, err := r.GetContainers(filterFuncs...)
if err != nil {
- return nil, nil, err
+ return nil, err
}
for _, c := range delContainers {
- ctr := c
- size, err := ctr.RWSize()
+ report := new(reports.PruneReport)
+ report.Id = c.ID()
+ report.Err = nil
+ report.Size = 0
+ size, err := c.RWSize()
if err != nil {
- pruneErrors[ctr.ID()] = err
+ report.Err = err
+ preports = append(preports, report)
continue
}
- err = r.RemoveContainer(context.Background(), ctr, false, false)
+ err = r.RemoveContainer(context.Background(), c, false, false)
if err != nil {
- pruneErrors[ctr.ID()] = err
+ report.Err = err
} else {
- prunedContainers[ctr.ID()] = size
+ report.Size = (uint64)(size)
}
+ preports = append(preports, report)
}
- return prunedContainers, pruneErrors, nil
+ return preports, nil
}
// MountStorageContainer mounts the storage container's root filesystem
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index a2d9a875e..965333f77 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -230,7 +230,7 @@ func (r *Runtime) Import(ctx context.Context, source, reference, signaturePolicy
return newImage.ID(), nil
}
-// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
+// downloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
// and temporarily saves in it $TMPDIR/importxyz, which is deleted after the image is imported
func downloadFromURL(source string) (string, error) {
fmt.Printf("Downloading from %q\n", source)
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 055a243c0..9d985f905 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -133,22 +134,32 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
}
// PruneVolumes removes unused volumes from the system
-func (r *Runtime) PruneVolumes(ctx context.Context) (map[string]error, error) {
- reports := make(map[string]error)
- vols, err := r.GetAllVolumes()
+func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
+ vols, err := r.Volumes(filterFuncs...)
if err != nil {
return nil, err
}
for _, vol := range vols {
+ report := new(reports.PruneReport)
+ volSize, err := vol.Size()
+ if err != nil {
+ volSize = 0
+ }
+ report.Size = volSize
+ report.Id = vol.Name()
if err := r.RemoveVolume(ctx, vol, false); err != nil {
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
- reports[vol.Name()] = err
+ report.Err = err
+ } else {
+ // We didn't remove the volume for some reason
+ continue
}
- continue
+ } else {
+ vol.newVolumeEvent(events.Prune)
}
- vol.newVolumeEvent(events.Prune)
- reports[vol.Name()] = nil
+ preports = append(preports, report)
}
- return reports, nil
+ return preports, nil
}
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index e1877b17d..9bf0fd108 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -58,7 +58,7 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption)
// Validate options
for key := range volume.config.Options {
switch key {
- case "device", "o", "type":
+ case "device", "o", "type", "UID", "GID":
// Do nothing, valid keys
default:
return nil, errors.Wrapf(define.ErrInvalidArg, "invalid mount option %s for driver 'local'", key)
diff --git a/libpod/state_test.go b/libpod/state_test.go
index da28f3d3f..0709071ec 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -882,7 +882,7 @@ func TestRemoveContainer(t *testing.T) {
})
}
-func TestRemoveNonexistantContainerFails(t *testing.T) {
+func TestRemoveNonexistentContainerFails(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
testCtr, err := getTestCtr1(manager)
assert.NoError(t, err)
@@ -1513,7 +1513,7 @@ func TestGetNotExistPodWithPods(t *testing.T) {
err = state.AddPod(testPod2)
assert.NoError(t, err)
- _, err = state.Pod("notexist")
+ _, err = state.Pod("nonexistent")
assert.Error(t, err)
})
}
@@ -1748,7 +1748,7 @@ func TestHasPodEmptyIDErrors(t *testing.T) {
func TestHasPodNoSuchPod(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
- exist, err := state.HasPod("notexist")
+ exist, err := state.HasPod("nonexistent")
assert.NoError(t, err)
assert.False(t, exist)
})
diff --git a/libpod/util.go b/libpod/util.go
index c26039c50..bf9bf2542 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -142,29 +142,44 @@ func JSONDeepCopy(from, to interface{}) error {
return json.Unmarshal(tmp, to)
}
-func dpkgVersion(path string) string {
+func queryPackageVersion(cmdArg ...string) string {
output := unknownPackage
- cmd := exec.Command("/usr/bin/dpkg", "-S", path)
- if outp, err := cmd.Output(); err == nil {
- output = string(outp)
+ if 1 < len(cmdArg) {
+ cmd := exec.Command(cmdArg[0], cmdArg[1:]...)
+ if outp, err := cmd.Output(); err == nil {
+ output = string(outp)
+ }
}
return strings.Trim(output, "\n")
}
+func equeryVersion(path string) string {
+ return queryPackageVersion("/usr/bin/equery", "b", path)
+}
+
+func pacmanVersion(path string) string {
+ return queryPackageVersion("/usr/bin/pacman", "-Qo", path)
+}
+
+func dpkgVersion(path string) string {
+ return queryPackageVersion("/usr/bin/dpkg", "-S", path)
+}
+
func rpmVersion(path string) string {
- output := unknownPackage
- cmd := exec.Command("/usr/bin/rpm", "-q", "-f", path)
- if outp, err := cmd.Output(); err == nil {
- output = string(outp)
- }
- return strings.Trim(output, "\n")
+ return queryPackageVersion("/usr/bin/rpm", "-q", "-f", path)
}
func packageVersion(program string) string {
if out := rpmVersion(program); out != unknownPackage {
return out
}
- return dpkgVersion(program)
+ if out := dpkgVersion(program); out != unknownPackage {
+ return out
+ }
+ if out := pacmanVersion(program); out != unknownPackage {
+ return out
+ }
+ return equeryVersion(program)
}
func programVersion(mountProgram string) (string, error) {
@@ -272,7 +287,7 @@ func writeHijackHeader(r *http.Request, conn io.Writer) {
fmt.Fprintf(conn,
"HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
} else {
- // Upraded
+ // Upgraded
fmt.Fprintf(conn,
"HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: %s\r\n\r\n",
proto)
diff --git a/libpod/volume.go b/libpod/volume.go
index 0535bf4db..ed08d375f 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "os"
+ "path/filepath"
"time"
"github.com/containers/podman/v2/libpod/define"
@@ -79,6 +81,18 @@ func (v *Volume) Name() string {
return v.config.Name
}
+// Returns the size on disk of volume
+func (v *Volume) Size() (uint64, error) {
+ var size uint64
+ err := filepath.Walk(v.config.MountPoint, func(path string, info os.FileInfo, err error) error {
+ if err == nil && !info.IsDir() {
+ size += (uint64)(info.Size())
+ }
+ return err
+ })
+ return size, err
+}
+
// Driver retrieves the volume's driver.
func (v *Volume) Driver() string {
return v.config.Driver
diff --git a/nix/default.nix b/nix/default.nix
index a1a8c5287..13b4585ea 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -38,10 +38,10 @@ let
doCheck = false;
enableParallelBuilding = true;
outputs = [ "out" ];
- nativeBuildInputs = [ bash git go-md2man installShellFiles makeWrapper pkg-config which ];
+ nativeBuildInputs = [ bash gitMinimal go-md2man installShellFiles makeWrapper pkg-config which ];
buildInputs = [ glibc glibc.static gpgme libassuan libgpgerror libseccomp libapparmor libselinux ];
prePatch = ''
- export CFLAGS='-static'
+ export CFLAGS='-static -pthread'
export LDFLAGS='-s -w -static-libgcc -static'
export EXTRA_LDFLAGS='-s -w -linkmode external -extldflags "-static -lm"'
export BUILDTAGS='static netgo osusergo exclude_graphdriver_btrfs exclude_graphdriver_devicemapper seccomp apparmor selinux'
diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json
index 81a2f974c..d304de536 100644
--- a/nix/nixpkgs.json
+++ b/nix/nixpkgs.json
@@ -1,7 +1,10 @@
{
"url": "https://github.com/nixos/nixpkgs",
- "rev": "6e089d30148953df7abb3a1167169afc7848499c",
- "date": "2020-11-05T09:56:30+01:00",
- "sha256": "0ydqjkz7payl16psx445jwh6dc6lgbvj2w11xin1dqvbpcp03jcy",
- "fetchSubmodules": false
+ "rev": "4a75203f0270f96cbc87f5dfa5d5185690237d87",
+ "date": "2020-12-29T03:18:48+01:00",
+ "path": "/nix/store/scswsm6r4jnhp9ki0f6s81kpj5x6jkn7-nixpkgs",
+ "sha256": "0h70fm9aa7s06wkalbadw70z5rscbs3p6nblb47z523nhlzgjxk9",
+ "fetchSubmodules": false,
+ "deepClone": false,
+ "leaveDotGit": false
}
diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go
index 19b1029d1..8badab20d 100644
--- a/pkg/annotations/annotations.go
+++ b/pkg/annotations/annotations.go
@@ -94,7 +94,7 @@ const (
// StdinOnce is the stdin_once annotation
StdinOnce = "io.kubernetes.cri-o.StdinOnce"
- // Volumes is the volumes annotatoin
+ // Volumes is the volumes annotation
Volumes = "io.kubernetes.cri-o.Volumes"
// HostNetwork indicates whether the host network namespace is used or not
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 7a3e5dd84..0f89c859e 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "sort"
"strconv"
"strings"
"syscall"
@@ -13,6 +14,8 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/domain/filters"
+ "github.com/containers/podman/v2/pkg/ps"
"github.com/containers/podman/v2/pkg/signal"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
@@ -78,10 +81,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
- var (
- containers []*libpod.Container
- err error
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
@@ -97,22 +96,48 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- if query.All {
- containers, err = runtime.GetAllContainers()
- } else {
- containers, err = runtime.GetRunningContainers()
+
+ filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
+ all := query.All || query.Limit > 0
+ if len(query.Filters) > 0 {
+ for k, v := range query.Filters {
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filterFuncs = append(filterFuncs, generatedFunc)
+ }
}
+
+ // Docker thinks that if status is given as an input, then we should override
+ // the all setting and always deal with all containers.
+ if len(query.Filters["status"]) > 0 {
+ all = true
+ }
+ if !all {
+ runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filterFuncs = append(filterFuncs, runningOnly)
+ }
+
+ containers, err := runtime.GetContainers(filterFuncs...)
if err != nil {
utils.InternalServerError(w, err)
return
}
if _, found := r.URL.Query()["limit"]; found && query.Limit > 0 {
- last := query.Limit
- if len(containers) > last {
- containers = containers[len(containers)-last:]
+ // Sort the libpod containers
+ sort.Sort(ps.SortCreateTime{SortContainers: containers})
+ // we should perform the lopping before we start getting
+ // the expensive information on containers
+ if len(containers) > query.Limit {
+ containers = containers[:query.Limit]
}
}
- // TODO filters still need to be applied
var list = make([]*handlers.Container, len(containers))
for i, ctnr := range containers {
api, err := LibpodToContainer(ctnr, query.Size)
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index d8197415c..083c72ce8 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -3,11 +3,13 @@ package compat
import (
"fmt"
"net/http"
+ "os"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/copy"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -44,58 +46,47 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
}
containerName := utils.GetName(r)
-
- ctr, err := runtime.LookupContainer(containerName)
- if errors.Cause(err) == define.ErrNoSuchCtr {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists"))
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+ statReport, err := containerEngine.ContainerStat(r.Context(), containerName, query.Path)
+
+ // NOTE
+ // The statReport may actually be set even in case of an error. That's
+ // the case when we're looking at a symlink pointing to nirvana. In
+ // such cases, we really need the FileInfo but we also need the error.
+ if statReport != nil {
+ statHeader, err := copy.EncodeFileInfo(&statReport.FileInfo)
+ if err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ return
+ }
+ w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
+ }
+
+ if errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == copy.ENOENT {
+ // 404 is returned for an absent container and path. The
+ // clients must deal with it accordingly.
+ utils.Error(w, "Not found.", http.StatusNotFound, err)
return
} else if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- source, err := copy.CopyItemForContainer(ctr, query.Path, true, true)
- defer source.CleanUp()
- if err != nil {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
- return
- }
-
- // NOTE: Docker always sets the header.
- info, err := source.Stat()
- if err != nil {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
- return
- }
- statHeader, err := copy.EncodeFileInfo(info)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
-
// Our work is done when the user is interested in the header only.
if r.Method == http.MethodHead {
w.WriteHeader(http.StatusOK)
return
}
- // Alright, the users wants data from the container.
- destination, err := copy.CopyItemForWriter(w)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
-
- copier, err := copy.GetCopier(&source, &destination, false)
+ copyFunc, err := containerEngine.ContainerCopyToArchive(r.Context(), containerName, query.Path, w)
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+ w.Header().Set("Content-Type", "application/x-tar")
w.WriteHeader(http.StatusOK)
- if err := copier.Copy(); err != nil {
- logrus.Errorf("Error during copy: %v", err)
- return
+ if err := copyFunc(); err != nil {
+ logrus.Error(err.Error())
}
}
@@ -113,36 +104,22 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder,
return
}
- ctrName := utils.GetName(r)
-
- ctr, err := runtime.LookupContainer(ctrName)
- if err != nil {
- utils.Error(w, "Not found", http.StatusNotFound, errors.Wrapf(err, "the %s container doesn't exists", ctrName))
- return
- }
+ containerName := utils.GetName(r)
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
- destination, err := copy.CopyItemForContainer(ctr, query.Path, true, false)
- defer destination.CleanUp()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body)
+ if errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err) {
+ // 404 is returned for an absent container and path. The
+ // clients must deal with it accordingly.
+ utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists"))
return
- }
-
- source, err := copy.CopyItemForReader(r.Body)
- defer source.CleanUp()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ } else if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- copier, err := copy.GetCopier(&source, &destination, false)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
w.WriteHeader(http.StatusOK)
- if err := copier.Copy(); err != nil {
- logrus.Errorf("Error during copy: %v", err)
- return
+ if err := copyFunc(); err != nil {
+ logrus.Error(err.Error())
}
}
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 409a74de2..6e85872b2 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -66,7 +66,20 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
return
}
- sg := specgen.NewSpecGenerator(newImage.ID(), cliOpts.RootFS)
+
+ imgNameOrID := newImage.ID()
+ // if the img had multi names with the same sha256 ID, should use the InputName, not the ID
+ if len(newImage.Names()) > 1 {
+ imageRef, err := utils.ParseDockerReference(newImage.InputName)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
+ return
+ }
+ // maybe the InputName has no tag, so use full name to display
+ imgNameOrID = imageRef.DockerReference().String()
+ }
+
+ sg := specgen.NewSpecGenerator(imgNameOrID, cliOpts.RootFS)
if err := common.FillOutSpecGen(sg, cliOpts, args); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen"))
return
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index 2cfeebcce..b3d26b8f4 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -4,19 +4,14 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
- "github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/docker/docker/api/types"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
+ "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
func PruneContainers(w http.ResponseWriter, r *http.Request) {
- var (
- delContainers []string
- space int64
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -29,7 +24,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
}
filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
for k, v := range query.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime)
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -49,36 +44,21 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
return
}
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ report, err := runtime.PruneContainers(filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return
}
- for ctrID, size := range prunedContainers {
- if pruneErrors[ctrID] == nil {
- space += size
- delContainers = append(delContainers, ctrID)
- }
- }
- report := types.ContainersPruneReport{
- ContainersDeleted: delContainers,
- SpaceReclaimed: uint64(space),
- }
utils.WriteResponse(w, http.StatusOK, report)
}
func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) (
- *entities.ContainerPruneReport, error) {
+ []*reports.PruneReport, error) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ reports, err := runtime.PruneContainers(filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return nil, err
}
-
- report := &entities.ContainerPruneReport{
- Err: pruneErrors,
- ID: prunedContainers,
- }
- return report, nil
+ return reports, nil
}
diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go
index f74491a8f..82a74e419 100644
--- a/pkg/api/handlers/compat/events.go
+++ b/pkg/api/handlers/compat/events.go
@@ -33,6 +33,8 @@ func filtersFromRequest(r *http.Request) ([]string, error) {
if _, found := r.URL.Query()["filters"]; found {
raw = []byte(r.Form.Get("filters"))
+ } else if _, found := r.URL.Query()["Filters"]; found {
+ raw = []byte(r.Form.Get("Filters"))
} else {
return []string{}, nil
}
@@ -73,7 +75,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
)
// NOTE: the "filters" parameter is extracted separately for backwards
- // compat via `fitlerFromRequest()`.
+ // compat via `filterFromRequest()`.
query := struct {
Since string `schema:"since"`
Until string `schema:"until"`
@@ -95,7 +97,6 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
-
eventChannel := make(chan *events.Event)
errorChannel := make(chan error)
@@ -110,6 +111,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
Until: query.Until,
}
errorChannel <- runtime.Events(r.Context(), readOpts)
+
}()
var flush = func() {}
@@ -130,8 +132,8 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
if err != nil {
// FIXME StatusOK already sent above cannot send 500 here
utils.InternalServerError(w, err)
- return
}
+ return
case evt := <-eventChannel:
if evt == nil {
continue
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index a51dd8ed3..9d7503aba 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -22,6 +22,7 @@ import (
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// mergeNameAndTagOrDigest creates an image reference as string from the
@@ -98,21 +99,23 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
if err != nil {
utils.InternalServerError(w, err)
return
}
- for _, p := range pruneCids {
+ reclaimedSpace := uint64(0)
+ for _, p := range imagePruneReports {
idr = append(idr, types.ImageDeleteResponseItem{
- Deleted: p,
+ Deleted: p.Id,
})
+ reclaimedSpace = reclaimedSpace + p.Size
}
// FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
- SpaceReclaimed: 1, // TODO we cannot supply this right now
+ SpaceReclaimed: reclaimedSpace,
}
utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr})
}
@@ -386,6 +389,12 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
return
}
+ defer func() {
+ err := os.Remove(f.Name())
+ if err != nil {
+ logrus.Errorf("Failed to remove temporary file: %v.", err)
+ }
+ }()
if err := SaveFromBody(f, r); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
return
diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go
index b3ceae3ee..6808cdad5 100644
--- a/pkg/api/handlers/compat/images_search.go
+++ b/pkg/api/handlers/compat/images_search.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
+ "github.com/docker/docker/api/types/registry"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -77,5 +78,18 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
utils.BadRequest(w, "term", query.Term, err)
return
}
- utils.WriteResponse(w, http.StatusOK, results)
+
+ compatResults := make([]registry.SearchResult, 0, len(results))
+ for _, result := range results {
+ compatResult := registry.SearchResult{
+ Name: result.Name,
+ Description: result.Description,
+ StarCount: result.Stars,
+ IsAutomated: result.Automated == "[OK]",
+ IsOfficial: result.Official == "[OK]",
+ }
+ compatResults = append(compatResults, compatResult)
+ }
+
+ utils.WriteResponse(w, http.StatusOK, compatResults)
}
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index 4b3a390f1..5adbeb031 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -48,7 +48,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
stateInfo := getContainersState(runtime)
sysInfo := sysinfo.New(true)
- // FIXME: Need to expose if runtime supports Checkpoint'ing
+ // FIXME: Need to expose if runtime supports Checkpointing
// liveRestoreEnabled := criu.CheckForCriu() && configInfo.RuntimeSupportsCheckpoint()
info := &handlers.Info{Info: docker.Info{
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index fe13971b0..f0b922885 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -131,7 +131,7 @@ func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filt
Name: conf.Name,
ID: network.GetNetworkID(conf.Name),
Created: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), // nolint: unconvert
- Scope: "",
+ Scope: "local",
Driver: network.DefaultNetworkDriver,
EnableIPv6: false,
IPAM: dockerNetwork.IPAM{
@@ -197,7 +197,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
}
var reports []*types.NetworkResource
- logrus.Errorf("netNames: %q", strings.Join(netNames, ", "))
+ logrus.Debugf("netNames: %q", strings.Join(netNames, ", "))
for _, name := range netNames {
report, err := getNetworkResourceByNameOrID(name, runtime, query.Filters)
if err != nil {
@@ -239,7 +239,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
Internal: networkCreate.Internal,
Labels: networkCreate.Labels,
}
- if networkCreate.IPAM != nil && networkCreate.IPAM.Config != nil {
+ if networkCreate.IPAM != nil && len(networkCreate.IPAM.Config) > 0 {
if len(networkCreate.IPAM.Config) > 1 {
utils.InternalServerError(w, errors.New("compat network create can only support one IPAM config"))
return
diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go
index bdc051d73..cc8c6ef0a 100644
--- a/pkg/api/handlers/compat/resize.go
+++ b/pkg/api/handlers/compat/resize.go
@@ -20,8 +20,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
// /containers/{id}/resize
query := struct {
- height uint16 `schema:"h"`
- width uint16 `schema:"w"`
+ Height uint16 `schema:"h"`
+ Width uint16 `schema:"w"`
}{
// override any golang type defaults
}
@@ -33,8 +33,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
}
sz := remotecommand.TerminalSize{
- Width: query.width,
- Height: query.height,
+ Width: query.Width,
+ Height: query.Height,
}
var status int
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index 71b848932..1188d8f84 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -3,6 +3,7 @@ package compat
import (
"encoding/json"
"net/http"
+ "net/url"
"time"
"github.com/containers/podman/v2/libpod"
@@ -207,7 +208,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
* using the volume at the same time".
*
* With this in mind, we only consider the `force` query parameter when we
- * hunt for specified volume by name, using it to seletively return a 204
+ * hunt for specified volume by name, using it to selectively return a 204
* or blow up depending on `force` being truthy or falsey/unset
* respectively.
*/
@@ -230,7 +231,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
utils.VolumeNotFound(w, name, err)
} else {
// Volume does not exist and `force` is truthy - this emulates what
- // Docker would do when told to `force` removal of a nonextant
+ // Docker would do when told to `force` removal of a nonexistent
// volume
utils.WriteResponse(w, http.StatusNoContent, nil)
}
@@ -254,22 +255,23 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- // TODO: We have no ability to pass pruning filters to `PruneVolumes()` so
- // we'll explicitly reject the request if we see any
- if len(query.Filters) > 0 {
- utils.InternalServerError(w, errors.New("filters for pruning volumes is not implemented"))
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
+ if err != nil {
+ utils.Error(w, "Something when wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters for %s", f.Encode()))
return
}
- pruned, err := runtime.PruneVolumes(r.Context())
+ pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return
}
prunedIds := make([]string, 0, len(pruned))
- for k := range pruned {
+ for _, v := range pruned {
// XXX: This drops any pruning per-volume error messages on the floor
- prunedIds = append(prunedIds, k)
+ prunedIds = append(prunedIds, v.Id)
}
pruneResponse := docker_api_types.VolumesPruneReport{
VolumesDeleted: prunedIds,
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 6145207ca..979a8adc4 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -51,7 +51,7 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
return
}
if !report.Value {
- utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(nil, "failed to find image %s", name))
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Errorf("failed to find image %s", name))
return
}
utils.WriteResponse(w, http.StatusNoContent, "")
@@ -156,12 +156,12 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
}
}
- cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- utils.WriteResponse(w, http.StatusOK, cids)
+ utils.WriteResponse(w, http.StatusOK, imagePruneReports)
}
func ExportImage(w http.ResponseWriter, r *http.Request) {
@@ -265,8 +265,14 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
// Format is mandatory! Currently, we only support multi-image docker
// archives.
+ if len(query.References) > 1 && query.Format != define.V2s2Archive {
+ utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("multi-image archives must use format of %s", define.V2s2Archive))
+ return
+
+ }
+
switch query.Format {
- case define.V2s2Archive:
+ case define.V2s2Archive, define.OCIArchive:
tmpfile, err := ioutil.TempFile("", "api.tar")
if err != nil {
utils.Error(w, "unable to create tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
@@ -277,6 +283,13 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unable to close tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
+ case define.OCIManifestDir, define.V2s2ManifestDir:
+ tmpdir, err := ioutil.TempDir("", "save")
+ if err != nil {
+ utils.Error(w, "unable to create tmpdir", http.StatusInternalServerError, errors.Wrap(err, "unable to create tmpdir"))
+ return
+ }
+ output = tmpdir
default:
utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format))
return
@@ -287,7 +300,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
opts := entities.ImageSaveOptions{
Compress: query.Compress,
Format: query.Format,
- MultiImageArchive: true,
+ MultiImageArchive: len(query.References) > 1,
Output: output,
RemoveSignatures: true,
}
@@ -414,7 +427,6 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
}{
// This is where you can override the golang default value for one of fields
}
-
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
@@ -607,12 +619,12 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
func SearchImages(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Term string `json:"term"`
- Limit int `json:"limit"`
- NoTrunc bool `json:"noTrunc"`
- Filters []string `json:"filters"`
- TLSVerify bool `json:"tlsVerify"`
- ListTags bool `json:"listTags"`
+ Term string `json:"term"`
+ Limit int `json:"limit"`
+ NoTrunc bool `json:"noTrunc"`
+ Filters map[string][]string `json:"filters"`
+ TLSVerify bool `json:"tlsVerify"`
+ ListTags bool `json:"listTags"`
}{
// This is where you can override the golang default value for one of fields
}
@@ -622,24 +634,44 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
return
}
+ filter := image.SearchFilter{}
+ if len(query.Filters) > 0 {
+ if len(query.Filters["stars"]) > 0 {
+ stars, err := strconv.Atoi(query.Filters["stars"][0])
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filter.Stars = stars
+ }
+ if len(query.Filters["is-official"]) > 0 {
+ isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0])
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filter.IsOfficial = types.NewOptionalBool(isOfficial)
+ }
+ if len(query.Filters["is-automated"]) > 0 {
+ isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0])
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filter.IsAutomated = types.NewOptionalBool(isAutomated)
+ }
+ }
options := image.SearchOptions{
Limit: query.Limit,
NoTrunc: query.NoTrunc,
ListTags: query.ListTags,
+ Filter: filter,
}
+
if _, found := r.URL.Query()["tlsVerify"]; found {
options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
- if _, found := r.URL.Query()["filters"]; found {
- filter, err := image.ParseSearchFilter(query.Filters)
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters parameter for %s", r.URL.String()))
- return
- }
- options.Filter = *filter
- }
-
_, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
@@ -678,10 +710,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
All bool `schema:"all"`
Force bool `schema:"force"`
Images []string `schema:"images"`
- }{
- All: false,
- Force: false,
- }
+ }{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
@@ -690,10 +719,8 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
}
opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force}
-
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
-
strErrs := errorhandling.ErrorsToStrings(rmErrors)
report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs}
utils.WriteResponse(w, http.StatusOK, report)
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 5e2727e95..bacba006d 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -115,10 +115,10 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
}
}
- writer := channel.NewWriter(make(chan []byte, 1))
+ writer := channel.NewWriter(make(chan []byte))
defer writer.Close()
- stderr := channel.NewWriter(make(chan []byte, 1))
+ stderr := channel.NewWriter(make(chan []byte))
defer stderr.Close()
images := make([]string, 0, len(imagesToPull))
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
index b157dfc7b..130e563ae 100644
--- a/pkg/api/handlers/libpod/system.go
+++ b/pkg/api/handlers/libpod/system.go
@@ -38,35 +38,28 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
systemPruneReport.PodPruneReport = podPruneReport
// We could parallelize this, should we?
- containerPruneReport, err := compat.PruneContainersHelper(w, r, nil)
+ containerPruneReports, err := compat.PruneContainersHelper(w, r, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.ContainerPruneReport = containerPruneReport
+ systemPruneReport.ContainerPruneReports = containerPruneReports
- results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
-
- systemPruneReport.ImagePruneReport = &report
+ systemPruneReport.ImagePruneReports = imagePruneReports
if query.Volumes {
- volumePruneReport, err := pruneVolumesHelper(r)
+ volumePruneReports, err := pruneVolumesHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.VolumePruneReport = volumePruneReport
+ systemPruneReport.VolumePruneReports = volumePruneReports
}
utils.WriteResponse(w, http.StatusOK, systemPruneReport)
}
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index b0d40fd8b..6f9537515 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -3,11 +3,13 @@ package libpod
import (
"encoding/json"
"net/http"
+ "net/url"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/gorilla/schema"
@@ -177,20 +179,30 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, reports)
}
-func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
+func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
+ decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- pruned, err := runtime.PruneVolumes(r.Context())
+ query := struct {
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // override any golang type defaults
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ return nil, err
+ }
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
+
+ reports, err := runtime.PruneVolumes(r.Context(), filterFuncs)
+ if err != nil {
+ return nil, err
}
return reports, nil
}
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
index 7506dbfd1..0fe3a308b 100644
--- a/pkg/api/handlers/utils/pods.go
+++ b/pkg/api/handlers/utils/pods.go
@@ -4,8 +4,8 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/gorilla/schema"
)
@@ -31,7 +31,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
filters := make([]libpod.PodFilter, 0, len(query.Filters))
for k, v := range query.Filters {
- f, err := lpfilters.GeneratePodFilterFunc(k, v)
+ f, err := dfilters.GeneratePodFilterFunc(k, v)
if err != nil {
return nil, err
}
diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go
index b2d2543c4..b20d89cc2 100644
--- a/pkg/api/server/register_archive.go
+++ b/pkg/api/server/register_archive.go
@@ -4,11 +4,10 @@ import (
"net/http"
"github.com/containers/podman/v2/pkg/api/handlers/compat"
- "github.com/containers/podman/v2/pkg/api/handlers/libpod"
"github.com/gorilla/mux"
)
-func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
+func (s *APIServer) registerArchiveHandlers(r *mux.Router) error {
// swagger:operation PUT /containers/{name}/archive compat putArchive
// ---
// summary: Put files into a container
@@ -92,7 +91,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
Libpod
*/
- // swagger:operation POST /libpod/containers/{name}/copy libpod libpodPutArchive
+ // swagger:operation POST /libpod/containers/{name}/archive libpod libpodPutArchive
// ---
// summary: Copy files into a container
// description: Copy a tar archive of files into a container
@@ -133,7 +132,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
- // swagger:operation GET /libpod/containers/{name}/copy libpod libpodGetArchive
+ // swagger:operation GET /libpod/containers/{name}/archive libpod libpodGetArchive
// ---
// summary: Copy files from a container
// description: Copy a tar archive of files from a container
@@ -164,8 +163,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
// $ref: "#/responses/NoSuchContainer"
// 500:
// $ref: "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name}/copy"), s.APIHandler(libpod.Archive)).Methods(http.MethodGet, http.MethodPost)
- r.HandleFunc(VersionedPath("/libpod/containers/{name}/archive"), s.APIHandler(libpod.Archive)).Methods(http.MethodGet, http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/archive"), s.APIHandler(compat.Archive)).Methods(http.MethodGet, http.MethodPut, http.MethodHead)
return nil
}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 870c6a90c..b80dea545 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -690,6 +690,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// - `label`=(`key` or `"key=value"`) of an container label
// - `name=<name>` a container's name
// - `network`=(`<network id>` or `<network name>`)
+ // - `pod`=(`<pod id>` or `<pod name>`)
// - `publish`=(`<port>[/<proto>]` or `<startport-endport>/[<proto>]`)
// - `since`=(`<container id>` or `<container name>`)
// - `status`=(`created`, `restarting`, `running`, `removing`, `paused`, `exited` or `dead`)
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index c2423218a..7e6de8783 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -666,7 +666,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - in: query
// name: destination
// type: string
- // description: Allows for pushing the image to a different destintation than the image refers to.
+ // description: Allows for pushing the image to a different destination than the image refers to.
// - in: query
// name: tlsVerify
// description: Require TLS verification.
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 09b6079e4..046f6561c 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -108,7 +108,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
for _, fn := range []func(*mux.Router) error{
server.registerAuthHandlers,
- server.registerAchiveHandlers,
+ server.registerArchiveHandlers,
server.registerContainersHandlers,
server.registerDistributionHandlers,
server.registerEventsHandlers,
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index 6d349bb7d..45253e01a 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -4,6 +4,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
// No such image
@@ -170,7 +171,7 @@ type ok struct {
// swagger:response VolumePruneResponse
type swagVolumePruneResponse struct {
// in:body
- Body []entities.VolumePruneReport
+ Body []reports.PruneReport
}
// Volume create response
diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go
index 44709f291..77851f534 100644
--- a/pkg/autoupdate/autoupdate.go
+++ b/pkg/autoupdate/autoupdate.go
@@ -44,7 +44,7 @@ var supportedPolicies = map[string]Policy{
"image": PolicyNewImage,
}
-// LookupPolicy looksup the corresponding Policy for the specified
+// LookupPolicy looks up the corresponding Policy for the specified
// string. If none is found, an errors is returned including the list of
// supported policies.
//
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index f2cb3147c..7b26037eb 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -182,30 +182,65 @@ func pingNewConnection(ctx context.Context) error {
func sshClient(_url *url.URL, secure bool, passPhrase string, identity string) (Connection, error) {
// if you modify the authmethods or their conditionals, you will also need to make similar
// changes in the client (currently cmd/podman/system/connection/add getUDS).
- authMethods := []ssh.AuthMethod{}
+
+ var signers []ssh.Signer // order Signers are appended to this list determines which key is presented to server
+
if len(identity) > 0 {
- auth, err := terminal.PublicKey(identity, []byte(passPhrase))
+ s, err := terminal.PublicKey(identity, []byte(passPhrase))
if err != nil {
return Connection{}, errors.Wrapf(err, "failed to parse identity %q", identity)
}
- logrus.Debugf("public key signer enabled for identity %q", identity)
- authMethods = append(authMethods, auth)
+
+ signers = append(signers, s)
+ logrus.Debugf("SSH Ident Key %q %s %s", identity, ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
}
if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
- logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock)
+ logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer(s) enabled", sock)
c, err := net.Dial("unix", sock)
if err != nil {
return Connection{}, err
}
- a := agent.NewClient(c)
- authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers))
+
+ agentSigners, err := agent.NewClient(c).Signers()
+ if err != nil {
+ return Connection{}, err
+ }
+ signers = append(signers, agentSigners...)
+
+ if logrus.IsLevelEnabled(logrus.DebugLevel) {
+ for _, s := range agentSigners {
+ logrus.Debugf("SSH Agent Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ }
+ }
+
+ var authMethods []ssh.AuthMethod
+ if len(signers) > 0 {
+ var dedup = make(map[string]ssh.Signer)
+ // Dedup signers based on fingerprint, ssh-agent keys override CONTAINER_SSHKEY
+ for _, s := range signers {
+ fp := ssh.FingerprintSHA256(s.PublicKey())
+ if _, found := dedup[fp]; found {
+ logrus.Debugf("Dedup SSH Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ dedup[fp] = s
+ }
+
+ var uniq []ssh.Signer
+ for _, s := range dedup {
+ uniq = append(uniq, s)
+ }
+ authMethods = append(authMethods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
+ return uniq, nil
+ }))
}
if pw, found := _url.User.Password(); found {
authMethods = append(authMethods, ssh.Password(pw))
}
+
if len(authMethods) == 0 {
callback := func() (string, error) {
pass, err := terminal.ReadPassword("Login password:")
diff --git a/pkg/bindings/containers/archive.go b/pkg/bindings/containers/archive.go
new file mode 100644
index 000000000..d1bbc0b95
--- /dev/null
+++ b/pkg/bindings/containers/archive.go
@@ -0,0 +1,92 @@
+package containers
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "net/url"
+
+ "github.com/containers/podman/v2/pkg/bindings"
+ "github.com/containers/podman/v2/pkg/copy"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
+)
+
+// Stat checks if the specified path is on the container. Note that the stat
+// report may be set even in case of an error. This happens when the path
+// resolves to symlink pointing to a non-existent path.
+func Stat(ctx context.Context, nameOrID string, path string) (*entities.ContainerStatReport, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ response, err := conn.DoRequest(nil, http.MethodHead, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ var finalErr error
+ if response.StatusCode == http.StatusNotFound {
+ finalErr = copy.ENOENT
+ } else if response.StatusCode != http.StatusOK {
+ finalErr = errors.New(response.Status)
+ }
+
+ var statReport *entities.ContainerStatReport
+
+ fileInfo, err := copy.ExtractFileInfoFromHeader(&response.Header)
+ if err != nil && finalErr == nil {
+ return nil, err
+ }
+
+ if fileInfo != nil {
+ statReport = &entities.ContainerStatReport{FileInfo: *fileInfo}
+ }
+
+ return statReport, finalErr
+}
+
+func CopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ return func() error {
+ response, err := conn.DoRequest(reader, http.MethodPut, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return err
+ }
+ if response.StatusCode != http.StatusOK {
+ return errors.New(response.Status)
+ }
+ return response.Process(nil)
+ }, nil
+}
+
+func CopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+ if response.StatusCode != http.StatusOK {
+ return nil, response.Process(nil)
+ }
+
+ return func() error {
+ _, err := io.Copy(writer, response.Body)
+ return err
+ }, nil
+}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 91b155fc4..69ae7a32f 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -26,7 +26,10 @@ import (
)
// Attach attaches to a running container
-func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
+func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool, options *AttachOptions) error {
+ if options == nil {
+ options = new(AttachOptions)
+ }
isSet := struct {
stdin bool
stdout bool
@@ -55,27 +58,24 @@ func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stre
}
// Do we need to wire in stdin?
- ctnr, err := Inspect(ctx, nameOrID, bindings.PFalse)
+ ctnr, err := Inspect(ctx, nameOrID, new(InspectOptions).WithSize(false))
if err != nil {
return err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
detachKeysInBytes := []byte{}
- if detachKeys != nil {
- params.Add("detachKeys", *detachKeys)
+ if options.Changed("DetachKeys") {
+ params.Add("detachKeys", options.GetDetachKeys())
- detachKeysInBytes, err = term.ToBytes(*detachKeys)
+ detachKeysInBytes, err = term.ToBytes(options.GetDetachKeys())
if err != nil {
return errors.Wrapf(err, "invalid detach keys")
}
}
- if logs != nil {
- params.Add("logs", fmt.Sprintf("%t", *logs))
- }
- if stream != nil {
- params.Add("stream", fmt.Sprintf("%t", *stream))
- }
if isSet.stdin {
params.Add("stdin", "true")
}
@@ -278,13 +278,19 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error
}
// ResizeContainerTTY sets container's TTY height and width in characters
-func ResizeContainerTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("containers", nameOrID, "resize"), height, width)
+func ResizeContainerTTY(ctx context.Context, nameOrID string, options *ResizeTTYOptions) error {
+ if options == nil {
+ options = new(ResizeTTYOptions)
+ }
+ return resizeTTY(ctx, bindings.JoinURL("containers", nameOrID, "resize"), options.Height, options.Width)
}
// ResizeExecTTY sets session's TTY height and width in characters
-func ResizeExecTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("exec", nameOrID, "resize"), height, width)
+func ResizeExecTTY(ctx context.Context, nameOrID string, options *ResizeExecTTYOptions) error {
+ if options == nil {
+ options = new(ResizeExecTTYOptions)
+ }
+ return resizeTTY(ctx, bindings.JoinURL("exec", nameOrID, "resize"), options.Height, options.Width)
}
// resizeTTY set size of TTY of container
@@ -337,9 +343,9 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i
var resizeErr error
if isExec {
- resizeErr = ResizeExecTTY(ctx, id, &h, &w)
+ resizeErr = ResizeExecTTY(ctx, id, new(ResizeExecTTYOptions).WithHeight(h).WithWidth(w))
} else {
- resizeErr = ResizeContainerTTY(ctx, id, &h, &w)
+ resizeErr = ResizeContainerTTY(ctx, id, new(ResizeTTYOptions).WithHeight(h).WithWidth(w))
}
if resizeErr != nil {
logrus.Warnf("failed to resize TTY: %v", err)
@@ -361,7 +367,10 @@ func setRawTerminal(file *os.File) (*terminal.State, error) {
}
// ExecStartAndAttach starts and attaches to a given exec session.
-func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.AttachStreams) error {
+func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStartAndAttachOptions) error {
+ if options == nil {
+ options = new(ExecStartAndAttachOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -450,10 +459,10 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
go attachHandleResize(ctx, winCtx, winChange, true, sessionID, terminalFile)
}
- if streams.AttachInput {
+ if options.GetAttachInput() {
go func() {
logrus.Debugf("Copying STDIN to socket")
- _, err := utils.CopyDetachable(socket, streams.InputStream, []byte{})
+ _, err := utils.CopyDetachable(socket, options.InputStream, []byte{})
if err != nil {
logrus.Error("failed to write input to service: " + err.Error())
}
@@ -463,11 +472,11 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
buffer := make([]byte, 1024)
if isTerm {
logrus.Debugf("Handling terminal attach to exec")
- if !streams.AttachOutput {
+ if !options.GetAttachOutput() {
return fmt.Errorf("exec session %s has a terminal and must have STDOUT enabled", sessionID)
}
// If not multiplex'ed, read from server and write to stdout
- _, err := utils.CopyDetachable(streams.OutputStream, socket, []byte{})
+ _, err := utils.CopyDetachable(options.GetOutputStream(), socket, []byte{})
if err != nil {
return err
}
@@ -489,22 +498,22 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
switch {
case fd == 0:
- if streams.AttachInput {
+ if options.GetAttachInput() {
// Write STDIN to STDOUT (echoing characters
// typed by another attach session)
- if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
+ if _, err := options.GetOutputStream().Write(frame[0:l]); err != nil {
return err
}
}
case fd == 1:
- if streams.AttachOutput {
- if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
+ if options.GetAttachOutput() {
+ if _, err := options.GetOutputStream().Write(frame[0:l]); err != nil {
return err
}
}
case fd == 2:
- if streams.AttachError {
- if _, err := streams.ErrorStream.Write(frame[0:l]); err != nil {
+ if options.GetAttachError() {
+ if _, err := options.GetErrorStream().Write(frame[0:l]); err != nil {
return err
}
}
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index f466f8a34..c250558a6 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -3,8 +3,6 @@ package containers
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -12,27 +10,18 @@ import (
// Checkpoint checkpoints the given container (identified by nameOrID). All additional
// options are options and allow for more fine grained control of the checkpoint process.
-func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEstablished, ignoreRootFS *bool, export *string) (*entities.CheckpointReport, error) {
+func Checkpoint(ctx context.Context, nameOrID string, options *CheckpointOptions) (*entities.CheckpointReport, error) {
var report entities.CheckpointReport
+ if options == nil {
+ options = new(CheckpointOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if keep != nil {
- params.Set("keep", strconv.FormatBool(*keep))
- }
- if leaveRunning != nil {
- params.Set("leaveRunning", strconv.FormatBool(*leaveRunning))
- }
- if tcpEstablished != nil {
- params.Set("TCPestablished", strconv.FormatBool(*tcpEstablished))
- }
- if ignoreRootFS != nil {
- params.Set("ignoreRootFS", strconv.FormatBool(*ignoreRootFS))
- }
- if export != nil {
- params.Set("export", *export)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
if err != nil {
@@ -43,33 +32,23 @@ func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEst
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
// additional options are optional and allow finer control of the restore process.
-func Restore(ctx context.Context, nameOrID string, keep, tcpEstablished, ignoreRootFS, ignoreStaticIP, ignoreStaticMAC *bool, name, importArchive *string) (*entities.RestoreReport, error) {
+func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*entities.RestoreReport, error) {
var report entities.RestoreReport
+ if options == nil {
+ options = new(RestoreOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if keep != nil {
- params.Set("keep", strconv.FormatBool(*keep))
- }
- if tcpEstablished != nil {
- params.Set("TCPestablished", strconv.FormatBool(*tcpEstablished))
- }
- if ignoreRootFS != nil {
- params.Set("ignoreRootFS", strconv.FormatBool(*ignoreRootFS))
- }
- if ignoreStaticIP != nil {
- params.Set("ignoreStaticIP", strconv.FormatBool(*ignoreStaticIP))
- }
- if ignoreStaticMAC != nil {
- params.Set("ignoreStaticMAC", strconv.FormatBool(*ignoreStaticMAC))
- }
- if name != nil {
- params.Set("name", *name)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
- if importArchive != nil {
- params.Set("import", *importArchive)
+ // The import key is a reserved golang term
+ params.Del("ImportArchive")
+ if i := options.GetImportAchive(); options.Changed("ImportArchive") {
+ params.Set("import", i)
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
if err != nil {
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
index 9ab4456a3..6205c75bd 100644
--- a/pkg/bindings/containers/commit.go
+++ b/pkg/bindings/containers/commit.go
@@ -3,8 +3,6 @@ package containers
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
@@ -12,35 +10,20 @@ import (
// Commit creates a container image from a container. The container is defined by nameOrID. Use
// the CommitOptions for finer grain control on characteristics of the resulting image.
-func Commit(ctx context.Context, nameOrID string, options CommitOptions) (handlers.IDResponse, error) {
+func Commit(ctx context.Context, nameOrID string, options *CommitOptions) (handlers.IDResponse, error) {
+ if options == nil {
+ options = new(CommitOptions)
+ }
id := handlers.IDResponse{}
conn, err := bindings.GetClient(ctx)
if err != nil {
return id, err
}
- params := url.Values{}
- params.Set("container", nameOrID)
- if options.Author != nil {
- params.Set("author", *options.Author)
- }
- for _, change := range options.Changes {
- params.Set("changes", change)
- }
- if options.Comment != nil {
- params.Set("comment", *options.Comment)
- }
- if options.Format != nil {
- params.Set("format", *options.Format)
- }
- if options.Pause != nil {
- params.Set("pause", strconv.FormatBool(*options.Pause))
- }
- if options.Repo != nil {
- params.Set("repo", *options.Repo)
- }
- if options.Tag != nil {
- params.Set("tag", *options.Tag)
+ params, err := options.ToParams()
+ if err != nil {
+ return handlers.IDResponse{}, err
}
+ params.Set("container", nameOrID)
response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params, nil)
if err != nil {
return id, err
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 4331ae6c2..1081a0e61 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -25,34 +26,18 @@ var (
// the most recent number of containers. The pod and size booleans indicate that pod information and rootfs
// size information should also be included. Finally, the sync bool synchronizes the OCI runtime and
// container state.
-func List(ctx context.Context, filters map[string][]string, all *bool, last *int, namespace, size, sync *bool) ([]entities.ListContainer, error) { // nolint:typecheck
+func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer, error) { // nolint:typecheck
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
var containers []entities.ListContainer
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if last != nil {
- params.Set("limit", strconv.Itoa(*last))
- }
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
- }
- if sync != nil {
- params.Set("sync", strconv.FormatBool(*sync))
- }
- if namespace != nil {
- params.Set("namespace", strconv.FormatBool(*namespace))
- }
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params, nil)
if err != nil {
@@ -65,19 +50,18 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int
// used for more granular selection of containers. The main error returned indicates if there were runtime
// errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse
// structure.
-func Prune(ctx context.Context, filters map[string][]string) (*entities.ContainerPruneReport, error) {
- var reports *entities.ContainerPruneReport
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
+ if options == nil {
+ options = new(PruneOptions)
+ }
+ var reports []*reports.PruneReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params, nil)
if err != nil {
@@ -89,17 +73,20 @@ func Prune(ctx context.Context, filters map[string][]string) (*entities.Containe
// Remove removes a container from local storage. The force bool designates
// that the container should be removed forcibly (example, even it is running). The volumes
// bool dictates that a container's volumes should also be removed.
-func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error {
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ if v := options.GetVolumes(); options.Changed("Volumes") {
+ params.Set("v", strconv.FormatBool(v))
}
- if volumes != nil {
- params.Set("v", strconv.FormatBool(*volumes))
+ if force := options.GetForce(); options.Changed("Force") {
+ params.Set("force", strconv.FormatBool(force))
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
if err != nil {
@@ -112,14 +99,17 @@ func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
// or a partial/full ID. The size bool determines whether the size of the container's root filesystem
// should be calculated. Calculating the size of a container requires extra work from the filesystem and
// is therefore slower.
-func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectContainerData, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*define.InspectContainerData, error) {
+ if options == nil {
+ options = new(InspectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nil, nameOrID)
if err != nil {
@@ -132,12 +122,18 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectC
// Kill sends a given signal to a given container. The signal should be the string
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
// or a partial/full ID
-func Kill(ctx context.Context, nameOrID string, sig string) error {
+func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions) error {
+ if options == nil {
+ options = new(KillOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
params.Set("signal", sig)
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
if err != nil {
@@ -149,7 +145,11 @@ func Kill(ctx context.Context, nameOrID string, sig string) error {
// Pause pauses a given container. The nameOrID can be a container name
// or a partial/full ID.
-func Pause(ctx context.Context, nameOrID string) error {
+func Pause(ctx context.Context, nameOrID string, options *PauseOptions) error {
+ if options == nil {
+ options = new(PauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -164,14 +164,17 @@ func Pause(ctx context.Context, nameOrID string) error {
// Restart restarts a running container. The nameOrID can be a container name
// or a partial/full ID. The optional timeout specifies the number of seconds to wait
// for the running container to stop before killing it.
-func Restart(ctx context.Context, nameOrID string, timeout *int) error {
+func Restart(ctx context.Context, nameOrID string, options *RestartOptions) error {
+ if options == nil {
+ options = new(RestartOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
params := url.Values{}
- if timeout != nil {
- params.Set("t", strconv.Itoa(*timeout))
+ if options.Changed("Timeout") {
+ params.Set("t", strconv.Itoa(options.GetTimeout()))
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
if err != nil {
@@ -183,15 +186,18 @@ func Restart(ctx context.Context, nameOrID string, timeout *int) error {
// Start starts a non-running container.The nameOrID can be a container name
// or a partial/full ID. The optional parameter for detach keys are to override the default
// detach key sequence.
-func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
+func Start(ctx context.Context, nameOrID string, options *StartOptions) error {
+ if options == nil {
+ options = new(StartOptions)
+ }
logrus.Infof("Going to start container %q", nameOrID)
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if detachKeys != nil {
- params.Set("detachKeys", *detachKeys)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nil, nameOrID)
if err != nil {
@@ -200,14 +206,18 @@ func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
return response.Process(nil)
}
-func Stats(ctx context.Context, containers []string, stream *bool) (chan entities.ContainerStatsReport, error) {
+func Stats(ctx context.Context, containers []string, options *StatsOptions) (chan entities.ContainerStatsReport, error) {
+ if options == nil {
+ options = new(StatsOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if stream != nil {
- params.Set("stream", strconv.FormatBool(*stream))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
for _, c := range containers {
params.Add("containers", c)
@@ -225,8 +235,8 @@ func Stats(ctx context.Context, containers []string, stream *bool) (chan entitie
dec := json.NewDecoder(response.Body)
doStream := true
- if stream != nil {
- doStream = *stream
+ if options.Changed("Stream") {
+ doStream = options.GetStream()
}
streamLabel: // label to flatten the scope
@@ -253,16 +263,18 @@ func Stats(ctx context.Context, containers []string, stream *bool) (chan entitie
// Top gathers statistics about the running processes in a container. The nameOrID can be a container name
// or a partial/full ID. The descriptors allow for specifying which data to collect from the process.
-func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, error) {
+func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, error) {
+ if options == nil {
+ options = new(TopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
-
- if len(descriptors) > 0 {
- // flatten the slice into one string
- params.Set("ps_args", strings.Join(descriptors, ","))
+ if options.Changed("Descriptors") {
+ ps_args := strings.Join(options.GetDescriptors(), ",")
+ params.Add("ps_args", ps_args)
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nil, nameOrID)
if err != nil {
@@ -287,7 +299,11 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
// Unpause resumes the given paused container. The nameOrID can be a container name
// or a partial/full ID.
-func Unpause(ctx context.Context, nameOrID string) error {
+func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) error {
+ if options == nil {
+ options = new(UnpauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -302,15 +318,18 @@ func Unpause(ctx context.Context, nameOrID string) error {
// Wait blocks until the given container reaches a condition. If not provided, the condition will
// default to stopped. If the condition is stopped, an exit code for the container will be provided. The
// nameOrID can be a container name or a partial/full ID.
-func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatus) (int32, error) { // nolint
+func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, error) { // nolint
+ if options == nil {
+ options = new(WaitOptions)
+ }
var exitCode int32
conn, err := bindings.GetClient(ctx)
if err != nil {
return exitCode, err
}
params := url.Values{}
- if condition != nil {
- params.Set("condition", condition.String())
+ if options.Changed("Condition") {
+ params.Set("condition", options.GetCondition().String())
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
if err != nil {
@@ -338,14 +357,17 @@ func Exists(ctx context.Context, nameOrID string, external bool) (bool, error) {
// Stop stops a running container. The timeout is optional. The nameOrID can be a container name
// or a partial/full ID
-func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
- params := url.Values{}
- conn, err := bindings.GetClient(ctx)
+func Stop(ctx context.Context, nameOrID string, options *StopOptions) error {
+ if options == nil {
+ options = new(StopOptions)
+ }
+ params, err := options.ToParams()
if err != nil {
return err
}
- if timeout != nil {
- params.Set("t", strconv.Itoa(int(*timeout)))
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nil, nameOrID)
if err != nil {
@@ -356,7 +378,11 @@ func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
// Export creates a tarball of the given name or ID of a container. It
// requires an io.Writer be provided to write the tarball.
-func Export(ctx context.Context, nameOrID string, w io.Writer) error {
+func Export(ctx context.Context, nameOrID string, w io.Writer, options *ExportOptions) error {
+ if options == nil {
+ options = new(ExportOptions)
+ }
+ _ = options
params := url.Values{}
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -376,7 +402,11 @@ func Export(ctx context.Context, nameOrID string, w io.Writer) error {
// ContainerInit takes a created container and executes all of the
// preparations to run the container except it will not start
// or attach to the container
-func ContainerInit(ctx context.Context, nameOrID string) error {
+func ContainerInit(ctx context.Context, nameOrID string, options *InitOptions) error {
+ if options == nil {
+ options = new(InitOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -391,7 +421,11 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
return response.Process(nil)
}
-func ShouldRestart(ctx context.Context, nameOrID string) (bool, error) {
+func ShouldRestart(ctx context.Context, nameOrID string, options *ShouldRestartOptions) (bool, error) {
+ if options == nil {
+ options = new(ShouldRestartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go
index 5c29ec577..177cf2e9c 100644
--- a/pkg/bindings/containers/create.go
+++ b/pkg/bindings/containers/create.go
@@ -11,8 +11,12 @@ import (
jsoniter "github.com/json-iterator/go"
)
-func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator) (entities.ContainerCreateResponse, error) {
+func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator, options *CreateOptions) (entities.ContainerCreateResponse, error) {
var ccr entities.ContainerCreateResponse
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return ccr, err
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
index 1478bd940..015172360 100644
--- a/pkg/bindings/containers/diff.go
+++ b/pkg/bindings/containers/diff.go
@@ -9,7 +9,11 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) {
+ if options == nil {
+ options = new(DiffOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go
index e080077c8..98ca975a0 100644
--- a/pkg/bindings/containers/exec.go
+++ b/pkg/bindings/containers/exec.go
@@ -50,7 +50,11 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat
// ExecInspect inspects an existing exec session, returning detailed information
// about it.
-func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSession, error) {
+func ExecInspect(ctx context.Context, sessionID string, options *ExecInspectOptions) (*define.InspectExecSession, error) {
+ if options == nil {
+ options = new(ExecInspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -72,7 +76,11 @@ func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSess
}
// ExecStart starts (but does not attach to) a given exec session.
-func ExecStart(ctx context.Context, sessionID string) error {
+func ExecStart(ctx context.Context, sessionID string, options *ExecStartOptions) error {
+ if options == nil {
+ options = new(ExecStartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go
index 9de6ffbe0..44b27629b 100644
--- a/pkg/bindings/containers/healthcheck.go
+++ b/pkg/bindings/containers/healthcheck.go
@@ -10,7 +10,11 @@ import (
// RunHealthCheck executes the container's healthcheck and returns the health status of the
// container.
-func RunHealthCheck(ctx context.Context, nameOrID string) (*define.HealthCheckResults, error) {
+func RunHealthCheck(ctx context.Context, nameOrID string, options *HealthCheckOptions) (*define.HealthCheckResults, error) {
+ if options == nil {
+ options = new(HealthCheckOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index a73517bac..04307d880 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"net/http"
- "net/url"
"strconv"
"github.com/containers/podman/v2/pkg/bindings"
@@ -14,35 +13,20 @@ import (
// Logs obtains a container's logs given the options provided. The logs are then sent to the
// stdout|stderr channels as strings.
-func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, stderrChan chan string) error {
+func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan, stderrChan chan string) error {
+ if options == nil {
+ options = new(LogOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if opts.Follow != nil {
- params.Set("follow", strconv.FormatBool(*opts.Follow))
- }
- if opts.Since != nil {
- params.Set("since", *opts.Since)
- }
- if opts.Stderr != nil {
- params.Set("stderr", strconv.FormatBool(*opts.Stderr))
- }
- if opts.Stdout != nil {
- params.Set("stdout", strconv.FormatBool(*opts.Stdout))
- }
- if opts.Tail != nil {
- params.Set("tail", *opts.Tail)
- }
- if opts.Timestamps != nil {
- params.Set("timestamps", strconv.FormatBool(*opts.Timestamps))
- }
- if opts.Until != nil {
- params.Set("until", *opts.Until)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
// The API requires either stdout|stderr be used. If neither are specified, we specify stdout
- if opts.Stdout == nil && opts.Stderr == nil {
+ if options.Stdout == nil && options.Stderr == nil {
params.Set("stdout", strconv.FormatBool(true))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nil, nameOrID)
diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go
index 4c2e0c188..4fd9f89bc 100644
--- a/pkg/bindings/containers/mount.go
+++ b/pkg/bindings/containers/mount.go
@@ -9,7 +9,11 @@ import (
// Mount mounts an existing container to the filesystem. It returns the path
// of the mounted container in string format.
-func Mount(ctx context.Context, nameOrID string) (string, error) {
+func Mount(ctx context.Context, nameOrID string, options *MountOptions) (string, error) {
+ if options == nil {
+ options = new(MountOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -26,7 +30,11 @@ func Mount(ctx context.Context, nameOrID string) (string, error) {
// Unmount unmounts a container from the filesystem. The container must not be running
// or the unmount will fail.
-func Unmount(ctx context.Context, nameOrID string) error {
+func Unmount(ctx context.Context, nameOrID string, options *UnmountOptions) error {
+ if options == nil {
+ options = new(UnmountOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -39,7 +47,11 @@ func Unmount(ctx context.Context, nameOrID string) error {
}
// GetMountedContainerPaths returns a map of mounted containers and their mount locations.
-func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) {
+func GetMountedContainerPaths(ctx context.Context, options *MountedContainerPathsOptions) (map[string]string, error) {
+ if options == nil {
+ options = new(MountedContainerPathsOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index f288c2944..24402e982 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -1,5 +1,13 @@
package containers
+import (
+ "bufio"
+ "io"
+
+ "github.com/containers/podman/v2/libpod/define"
+)
+
+//go:generate go run ../generator/generator.go LogOptions
// LogOptions describe finer control of log content or
// how the content is formatted.
type LogOptions struct {
@@ -12,6 +20,7 @@ type LogOptions struct {
Until *string
}
+//go:generate go run ../generator/generator.go CommitOptions
// CommitOptions describe details about the resulting committed
// image as defined by repo and tag. None of these options
// are required.
@@ -24,3 +33,200 @@ type CommitOptions struct {
Repo *string
Tag *string
}
+
+//go:generate go run ../generator/generator.go AttachOptions
+// AttachOptions are optional options for attaching to containers
+type AttachOptions struct {
+ DetachKeys *string
+ Logs *bool
+ Stream *bool
+}
+
+//go:generate go run ../generator/generator.go CheckpointOptions
+// CheckpointOptions are optional options for checkpointing containers
+type CheckpointOptions struct {
+ Export *string
+ IgnoreRootfs *bool
+ Keep *bool
+ LeaveRunning *bool
+ TCPEstablished *bool
+}
+
+//go:generate go run ../generator/generator.go RestoreOptions
+// RestoreOptions are optional options for restoring containers
+type RestoreOptions struct {
+ IgnoreRootfs *bool
+ IgnoreStaticIP *bool
+ IgnoreStaticMAC *bool
+ ImportAchive *string
+ Keep *bool
+ Name *string
+ TCPEstablished *bool
+}
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating containers
+type CreateOptions struct{}
+
+//go:generate go run ../generator/generator.go DiffOptions
+// DiffOptions are optional options for creating containers
+type DiffOptions struct{}
+
+//go:generate go run ../generator/generator.go ExecInspectOptions
+// ExecInspectOptions are optional options for inspecting
+// exec sessions
+type ExecInspectOptions struct{}
+
+//go:generate go run ../generator/generator.go ExecStartOptions
+// ExecStartOptions are optional options for starting
+// exec sessions
+type ExecStartOptions struct{}
+
+//go:generate go run ../generator/generator.go HealthCheckOptions
+// HealthCheckOptions are optional options for checking
+// the health of a container
+type HealthCheckOptions struct{}
+
+//go:generate go run ../generator/generator.go MountOptions
+// MountOptions are optional options for mounting
+// containers
+type MountOptions struct{}
+
+//go:generate go run ../generator/generator.go UnmountOptions
+// UnmountOptions are optional options for unmounting
+// containers
+type UnmountOptions struct{}
+
+//go:generate go run ../generator/generator.go MountedContainerPathsOptions
+// MountedContainerPathsOptions are optional options for getting
+// container mount paths
+type MountedContainerPathsOptions struct{}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing containers
+type ListOptions struct {
+ All *bool
+ Filters map[string][]string
+ Last *int
+ Namespace *bool
+ Size *bool
+ Sync *bool
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning containers
+type PruneOptions struct {
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing containers
+type RemoveOptions struct {
+ Force *bool
+ Volumes *bool
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting containers
+type InspectOptions struct {
+ Size *bool
+}
+
+//go:generate go run ../generator/generator.go KillOptions
+// KillOptions are optional options for killing containers
+type KillOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PauseOptions
+// PauseOptions are optional options for pausing containers
+type PauseOptions struct{}
+
+//go:generate go run ../generator/generator.go RestartOptions
+// RestartOptions are optional options for restarting containers
+type RestartOptions struct {
+ Timeout *int
+}
+
+//go:generate go run ../generator/generator.go StartOptions
+// StartOptions are optional options for starting containers
+type StartOptions struct {
+ DetachKeys *string
+}
+
+//go:generate go run ../generator/generator.go StatsOptions
+// StatsOptions are optional options for getting stats on containers
+type StatsOptions struct {
+ Stream *bool
+}
+
+//go:generate go run ../generator/generator.go TopOptions
+// TopOptions are optional options for getting running
+// processes in containers
+type TopOptions struct {
+ Descriptors *[]string
+}
+
+//go:generate go run ../generator/generator.go UnpauseOptions
+// UnpauseOptions are optional options for unpausing containers
+type UnpauseOptions struct{}
+
+//go:generate go run ../generator/generator.go WaitOptions
+// WaitOptions are optional options for waiting on containers
+type WaitOptions struct {
+ Condition *define.ContainerStatus
+}
+
+//go:generate go run ../generator/generator.go StopOptions
+// StopOptions are optional options for stopping containers
+type StopOptions struct {
+ Timeout *uint
+}
+
+//go:generate go run ../generator/generator.go ExportOptions
+// ExportOptions are optional options for exporting containers
+type ExportOptions struct{}
+
+//go:generate go run ../generator/generator.go InitOptions
+// InitOptions are optional options for initing containers
+type InitOptions struct{}
+
+//go:generate go run ../generator/generator.go ShouldRestartOptions
+// ShouldRestartOptions
+type ShouldRestartOptions struct{}
+
+//go:generate go run ../generator/generator.go ResizeTTYOptions
+// ResizeTTYOptions are optional options for resizing
+// container TTYs
+type ResizeTTYOptions struct {
+ Height *int
+ Width *int
+}
+
+//go:generate go run ../generator/generator.go ResizeExecTTYOptions
+// ResizeExecTTYOptions are optional options for resizing
+// container ExecTTYs
+type ResizeExecTTYOptions struct {
+ Height *int
+ Width *int
+}
+
+//go:generate go run ../generator/generator.go ExecStartAndAttachOptions
+// ExecStartAndAttachOptions are optional options for resizing
+// container ExecTTYs
+type ExecStartAndAttachOptions struct {
+ // OutputStream will be attached to container's STDOUT
+ OutputStream *io.WriteCloser
+ // ErrorStream will be attached to container's STDERR
+ ErrorStream *io.WriteCloser
+ // InputStream will be attached to container's STDIN
+ InputStream *bufio.Reader
+ // AttachOutput is whether to attach to STDOUT
+ // If false, stdout will not be attached
+ AttachOutput *bool
+ // AttachError is whether to attach to STDERR
+ // If false, stdout will not be attached
+ AttachError *bool
+ // AttachInput is whether to attach to STDIN
+ // If false, stdout will not be attached
+ AttachInput *bool
+}
diff --git a/pkg/bindings/containers/types_attach_options.go b/pkg/bindings/containers/types_attach_options.go
new file mode 100644
index 000000000..4ffb8ab17
--- /dev/null
+++ b/pkg/bindings/containers/types_attach_options.go
@@ -0,0 +1,136 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.566804404 -0600 CST m=+0.000258831
+*/
+
+// Changed
+func (o *AttachOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *AttachOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDetachKeys
+func (o *AttachOptions) WithDetachKeys(value string) *AttachOptions {
+ v := &value
+ o.DetachKeys = v
+ return o
+}
+
+// GetDetachKeys
+func (o *AttachOptions) GetDetachKeys() string {
+ var detachKeys string
+ if o.DetachKeys == nil {
+ return detachKeys
+ }
+ return *o.DetachKeys
+}
+
+// WithLogs
+func (o *AttachOptions) WithLogs(value bool) *AttachOptions {
+ v := &value
+ o.Logs = v
+ return o
+}
+
+// GetLogs
+func (o *AttachOptions) GetLogs() bool {
+ var logs bool
+ if o.Logs == nil {
+ return logs
+ }
+ return *o.Logs
+}
+
+// WithStream
+func (o *AttachOptions) WithStream(value bool) *AttachOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *AttachOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go
new file mode 100644
index 000000000..d03dc8231
--- /dev/null
+++ b/pkg/bindings/containers/types_checkpoint_options.go
@@ -0,0 +1,168 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.714853285 -0600 CST m=+0.000319103
+*/
+
+// Changed
+func (o *CheckpointOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CheckpointOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithExport
+func (o *CheckpointOptions) WithExport(value string) *CheckpointOptions {
+ v := &value
+ o.Export = v
+ return o
+}
+
+// GetExport
+func (o *CheckpointOptions) GetExport() string {
+ var export string
+ if o.Export == nil {
+ return export
+ }
+ return *o.Export
+}
+
+// WithIgnoreRootfs
+func (o *CheckpointOptions) WithIgnoreRootfs(value bool) *CheckpointOptions {
+ v := &value
+ o.IgnoreRootfs = v
+ return o
+}
+
+// GetIgnoreRootfs
+func (o *CheckpointOptions) GetIgnoreRootfs() bool {
+ var ignoreRootfs bool
+ if o.IgnoreRootfs == nil {
+ return ignoreRootfs
+ }
+ return *o.IgnoreRootfs
+}
+
+// WithKeep
+func (o *CheckpointOptions) WithKeep(value bool) *CheckpointOptions {
+ v := &value
+ o.Keep = v
+ return o
+}
+
+// GetKeep
+func (o *CheckpointOptions) GetKeep() bool {
+ var keep bool
+ if o.Keep == nil {
+ return keep
+ }
+ return *o.Keep
+}
+
+// WithLeaveRunning
+func (o *CheckpointOptions) WithLeaveRunning(value bool) *CheckpointOptions {
+ v := &value
+ o.LeaveRunning = v
+ return o
+}
+
+// GetLeaveRunning
+func (o *CheckpointOptions) GetLeaveRunning() bool {
+ var leaveRunning bool
+ if o.LeaveRunning == nil {
+ return leaveRunning
+ }
+ return *o.LeaveRunning
+}
+
+// WithTCPEstablished
+func (o *CheckpointOptions) WithTCPEstablished(value bool) *CheckpointOptions {
+ v := &value
+ o.TCPEstablished = v
+ return o
+}
+
+// GetTCPEstablished
+func (o *CheckpointOptions) GetTCPEstablished() bool {
+ var tCPEstablished bool
+ if o.TCPEstablished == nil {
+ return tCPEstablished
+ }
+ return *o.TCPEstablished
+}
diff --git a/pkg/bindings/containers/types_commit_options.go b/pkg/bindings/containers/types_commit_options.go
new file mode 100644
index 000000000..a8b215141
--- /dev/null
+++ b/pkg/bindings/containers/types_commit_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.420656951 -0600 CST m=+0.000259662
+*/
+
+// Changed
+func (o *CommitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CommitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthor
+func (o *CommitOptions) WithAuthor(value string) *CommitOptions {
+ v := &value
+ o.Author = v
+ return o
+}
+
+// GetAuthor
+func (o *CommitOptions) GetAuthor() string {
+ var author string
+ if o.Author == nil {
+ return author
+ }
+ return *o.Author
+}
+
+// WithChanges
+func (o *CommitOptions) WithChanges(value []string) *CommitOptions {
+ v := value
+ o.Changes = v
+ return o
+}
+
+// GetChanges
+func (o *CommitOptions) GetChanges() []string {
+ var changes []string
+ if o.Changes == nil {
+ return changes
+ }
+ return o.Changes
+}
+
+// WithComment
+func (o *CommitOptions) WithComment(value string) *CommitOptions {
+ v := &value
+ o.Comment = v
+ return o
+}
+
+// GetComment
+func (o *CommitOptions) GetComment() string {
+ var comment string
+ if o.Comment == nil {
+ return comment
+ }
+ return *o.Comment
+}
+
+// WithFormat
+func (o *CommitOptions) WithFormat(value string) *CommitOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *CommitOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
+
+// WithPause
+func (o *CommitOptions) WithPause(value bool) *CommitOptions {
+ v := &value
+ o.Pause = v
+ return o
+}
+
+// GetPause
+func (o *CommitOptions) GetPause() bool {
+ var pause bool
+ if o.Pause == nil {
+ return pause
+ }
+ return *o.Pause
+}
+
+// WithRepo
+func (o *CommitOptions) WithRepo(value string) *CommitOptions {
+ v := &value
+ o.Repo = v
+ return o
+}
+
+// GetRepo
+func (o *CommitOptions) GetRepo() string {
+ var repo string
+ if o.Repo == nil {
+ return repo
+ }
+ return *o.Repo
+}
+
+// WithTag
+func (o *CommitOptions) WithTag(value string) *CommitOptions {
+ v := &value
+ o.Tag = v
+ return o
+}
+
+// GetTag
+func (o *CommitOptions) GetTag() string {
+ var tag string
+ if o.Tag == nil {
+ return tag
+ }
+ return *o.Tag
+}
diff --git a/pkg/bindings/containers/types_create_options.go b/pkg/bindings/containers/types_create_options.go
new file mode 100644
index 000000000..4dbce0203
--- /dev/null
+++ b/pkg/bindings/containers/types_create_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.011789618 -0600 CST m=+0.000259413
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_diff_options.go b/pkg/bindings/containers/types_diff_options.go
new file mode 100644
index 000000000..be3bbf554
--- /dev/null
+++ b/pkg/bindings/containers/types_diff_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.159128927 -0600 CST m=+0.000255635
+*/
+
+// Changed
+func (o *DiffOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiffOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execinspect_options.go b/pkg/bindings/containers/types_execinspect_options.go
new file mode 100644
index 000000000..3c4c870be
--- /dev/null
+++ b/pkg/bindings/containers/types_execinspect_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.303239014 -0600 CST m=+0.000256861
+*/
+
+// Changed
+func (o *ExecInspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecInspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execstart_options.go b/pkg/bindings/containers/types_execstart_options.go
new file mode 100644
index 000000000..66fdc82cb
--- /dev/null
+++ b/pkg/bindings/containers/types_execstart_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.447714428 -0600 CST m=+0.000257278
+*/
+
+// Changed
+func (o *ExecStartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecStartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execstartandattach_options.go b/pkg/bindings/containers/types_execstartandattach_options.go
new file mode 100644
index 000000000..43900d29d
--- /dev/null
+++ b/pkg/bindings/containers/types_execstartandattach_options.go
@@ -0,0 +1,186 @@
+package containers
+
+import (
+ "bufio"
+ "io"
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.827903078 -0600 CST m=+0.000269906
+*/
+
+// Changed
+func (o *ExecStartAndAttachOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecStartAndAttachOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithOutputStream
+func (o *ExecStartAndAttachOptions) WithOutputStream(value io.WriteCloser) *ExecStartAndAttachOptions {
+ v := &value
+ o.OutputStream = v
+ return o
+}
+
+// GetOutputStream
+func (o *ExecStartAndAttachOptions) GetOutputStream() io.WriteCloser {
+ var outputStream io.WriteCloser
+ if o.OutputStream == nil {
+ return outputStream
+ }
+ return *o.OutputStream
+}
+
+// WithErrorStream
+func (o *ExecStartAndAttachOptions) WithErrorStream(value io.WriteCloser) *ExecStartAndAttachOptions {
+ v := &value
+ o.ErrorStream = v
+ return o
+}
+
+// GetErrorStream
+func (o *ExecStartAndAttachOptions) GetErrorStream() io.WriteCloser {
+ var errorStream io.WriteCloser
+ if o.ErrorStream == nil {
+ return errorStream
+ }
+ return *o.ErrorStream
+}
+
+// WithInputStream
+func (o *ExecStartAndAttachOptions) WithInputStream(value bufio.Reader) *ExecStartAndAttachOptions {
+ v := &value
+ o.InputStream = v
+ return o
+}
+
+// GetInputStream
+func (o *ExecStartAndAttachOptions) GetInputStream() bufio.Reader {
+ var inputStream bufio.Reader
+ if o.InputStream == nil {
+ return inputStream
+ }
+ return *o.InputStream
+}
+
+// WithAttachOutput
+func (o *ExecStartAndAttachOptions) WithAttachOutput(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachOutput = v
+ return o
+}
+
+// GetAttachOutput
+func (o *ExecStartAndAttachOptions) GetAttachOutput() bool {
+ var attachOutput bool
+ if o.AttachOutput == nil {
+ return attachOutput
+ }
+ return *o.AttachOutput
+}
+
+// WithAttachError
+func (o *ExecStartAndAttachOptions) WithAttachError(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachError = v
+ return o
+}
+
+// GetAttachError
+func (o *ExecStartAndAttachOptions) GetAttachError() bool {
+ var attachError bool
+ if o.AttachError == nil {
+ return attachError
+ }
+ return *o.AttachError
+}
+
+// WithAttachInput
+func (o *ExecStartAndAttachOptions) WithAttachInput(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachInput = v
+ return o
+}
+
+// GetAttachInput
+func (o *ExecStartAndAttachOptions) GetAttachInput() bool {
+ var attachInput bool
+ if o.AttachInput == nil {
+ return attachInput
+ }
+ return *o.AttachInput
+}
diff --git a/pkg/bindings/containers/types_export_options.go b/pkg/bindings/containers/types_export_options.go
new file mode 100644
index 000000000..e325bd2cd
--- /dev/null
+++ b/pkg/bindings/containers/types_export_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.101679998 -0600 CST m=+0.000261669
+*/
+
+// Changed
+func (o *ExportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_healthcheck_options.go b/pkg/bindings/containers/types_healthcheck_options.go
new file mode 100644
index 000000000..8c4300366
--- /dev/null
+++ b/pkg/bindings/containers/types_healthcheck_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.593883686 -0600 CST m=+0.000289845
+*/
+
+// Changed
+func (o *HealthCheckOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *HealthCheckOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_init_options.go b/pkg/bindings/containers/types_init_options.go
new file mode 100644
index 000000000..655362f62
--- /dev/null
+++ b/pkg/bindings/containers/types_init_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.245077233 -0600 CST m=+0.000255461
+*/
+
+// Changed
+func (o *InitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_inspect_options.go b/pkg/bindings/containers/types_inspect_options.go
new file mode 100644
index 000000000..884f5524d
--- /dev/null
+++ b/pkg/bindings/containers/types_inspect_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.635987603 -0600 CST m=+0.000260270
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSize
+func (o *InspectOptions) WithSize(value bool) *InspectOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *InspectOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
diff --git a/pkg/bindings/containers/types_kill_options.go b/pkg/bindings/containers/types_kill_options.go
new file mode 100644
index 000000000..3d6fa6224
--- /dev/null
+++ b/pkg/bindings/containers/types_kill_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.781581076 -0600 CST m=+0.000259040
+*/
+
+// Changed
+func (o *KillOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KillOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go
new file mode 100644
index 000000000..dd74d37b7
--- /dev/null
+++ b/pkg/bindings/containers/types_list_options.go
@@ -0,0 +1,186 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+ "strings"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.199081744 -0600 CST m=+0.000270626
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ fieldName = strings.ToLower(fieldName)
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *ListOptions) WithAll(value bool) *ListOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *ListOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithLast
+func (o *ListOptions) WithLast(value int) *ListOptions {
+ v := &value
+ o.Last = v
+ return o
+}
+
+// GetLast
+func (o *ListOptions) GetLast() int {
+ var last int
+ if o.Last == nil {
+ return last
+ }
+ return *o.Last
+}
+
+// WithNamespace
+func (o *ListOptions) WithNamespace(value bool) *ListOptions {
+ v := &value
+ o.Namespace = v
+ return o
+}
+
+// GetNamespace
+func (o *ListOptions) GetNamespace() bool {
+ var namespace bool
+ if o.Namespace == nil {
+ return namespace
+ }
+ return *o.Namespace
+}
+
+// WithSize
+func (o *ListOptions) WithSize(value bool) *ListOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *ListOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
+
+// WithSync
+func (o *ListOptions) WithSync(value bool) *ListOptions {
+ v := &value
+ o.Sync = v
+ return o
+}
+
+// GetSync
+func (o *ListOptions) GetSync() bool {
+ var sync bool
+ if o.Sync == nil {
+ return sync
+ }
+ return *o.Sync
+}
diff --git a/pkg/bindings/containers/types_log_options.go b/pkg/bindings/containers/types_log_options.go
new file mode 100644
index 000000000..a6958242f
--- /dev/null
+++ b/pkg/bindings/containers/types_log_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.273264471 -0600 CST m=+0.000274536
+*/
+
+// Changed
+func (o *LogOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *LogOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFollow
+func (o *LogOptions) WithFollow(value bool) *LogOptions {
+ v := &value
+ o.Follow = v
+ return o
+}
+
+// GetFollow
+func (o *LogOptions) GetFollow() bool {
+ var follow bool
+ if o.Follow == nil {
+ return follow
+ }
+ return *o.Follow
+}
+
+// WithSince
+func (o *LogOptions) WithSince(value string) *LogOptions {
+ v := &value
+ o.Since = v
+ return o
+}
+
+// GetSince
+func (o *LogOptions) GetSince() string {
+ var since string
+ if o.Since == nil {
+ return since
+ }
+ return *o.Since
+}
+
+// WithStderr
+func (o *LogOptions) WithStderr(value bool) *LogOptions {
+ v := &value
+ o.Stderr = v
+ return o
+}
+
+// GetStderr
+func (o *LogOptions) GetStderr() bool {
+ var stderr bool
+ if o.Stderr == nil {
+ return stderr
+ }
+ return *o.Stderr
+}
+
+// WithStdout
+func (o *LogOptions) WithStdout(value bool) *LogOptions {
+ v := &value
+ o.Stdout = v
+ return o
+}
+
+// GetStdout
+func (o *LogOptions) GetStdout() bool {
+ var stdout bool
+ if o.Stdout == nil {
+ return stdout
+ }
+ return *o.Stdout
+}
+
+// WithTail
+func (o *LogOptions) WithTail(value string) *LogOptions {
+ v := &value
+ o.Tail = v
+ return o
+}
+
+// GetTail
+func (o *LogOptions) GetTail() string {
+ var tail string
+ if o.Tail == nil {
+ return tail
+ }
+ return *o.Tail
+}
+
+// WithTimestamps
+func (o *LogOptions) WithTimestamps(value bool) *LogOptions {
+ v := &value
+ o.Timestamps = v
+ return o
+}
+
+// GetTimestamps
+func (o *LogOptions) GetTimestamps() bool {
+ var timestamps bool
+ if o.Timestamps == nil {
+ return timestamps
+ }
+ return *o.Timestamps
+}
+
+// WithUntil
+func (o *LogOptions) WithUntil(value string) *LogOptions {
+ v := &value
+ o.Until = v
+ return o
+}
+
+// GetUntil
+func (o *LogOptions) GetUntil() string {
+ var until string
+ if o.Until == nil {
+ return until
+ }
+ return *o.Until
+}
diff --git a/pkg/bindings/containers/types_mount_options.go b/pkg/bindings/containers/types_mount_options.go
new file mode 100644
index 000000000..c0e253094
--- /dev/null
+++ b/pkg/bindings/containers/types_mount_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.740822464 -0600 CST m=+0.000250074
+*/
+
+// Changed
+func (o *MountOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *MountOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_mountedcontainerpaths_options.go b/pkg/bindings/containers/types_mountedcontainerpaths_options.go
new file mode 100644
index 000000000..e368ff131
--- /dev/null
+++ b/pkg/bindings/containers/types_mountedcontainerpaths_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.048233253 -0600 CST m=+0.000307223
+*/
+
+// Changed
+func (o *MountedContainerPathsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *MountedContainerPathsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_pause_options.go b/pkg/bindings/containers/types_pause_options.go
new file mode 100644
index 000000000..26ad86793
--- /dev/null
+++ b/pkg/bindings/containers/types_pause_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.929891294 -0600 CST m=+0.000261081
+*/
+
+// Changed
+func (o *PauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_prune_options.go b/pkg/bindings/containers/types_prune_options.go
new file mode 100644
index 000000000..e3c0f4de7
--- /dev/null
+++ b/pkg/bindings/containers/types_prune_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.344278799 -0600 CST m=+0.000263499
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go
new file mode 100644
index 000000000..6f59f0ed5
--- /dev/null
+++ b/pkg/bindings/containers/types_remove_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.489968735 -0600 CST m=+0.000264450
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
+
+// WithVolumes
+func (o *RemoveOptions) WithVolumes(value bool) *RemoveOptions {
+ v := &value
+ o.Volumes = v
+ return o
+}
+
+// GetVolumes
+func (o *RemoveOptions) GetVolumes() bool {
+ var volumes bool
+ if o.Volumes == nil {
+ return volumes
+ }
+ return *o.Volumes
+}
diff --git a/pkg/bindings/containers/types_resizeexectty_options.go b/pkg/bindings/containers/types_resizeexectty_options.go
new file mode 100644
index 000000000..33bb4e78b
--- /dev/null
+++ b/pkg/bindings/containers/types_resizeexectty_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.680735758 -0600 CST m=+0.000267081
+*/
+
+// Changed
+func (o *ResizeExecTTYOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ResizeExecTTYOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithHeight
+func (o *ResizeExecTTYOptions) WithHeight(value int) *ResizeExecTTYOptions {
+ v := &value
+ o.Height = v
+ return o
+}
+
+// GetHeight
+func (o *ResizeExecTTYOptions) GetHeight() int {
+ var height int
+ if o.Height == nil {
+ return height
+ }
+ return *o.Height
+}
+
+// WithWidth
+func (o *ResizeExecTTYOptions) WithWidth(value int) *ResizeExecTTYOptions {
+ v := &value
+ o.Width = v
+ return o
+}
+
+// GetWidth
+func (o *ResizeExecTTYOptions) GetWidth() int {
+ var width int
+ if o.Width == nil {
+ return width
+ }
+ return *o.Width
+}
diff --git a/pkg/bindings/containers/types_resizetty_options.go b/pkg/bindings/containers/types_resizetty_options.go
new file mode 100644
index 000000000..29ec54988
--- /dev/null
+++ b/pkg/bindings/containers/types_resizetty_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.535788375 -0600 CST m=+0.000266528
+*/
+
+// Changed
+func (o *ResizeTTYOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ResizeTTYOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithHeight
+func (o *ResizeTTYOptions) WithHeight(value int) *ResizeTTYOptions {
+ v := &value
+ o.Height = v
+ return o
+}
+
+// GetHeight
+func (o *ResizeTTYOptions) GetHeight() int {
+ var height int
+ if o.Height == nil {
+ return height
+ }
+ return *o.Height
+}
+
+// WithWidth
+func (o *ResizeTTYOptions) WithWidth(value int) *ResizeTTYOptions {
+ v := &value
+ o.Width = v
+ return o
+}
+
+// GetWidth
+func (o *ResizeTTYOptions) GetWidth() int {
+ var width int
+ if o.Width == nil {
+ return width
+ }
+ return *o.Width
+}
diff --git a/pkg/bindings/containers/types_restart_options.go b/pkg/bindings/containers/types_restart_options.go
new file mode 100644
index 000000000..13ac099b1
--- /dev/null
+++ b/pkg/bindings/containers/types_restart_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.076709643 -0600 CST m=+0.000303354
+*/
+
+// Changed
+func (o *RestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *RestartOptions) WithTimeout(value int) *RestartOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *RestartOptions) GetTimeout() int {
+ var timeout int
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
new file mode 100644
index 000000000..be6e94736
--- /dev/null
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.861536405 -0600 CST m=+0.000300026
+*/
+
+// Changed
+func (o *RestoreOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestoreOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithIgnoreRootfs
+func (o *RestoreOptions) WithIgnoreRootfs(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreRootfs = v
+ return o
+}
+
+// GetIgnoreRootfs
+func (o *RestoreOptions) GetIgnoreRootfs() bool {
+ var ignoreRootfs bool
+ if o.IgnoreRootfs == nil {
+ return ignoreRootfs
+ }
+ return *o.IgnoreRootfs
+}
+
+// WithIgnoreStaticIP
+func (o *RestoreOptions) WithIgnoreStaticIP(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreStaticIP = v
+ return o
+}
+
+// GetIgnoreStaticIP
+func (o *RestoreOptions) GetIgnoreStaticIP() bool {
+ var ignoreStaticIP bool
+ if o.IgnoreStaticIP == nil {
+ return ignoreStaticIP
+ }
+ return *o.IgnoreStaticIP
+}
+
+// WithIgnoreStaticMAC
+func (o *RestoreOptions) WithIgnoreStaticMAC(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreStaticMAC = v
+ return o
+}
+
+// GetIgnoreStaticMAC
+func (o *RestoreOptions) GetIgnoreStaticMAC() bool {
+ var ignoreStaticMAC bool
+ if o.IgnoreStaticMAC == nil {
+ return ignoreStaticMAC
+ }
+ return *o.IgnoreStaticMAC
+}
+
+// WithImportAchive
+func (o *RestoreOptions) WithImportAchive(value string) *RestoreOptions {
+ v := &value
+ o.ImportAchive = v
+ return o
+}
+
+// GetImportAchive
+func (o *RestoreOptions) GetImportAchive() string {
+ var importAchive string
+ if o.ImportAchive == nil {
+ return importAchive
+ }
+ return *o.ImportAchive
+}
+
+// WithKeep
+func (o *RestoreOptions) WithKeep(value bool) *RestoreOptions {
+ v := &value
+ o.Keep = v
+ return o
+}
+
+// GetKeep
+func (o *RestoreOptions) GetKeep() bool {
+ var keep bool
+ if o.Keep == nil {
+ return keep
+ }
+ return *o.Keep
+}
+
+// WithName
+func (o *RestoreOptions) WithName(value string) *RestoreOptions {
+ v := &value
+ o.Name = v
+ return o
+}
+
+// GetName
+func (o *RestoreOptions) GetName() string {
+ var name string
+ if o.Name == nil {
+ return name
+ }
+ return *o.Name
+}
+
+// WithTCPEstablished
+func (o *RestoreOptions) WithTCPEstablished(value bool) *RestoreOptions {
+ v := &value
+ o.TCPEstablished = v
+ return o
+}
+
+// GetTCPEstablished
+func (o *RestoreOptions) GetTCPEstablished() bool {
+ var tCPEstablished bool
+ if o.TCPEstablished == nil {
+ return tCPEstablished
+ }
+ return *o.TCPEstablished
+}
diff --git a/pkg/bindings/containers/types_shouldrestart_options.go b/pkg/bindings/containers/types_shouldrestart_options.go
new file mode 100644
index 000000000..c833d0d8b
--- /dev/null
+++ b/pkg/bindings/containers/types_shouldrestart_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.388596051 -0600 CST m=+0.000253693
+*/
+
+// Changed
+func (o *ShouldRestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ShouldRestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_start_options.go b/pkg/bindings/containers/types_start_options.go
new file mode 100644
index 000000000..5918af89b
--- /dev/null
+++ b/pkg/bindings/containers/types_start_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.221364502 -0600 CST m=+0.000276575
+*/
+
+// Changed
+func (o *StartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDetachKeys
+func (o *StartOptions) WithDetachKeys(value string) *StartOptions {
+ v := &value
+ o.DetachKeys = v
+ return o
+}
+
+// GetDetachKeys
+func (o *StartOptions) GetDetachKeys() string {
+ var detachKeys string
+ if o.DetachKeys == nil {
+ return detachKeys
+ }
+ return *o.DetachKeys
+}
diff --git a/pkg/bindings/containers/types_stats_options.go b/pkg/bindings/containers/types_stats_options.go
new file mode 100644
index 000000000..f821ea1cd
--- /dev/null
+++ b/pkg/bindings/containers/types_stats_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.370213399 -0600 CST m=+0.000264334
+*/
+
+// Changed
+func (o *StatsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StatsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithStream
+func (o *StatsOptions) WithStream(value bool) *StatsOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *StatsOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
diff --git a/pkg/bindings/containers/types_stop_options.go b/pkg/bindings/containers/types_stop_options.go
new file mode 100644
index 000000000..14d7633a0
--- /dev/null
+++ b/pkg/bindings/containers/types_stop_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.95469621 -0600 CST m=+0.000261399
+*/
+
+// Changed
+func (o *StopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *StopOptions) WithTimeout(value uint) *StopOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *StopOptions) GetTimeout() uint {
+ var timeout uint
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/containers/types_top_options.go b/pkg/bindings/containers/types_top_options.go
new file mode 100644
index 000000000..95a1ee686
--- /dev/null
+++ b/pkg/bindings/containers/types_top_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.515867629 -0600 CST m=+0.000257106
+*/
+
+// Changed
+func (o *TopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDescriptors
+func (o *TopOptions) WithDescriptors(value []string) *TopOptions {
+ v := &value
+ o.Descriptors = v
+ return o
+}
+
+// GetDescriptors
+func (o *TopOptions) GetDescriptors() []string {
+ var descriptors []string
+ if o.Descriptors == nil {
+ return descriptors
+ }
+ return *o.Descriptors
+}
diff --git a/pkg/bindings/containers/types_unmount_options.go b/pkg/bindings/containers/types_unmount_options.go
new file mode 100644
index 000000000..a29bd8216
--- /dev/null
+++ b/pkg/bindings/containers/types_unmount_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.891657824 -0600 CST m=+0.000326668
+*/
+
+// Changed
+func (o *UnmountOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnmountOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_unpause_options.go b/pkg/bindings/containers/types_unpause_options.go
new file mode 100644
index 000000000..44c077df2
--- /dev/null
+++ b/pkg/bindings/containers/types_unpause_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.661356277 -0600 CST m=+0.000262608
+*/
+
+// Changed
+func (o *UnpauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnpauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_wait_options.go b/pkg/bindings/containers/types_wait_options.go
new file mode 100644
index 000000000..18d36c377
--- /dev/null
+++ b/pkg/bindings/containers/types_wait_options.go
@@ -0,0 +1,105 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ "github.com/containers/podman/v2/libpod/define"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.809397978 -0600 CST m=+0.000267049
+*/
+
+// Changed
+func (o *WaitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *WaitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithCondition
+func (o *WaitOptions) WithCondition(value define.ContainerStatus) *WaitOptions {
+ v := &value
+ o.Condition = v
+ return o
+}
+
+// GetCondition
+func (o *WaitOptions) GetCondition() define.ContainerStatus {
+ var condition define.ContainerStatus
+ if o.Condition == nil {
+ return condition
+ }
+ return *o.Condition
+}
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index 8d0146ec1..29eb39557 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -4,31 +4,23 @@ import (
"context"
"errors"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+func Systemd(ctx context.Context, nameOrID string, options *SystemdOptions) (*entities.GenerateSystemdReport, error) {
+ if options == nil {
+ options = new(SystemdOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
-
- params.Set("useName", strconv.FormatBool(options.Name))
- params.Set("new", strconv.FormatBool(options.New))
- if options.RestartPolicy != "" {
- params.Set("restartPolicy", options.RestartPolicy)
- }
- if options.StopTimeout != nil {
- params.Set("stopTimeout", strconv.FormatUint(uint64(*options.StopTimeout), 10))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
- params.Set("containerPrefix", options.ContainerPrefix)
- params.Set("podPrefix", options.PodPrefix)
- params.Set("separator", options.Separator)
response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/systemd", params, nil, nameOrID)
if err != nil {
@@ -38,7 +30,10 @@ func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSyst
return report, response.Process(&report.Units)
}
-func Kube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+func Kube(ctx context.Context, nameOrIDs []string, options *KubeOptions) (*entities.GenerateKubeReport, error) {
+ if options == nil {
+ options = new(KubeOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -46,12 +41,14 @@ func Kube(ctx context.Context, nameOrIDs []string, options entities.GenerateKube
if len(nameOrIDs) < 1 {
return nil, errors.New("must provide the name or ID of one container or pod")
}
- params := url.Values{}
+
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
for _, name := range nameOrIDs {
params.Add("names", name)
}
- params.Set("service", strconv.FormatBool(options.Service))
-
response, err := conn.DoRequest(nil, http.MethodGet, "/generate/kube", params, nil)
if err != nil {
return nil, err
diff --git a/pkg/bindings/generate/types.go b/pkg/bindings/generate/types.go
new file mode 100644
index 000000000..4e9d7a0ff
--- /dev/null
+++ b/pkg/bindings/generate/types.go
@@ -0,0 +1,27 @@
+package generate
+
+//go:generate go run ../generator/generator.go KubeOptions
+// KubeOptions are optional options for generating kube YAML files
+type KubeOptions struct {
+ // Service - generate YAML for a Kubernetes _service_ object.
+ Service *bool
+}
+
+//go:generate go run ../generator/generator.go SystemdOptions
+// SystemdOptions are optional options for generating systemd files
+type SystemdOptions struct {
+ // Name - use container/pod name instead of its ID.
+ UseName *bool
+ // New - create a new container instead of starting a new one.
+ New *bool
+ // RestartPolicy - systemd restart policy.
+ RestartPolicy *string
+ // StopTimeout - time when stopping the container.
+ StopTimeout *uint
+ // ContainerPrefix - systemd unit name prefix for containers
+ ContainerPrefix *string
+ // PodPrefix - systemd unit name prefix for pods
+ PodPrefix *string
+ // Separator - systemd unit name separator between name/id and prefix
+ Separator *string
+}
diff --git a/pkg/bindings/generate/types_kube_options.go b/pkg/bindings/generate/types_kube_options.go
new file mode 100644
index 000000000..68488aaee
--- /dev/null
+++ b/pkg/bindings/generate/types_kube_options.go
@@ -0,0 +1,104 @@
+package generate
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:20.522950566 -0600 CST m=+0.000154384
+*/
+
+// Changed
+func (o *KubeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KubeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithService
+func (o *KubeOptions) WithService(value bool) *KubeOptions {
+ v := &value
+ o.Service = v
+ return o
+}
+
+// GetService
+func (o *KubeOptions) GetService() bool {
+ var service bool
+ if o.Service == nil {
+ return service
+ }
+ return *o.Service
+}
diff --git a/pkg/bindings/generate/types_systemd_options.go b/pkg/bindings/generate/types_systemd_options.go
new file mode 100644
index 000000000..0e8a46aa0
--- /dev/null
+++ b/pkg/bindings/generate/types_systemd_options.go
@@ -0,0 +1,200 @@
+package generate
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:20.661450253 -0600 CST m=+0.000135779
+*/
+
+// Changed
+func (o *SystemdOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *SystemdOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithUseName
+func (o *SystemdOptions) WithUseName(value bool) *SystemdOptions {
+ v := &value
+ o.UseName = v
+ return o
+}
+
+// GetUseName
+func (o *SystemdOptions) GetUseName() bool {
+ var useName bool
+ if o.UseName == nil {
+ return useName
+ }
+ return *o.UseName
+}
+
+// WithNew
+func (o *SystemdOptions) WithNew(value bool) *SystemdOptions {
+ v := &value
+ o.New = v
+ return o
+}
+
+// GetNew
+func (o *SystemdOptions) GetNew() bool {
+ var new bool
+ if o.New == nil {
+ return new
+ }
+ return *o.New
+}
+
+// WithRestartPolicy
+func (o *SystemdOptions) WithRestartPolicy(value string) *SystemdOptions {
+ v := &value
+ o.RestartPolicy = v
+ return o
+}
+
+// GetRestartPolicy
+func (o *SystemdOptions) GetRestartPolicy() string {
+ var restartPolicy string
+ if o.RestartPolicy == nil {
+ return restartPolicy
+ }
+ return *o.RestartPolicy
+}
+
+// WithStopTimeout
+func (o *SystemdOptions) WithStopTimeout(value uint) *SystemdOptions {
+ v := &value
+ o.StopTimeout = v
+ return o
+}
+
+// GetStopTimeout
+func (o *SystemdOptions) GetStopTimeout() uint {
+ var stopTimeout uint
+ if o.StopTimeout == nil {
+ return stopTimeout
+ }
+ return *o.StopTimeout
+}
+
+// WithContainerPrefix
+func (o *SystemdOptions) WithContainerPrefix(value string) *SystemdOptions {
+ v := &value
+ o.ContainerPrefix = v
+ return o
+}
+
+// GetContainerPrefix
+func (o *SystemdOptions) GetContainerPrefix() string {
+ var containerPrefix string
+ if o.ContainerPrefix == nil {
+ return containerPrefix
+ }
+ return *o.ContainerPrefix
+}
+
+// WithPodPrefix
+func (o *SystemdOptions) WithPodPrefix(value string) *SystemdOptions {
+ v := &value
+ o.PodPrefix = v
+ return o
+}
+
+// GetPodPrefix
+func (o *SystemdOptions) GetPodPrefix() string {
+ var podPrefix string
+ if o.PodPrefix == nil {
+ return podPrefix
+ }
+ return *o.PodPrefix
+}
+
+// WithSeparator
+func (o *SystemdOptions) WithSeparator(value string) *SystemdOptions {
+ v := &value
+ o.Separator = v
+ return o
+}
+
+// GetSeparator
+func (o *SystemdOptions) GetSeparator() string {
+ var separator string
+ if o.Separator == nil {
+ return separator
+ }
+ return *o.Separator
+}
diff --git a/pkg/bindings/generator/generator.go b/pkg/bindings/generator/generator.go
new file mode 100644
index 000000000..8c79aebae
--- /dev/null
+++ b/pkg/bindings/generator/generator.go
@@ -0,0 +1,261 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+ "text/template"
+ "time"
+)
+
+var bodyTmpl = `package {{.PackageName}}
+
+import (
+{{range $import := .Imports}} {{$import}}
+{{end}}
+
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created {{.Date}}
+*/
+
+// Changed
+func (o *{{.StructName}}) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *{{.StructName}}) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+`
+
+var fieldTmpl = `
+// With{{.Name}}
+func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} {
+ v := {{.TypedValue}}
+ o.{{.Name}} = v
+ return o
+}
+
+// Get{{.Name}}
+func(o *{{.StructName}}) Get{{.Name}}() {{.Type}} {
+ var {{.ZeroName}} {{.Type}}
+ if o.{{.Name}} == nil {
+ return {{.ZeroName}}
+ }
+ return {{.TypedName}}
+}
+`
+
+type fieldStruct struct {
+ Name string
+ StructName string
+ Type string
+ TypedName string
+ TypedValue string
+ ZeroName string
+}
+
+func main() {
+ var (
+ closed bool
+ fieldStructs []fieldStruct
+ )
+ srcFile := os.Getenv("GOFILE")
+ pkg := os.Getenv("GOPACKAGE")
+ inputStructName := os.Args[1]
+ b, err := ioutil.ReadFile(srcFile)
+ if err != nil {
+ panic(err)
+ }
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "", b, parser.ParseComments)
+ if err != nil {
+ panic(err)
+ }
+ // always add reflect
+ imports := []string{"\"reflect\""}
+ for _, imp := range f.Imports {
+ imports = append(imports, imp.Path.Value)
+ }
+
+ out, err := os.Create(strings.TrimRight(srcFile, ".go") + "_" + strings.Replace(strings.ToLower(inputStructName), "options", "_options", 1) + ".go")
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if !closed {
+ out.Close()
+ }
+ }()
+ bodyStruct := struct {
+ PackageName string
+ Imports []string
+ Date string
+ StructName string
+ }{
+ PackageName: pkg,
+ Imports: imports,
+ Date: time.Now().String(),
+ StructName: inputStructName,
+ }
+
+ body := template.Must(template.New("body").Parse(bodyTmpl))
+ fields := template.Must(template.New("fields").Parse(fieldTmpl))
+ ast.Inspect(f, func(n ast.Node) bool {
+ ref, refOK := n.(*ast.TypeSpec)
+ if refOK {
+ if ref.Name.Name == inputStructName {
+ x := ref.Type.(*ast.StructType)
+ for _, field := range x.Fields.List {
+ var (
+ name, zeroName, typedName, typedValue string
+ )
+ if len(field.Names) > 0 {
+ name = field.Names[0].Name
+ if len(name) < 1 {
+ panic(errors.New("bad name"))
+ }
+ }
+ for k, v := range name {
+ zeroName = strings.ToLower(string(v)) + name[k+1:]
+ break
+ }
+ //sub := "*"
+ typeExpr := field.Type
+ switch field.Type.(type) {
+ case *ast.MapType, *ast.StructType, *ast.ArrayType:
+ typedName = "o." + name
+ typedValue = "value"
+ default:
+ typedName = "*o." + name
+ typedValue = "&value"
+ }
+ start := typeExpr.Pos() - 1
+ end := typeExpr.End() - 1
+ fieldType := strings.Replace(string(b[start:end]), "*", "", 1)
+ fStruct := fieldStruct{
+ Name: name,
+ StructName: inputStructName,
+ Type: fieldType,
+ TypedName: typedName,
+ TypedValue: typedValue,
+ ZeroName: zeroName,
+ }
+ fieldStructs = append(fieldStructs, fStruct)
+ } // for
+
+ // create the body
+ if err := body.Execute(out, bodyStruct); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ // create with func from the struct fields
+ for _, fs := range fieldStructs {
+ if err := fields.Execute(out, fs); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ // close out file
+ if err := out.Close(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ closed = true
+
+ // go fmt file
+ gofmt := exec.Command("gofmt", "-w", "-s", out.Name())
+ gofmt.Stderr = os.Stdout
+ if err := gofmt.Run(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ // go import file
+ goimport := exec.Command("goimports", "-w", out.Name())
+ goimport.Stderr = os.Stdout
+ if err := goimport.Run(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ }
+ return true
+ })
+}
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
index 10d50b0fd..8802c15e2 100644
--- a/pkg/bindings/images/diff.go
+++ b/pkg/bindings/images/diff.go
@@ -9,7 +9,11 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) {
+ if options == nil {
+ options = new(DiffOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 2d3035d8d..ecdd1f553 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -8,11 +8,11 @@ import (
"net/url"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -32,22 +32,18 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// List returns a list of images in local storage. The all boolean and filters parameters are optional
// ways to alter the image query.
-func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entities.ImageSummary, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.ImageSummary, error) {
+ if options == nil {
+ options = new(ListOptions)
+ }
var imageSummary []*entities.ImageSummary
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if filters != nil {
- strFilters, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", strFilters)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
if err != nil {
@@ -58,14 +54,17 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit
// Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter.
-func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) {
+func GetImage(ctx context.Context, nameOrID string, options *GetOptions) (*entities.ImageInspectReport, error) {
+ if options == nil {
+ options = new(GetOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
inspectedData := entities.ImageInspectReport{}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID)
@@ -76,15 +75,18 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
}
// Tree retrieves a "tree" based representation of the given image
-func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) {
+func Tree(ctx context.Context, nameOrID string, options *TreeOptions) (*entities.ImageTreeReport, error) {
+ if options == nil {
+ options = new(TreeOptions)
+ }
var report entities.ImageTreeReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if whatRequires != nil {
- params.Set("size", strconv.FormatBool(*whatRequires))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
if err != nil {
@@ -94,7 +96,11 @@ func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.I
}
// History returns the parent layers of an image.
-func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
+func History(ctx context.Context, nameOrID string, options *HistoryOptions) ([]*handlers.HistoryResponse, error) {
+ if options == nil {
+ options = new(HistoryOptions)
+ }
+ _ = options
var history []*handlers.HistoryResponse
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -107,15 +113,18 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
return history, response.Process(&history)
}
-func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) {
+func Load(ctx context.Context, r io.Reader, options *LoadOptions) (*entities.ImageLoadReport, error) {
+ if options == nil {
+ options = new(LoadOptions)
+ }
var report entities.ImageLoadReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if name != nil {
- params.Set("reference", *name)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
if err != nil {
@@ -124,49 +133,24 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe
return &report, response.Process(&report)
}
-func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error {
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return err
- }
- params := url.Values{}
- if format != nil {
- params.Set("format", *format)
- }
- if compress != nil {
- params.Set("compress", strconv.FormatBool(*compress))
- }
- for _, ref := range namesOrIds {
- params.Add("references", ref)
+// Export saves images from local storage as a tarball or image archive. The optional format
+// parameter is used to change the format of the output.
+func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *ExportOptions) error {
+ if options == nil {
+ options = new(ExportOptions)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
-
- if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
- _, err = io.Copy(w, response.Body)
- return err
- }
- return response.Process(nil)
-
-}
-
-// Export saves an image from local storage as a tarball or image archive. The optional format
-// parameter is used to change the format of the output.
-func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error {
- conn, err := bindings.GetClient(ctx)
+ params, err := options.ToParams()
if err != nil {
return err
}
- params := url.Values{}
- if format != nil {
- params.Set("format", *format)
- }
- if compress != nil {
- params.Set("compress", strconv.FormatBool(*compress))
+ for _, ref := range nameOrIDs {
+ params.Add("references", ref)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
if err != nil {
return err
}
@@ -180,34 +164,35 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c
// Prune removes unused images from local storage. The optional filters can be used to further
// define which images should be pruned.
-func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- deleted []string
+ deleted []*reports.PruneReport
)
+ if options == nil {
+ options = new(PruneOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if filters != nil {
- stringFilter, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", stringFilter)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
if err != nil {
return deleted, err
}
- return deleted, response.Process(&deleted)
+ err = response.Process(&deleted)
+ return deleted, err
}
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
-func Tag(ctx context.Context, nameOrID, tag, repo string) error {
+func Tag(ctx context.Context, nameOrID, tag, repo string, options *TagOptions) error {
+ if options == nil {
+ options = new(TagOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -223,7 +208,11 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error {
}
// Untag removes a name from locally-stored image. Both the tag and repo parameters are required.
-func Untag(ctx context.Context, nameOrID, tag, repo string) error {
+func Untag(ctx context.Context, nameOrID, tag, repo string, options *UntagOptions) error {
+ if options == nil {
+ options = new(UntagOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -241,27 +230,21 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error {
// Imports adds the given image to the local image store. This can be done by file and the given reader
// or via the url parameter. Additional metadata can be associated with the image by using the changes and
// message parameters. The image can also be tagged given a reference. One of url OR r must be provided.
-func Import(ctx context.Context, changes []string, message, reference, u *string, r io.Reader) (*entities.ImageImportReport, error) {
+func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities.ImageImportReport, error) {
+ if options == nil {
+ options = new(ImportOptions)
+ }
var report entities.ImageImportReport
- if r != nil && u != nil {
+ if r != nil && options.URL != nil {
return nil, errors.New("url and r parameters cannot be used together")
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- for _, change := range changes {
- params.Add("changes", change)
- }
- if message != nil {
- params.Set("message", *message)
- }
- if reference != nil {
- params.Set("reference", *reference)
- }
- if u != nil {
- params.Set("url", *u)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
if err != nil {
@@ -275,25 +258,31 @@ func Import(ctx context.Context, changes []string, message, reference, u *string
// The destination must be a reference to a registry (i.e., of docker transport
// or be normalized to one). Other transports are rejected as they do not make
// sense in a remote context.
-func Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
+func Push(ctx context.Context, source string, destination string, options *PushOptions) error {
+ if options == nil {
+ options = new(PushOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
-
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return err
}
- params := url.Values{}
- params.Set("destination", destination)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
- // Note: we have to verify if skipped is false.
- verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
+ //SkipTLSVerify is special. We need to delete the param added by
+ //toparams and change the key and flip the bool
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
+ params.Set("destination", destination)
path := fmt.Sprintf("/images/%s/push", source)
response, err := conn.DoRequest(nil, http.MethodPost, path, params, header)
@@ -305,28 +294,28 @@ func Push(ctx context.Context, source string, destination string, options entiti
}
// Search is the binding for libpod's v2 endpoints for Search images.
-func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
+func Search(ctx context.Context, term string, options *SearchOptions) ([]entities.ImageSearchReport, error) {
+ if options == nil {
+ options = new(SearchOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- params.Set("term", term)
- params.Set("limit", strconv.Itoa(opts.Limit))
- params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
- params.Set("listTags", strconv.FormatBool(opts.ListTags))
- for _, f := range opts.Filters {
- params.Set("filters", f)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
+ params.Set("term", term)
- if opts.SkipTLSVerify != types.OptionalBoolUndefined {
- // Note: we have to verify if skipped is false.
- verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ // Note: we have to verify if skipped is false.
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "")
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), "", "")
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index c827b3283..5669c704e 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -8,11 +8,9 @@ import (
"io"
"io/ioutil"
"net/http"
- "net/url"
"os"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -23,26 +21,28 @@ import (
// `rawImage` must be a reference to a registry (i.e., of docker transport or be
// normalized to one). Other transports are rejected as they do not make sense
// in a remote context. Progress reported on stderr
-func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) {
+func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) {
+ if options == nil {
+ options = new(PullOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
params.Set("reference", rawImage)
- params.Set("overrideArch", options.OverrideArch)
- params.Set("overrideOS", options.OverrideOS)
- params.Set("overrideVariant", options.OverrideVariant)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
// Note: we have to verify if skipped is false.
- verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
- params.Set("allTags", strconv.FormatBool(options.AllTags))
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
@@ -59,7 +59,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
// Historically pull writes status to stderr
stderr := io.Writer(os.Stderr)
- if options.Quiet {
+ if options.GetQuiet() {
stderr = ioutil.Discard
}
diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go
index 9685b75e4..e652e66aa 100644
--- a/pkg/bindings/images/rm.go
+++ b/pkg/bindings/images/rm.go
@@ -3,8 +3,6 @@ package images
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
@@ -12,8 +10,12 @@ import (
"github.com/containers/podman/v2/pkg/errorhandling"
)
-// BachtRemove removes a batch of images from the local storage.
-func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
+// Remove removes one or more images from the local storage. Use optional force option to remove an
+// image, even if it's used by containers.
+func Remove(ctx context.Context, images []string, options *RemoveOptions) (*entities.ImageRemoveReport, []error) {
+ if options == nil {
+ options = new(RemoveOptions)
+ }
// FIXME - bindings tests are missing for this endpoint. Once the CI is
// re-enabled for bindings, we need to add them. At the time of writing,
// the tests don't compile.
@@ -23,13 +25,13 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return nil, []error{err}
}
- params := url.Values{}
- params.Set("all", strconv.FormatBool(opts.All))
- params.Set("force", strconv.FormatBool(opts.Force))
- for _, i := range images {
- params.Add("images", i)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, nil
+ }
+ for _, image := range images {
+ params.Add("images", image)
}
-
response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil)
if err != nil {
return nil, []error{err}
@@ -40,26 +42,3 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return &report.ImageRemoveReport, errorhandling.StringsToErrors(report.Errors)
}
-
-// Remove removes an image from the local storage. Use force to remove an
-// image, even if it's used by containers.
-func Remove(ctx context.Context, nameOrID string, force bool) (*entities.ImageRemoveReport, error) {
- var report handlers.LibpodImagesRemoveReport
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
-
- params := url.Values{}
- params.Set("force", strconv.FormatBool(force))
- response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID)
- if err != nil {
- return nil, err
- }
- if err := response.Process(&report); err != nil {
- return nil, err
- }
-
- errs := errorhandling.StringsToErrors(report.Errors)
- return &report.ImageRemoveReport, errorhandling.JoinErrors(errs)
-}
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
new file mode 100644
index 000000000..3adb4356b
--- /dev/null
+++ b/pkg/bindings/images/types.go
@@ -0,0 +1,193 @@
+package images
+
+import (
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/common/pkg/config"
+)
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for image removal
+type RemoveOptions struct {
+ // All removes all images
+ All *bool
+ // Forces removes all containers based on the image
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go DiffOptions
+// DiffOptions are optional options image diffs
+type DiffOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing images
+type ListOptions struct {
+ // All lists all image in the image store including dangling images
+ All *bool
+ // filters that can be used to get a more specific list of images
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go GetOptions
+// GetOptions are optional options for inspecting an image
+type GetOptions struct {
+ // Size computes the amount of storage the image consumes
+ Size *bool
+}
+
+//go:generate go run ../generator/generator.go TreeOptions
+// TreeOptions are optional options for a tree-based representation
+// of the image
+type TreeOptions struct {
+ // WhatRequires ...
+ WhatRequires *bool
+}
+
+//go:generate go run ../generator/generator.go HistoryOptions
+// HistoryOptions are optional options image history
+type HistoryOptions struct {
+}
+
+//go:generate go run ../generator/generator.go LoadOptions
+// LoadOptions are optional options for loading an image
+type LoadOptions struct {
+ // Reference is the name of the loaded image
+ Reference *string
+}
+
+//go:generate go run ../generator/generator.go ExportOptions
+// ExportOptions are optional options for exporting images
+type ExportOptions struct {
+ // Compress the image
+ Compress *bool
+ // Format of the output
+ Format *string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning images
+type PruneOptions struct {
+ // Prune all images
+ All *bool
+ // Filters to apply when pruning images
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go TagOptions
+// TagOptions are optional options for tagging images
+type TagOptions struct {
+}
+
+//go:generate go run ../generator/generator.go UntagOptions
+// UntagOptions are optional options for untagging images
+type UntagOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ImportOptions
+// ImportOptions are optional options for importing images
+type ImportOptions struct {
+ // Changes to be applied to the image
+ Changes *[]string
+ // Message to be applied to the image
+ Message *string
+ // Reference is a tag to be applied to the image
+ Reference *string
+ // Url to option image to import. Cannot be used with the reader
+ URL *string
+}
+
+//go:generate go run ../generator/generator.go PushOptions
+// PushOptions are optional options for importing images
+type PushOptions struct {
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // CertDir is the path to certificate directories. Ignored for remote
+ // calls.
+ CertDir *string
+ // Compress tarball image layers when pushing to a directory using the 'dir'
+ // transport. Default is same compression type as source. Ignored for remote
+ // calls.
+ Compress *bool
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // DigestFile, after copying the image, write the digest of the resulting
+ // image to the file. Ignored for remote calls.
+ DigestFile *string
+ // Format is the Manifest type (oci, v2s1, or v2s2) to use when pushing an
+ // image using the 'dir' transport. Default is manifest type of source.
+ // Ignored for remote calls.
+ Format *string
+ // Quiet can be specified to suppress pull progress when pulling. Ignored
+ // for remote calls.
+ Quiet *bool
+ // RemoveSignatures, discard any pre-existing signatures in the image.
+ // Ignored for remote calls.
+ RemoveSignatures *bool
+ // SignaturePolicy to use when pulling. Ignored for remote calls.
+ SignaturePolicy *string
+ // SignBy adds a signature at the destination using the specified key.
+ // Ignored for remote calls.
+ SignBy *string
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+}
+
+//go:generate go run ../generator/generator.go SearchOptions
+// SearchOptions are optional options for searching images on registries
+type SearchOptions struct {
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // Filters for the search results.
+ Filters map[string][]string
+ // Limit the number of results.
+ Limit *int
+ // NoTrunc will not truncate the output.
+ NoTrunc *bool
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+ // ListTags search the available tags of the repository
+ ListTags *bool
+}
+
+//go:generate go run ../generator/generator.go PullOptions
+// PullOptions are optional options for pulling images
+type PullOptions struct {
+ // AllTags can be specified to pull all tags of an image. Note
+ // that this only works if the image does not include a tag.
+ AllTags *bool
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // CertDir is the path to certificate directories. Ignored for remote
+ // calls.
+ CertDir *string
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // OverrideArch will overwrite the local architecture for image pulls.
+ OverrideArch *string
+ // OverrideOS will overwrite the local operating system (OS) for image
+ // pulls.
+ OverrideOS *string
+ // OverrideVariant will overwrite the local variant for image pulls.
+ OverrideVariant *string
+ // Quiet can be specified to suppress pull progress when pulling. Ignored
+ // for remote calls.
+ Quiet *bool
+ // SignaturePolicy to use when pulling. Ignored for remote calls.
+ SignaturePolicy *string
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+ // PullPolicy whether to pull new image
+ PullPolicy *config.PullPolicy
+}
+
+//BuildOptions are optional options for building images
+type BuildOptions struct {
+ imagebuildah.BuildOptions
+}
diff --git a/pkg/bindings/images/types_diff_options.go b/pkg/bindings/images/types_diff_options.go
new file mode 100644
index 000000000..d27c8945e
--- /dev/null
+++ b/pkg/bindings/images/types_diff_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.320022698 -0600 CST m=+0.000277796
+*/
+
+// Changed
+func (o *DiffOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiffOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_export_options.go b/pkg/bindings/images/types_export_options.go
new file mode 100644
index 000000000..078b27fc0
--- /dev/null
+++ b/pkg/bindings/images/types_export_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.173810543 -0600 CST m=+0.000239871
+*/
+
+// Changed
+func (o *ExportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithCompress
+func (o *ExportOptions) WithCompress(value bool) *ExportOptions {
+ v := &value
+ o.Compress = v
+ return o
+}
+
+// GetCompress
+func (o *ExportOptions) GetCompress() bool {
+ var compress bool
+ if o.Compress == nil {
+ return compress
+ }
+ return *o.Compress
+}
+
+// WithFormat
+func (o *ExportOptions) WithFormat(value string) *ExportOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *ExportOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
diff --git a/pkg/bindings/images/types_get_options.go b/pkg/bindings/images/types_get_options.go
new file mode 100644
index 000000000..1161657f7
--- /dev/null
+++ b/pkg/bindings/images/types_get_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.609005517 -0600 CST m=+0.000241828
+*/
+
+// Changed
+func (o *GetOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *GetOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSize
+func (o *GetOptions) WithSize(value bool) *GetOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *GetOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
diff --git a/pkg/bindings/images/types_history_options.go b/pkg/bindings/images/types_history_options.go
new file mode 100644
index 000000000..6f9854e03
--- /dev/null
+++ b/pkg/bindings/images/types_history_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.890854681 -0600 CST m=+0.000243668
+*/
+
+// Changed
+func (o *HistoryOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *HistoryOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_import_options.go b/pkg/bindings/images/types_import_options.go
new file mode 100644
index 000000000..f5e6c8f7e
--- /dev/null
+++ b/pkg/bindings/images/types_import_options.go
@@ -0,0 +1,152 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.740585278 -0600 CST m=+0.000340441
+*/
+
+// Changed
+func (o *ImportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ImportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithChanges
+func (o *ImportOptions) WithChanges(value []string) *ImportOptions {
+ v := &value
+ o.Changes = v
+ return o
+}
+
+// GetChanges
+func (o *ImportOptions) GetChanges() []string {
+ var changes []string
+ if o.Changes == nil {
+ return changes
+ }
+ return *o.Changes
+}
+
+// WithMessage
+func (o *ImportOptions) WithMessage(value string) *ImportOptions {
+ v := &value
+ o.Message = v
+ return o
+}
+
+// GetMessage
+func (o *ImportOptions) GetMessage() string {
+ var message string
+ if o.Message == nil {
+ return message
+ }
+ return *o.Message
+}
+
+// WithReference
+func (o *ImportOptions) WithReference(value string) *ImportOptions {
+ v := &value
+ o.Reference = v
+ return o
+}
+
+// GetReference
+func (o *ImportOptions) GetReference() string {
+ var reference string
+ if o.Reference == nil {
+ return reference
+ }
+ return *o.Reference
+}
+
+// WithURL
+func (o *ImportOptions) WithURL(value string) *ImportOptions {
+ v := &value
+ o.URL = v
+ return o
+}
+
+// GetURL
+func (o *ImportOptions) GetURL() string {
+ var uRL string
+ if o.URL == nil {
+ return uRL
+ }
+ return *o.URL
+}
diff --git a/pkg/bindings/images/types_list_options.go b/pkg/bindings/images/types_list_options.go
new file mode 100644
index 000000000..209d72e34
--- /dev/null
+++ b/pkg/bindings/images/types_list_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.462967928 -0600 CST m=+0.000289760
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *ListOptions) WithAll(value bool) *ListOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *ListOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/images/types_load_options.go b/pkg/bindings/images/types_load_options.go
new file mode 100644
index 000000000..6bba573d4
--- /dev/null
+++ b/pkg/bindings/images/types_load_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.031848205 -0600 CST m=+0.000279409
+*/
+
+// Changed
+func (o *LoadOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *LoadOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithReference
+func (o *LoadOptions) WithReference(value string) *LoadOptions {
+ v := &value
+ o.Reference = v
+ return o
+}
+
+// GetReference
+func (o *LoadOptions) GetReference() string {
+ var reference string
+ if o.Reference == nil {
+ return reference
+ }
+ return *o.Reference
+}
diff --git a/pkg/bindings/images/types_prune_options.go b/pkg/bindings/images/types_prune_options.go
new file mode 100644
index 000000000..c29fdae12
--- /dev/null
+++ b/pkg/bindings/images/types_prune_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.316938584 -0600 CST m=+0.000239843
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PruneOptions) WithAll(value bool) *PruneOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PruneOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go
new file mode 100644
index 000000000..07f3e079d
--- /dev/null
+++ b/pkg/bindings/images/types_pull_options.go
@@ -0,0 +1,281 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ "github.com/containers/common/pkg/config"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:28.164648348 -0600 CST m=+0.000243264
+*/
+
+// Changed
+func (o *PullOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PullOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAllTags
+func (o *PullOptions) WithAllTags(value bool) *PullOptions {
+ v := &value
+ o.AllTags = v
+ return o
+}
+
+// GetAllTags
+func (o *PullOptions) GetAllTags() bool {
+ var allTags bool
+ if o.AllTags == nil {
+ return allTags
+ }
+ return *o.AllTags
+}
+
+// WithAuthfile
+func (o *PullOptions) WithAuthfile(value string) *PullOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *PullOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *PullOptions) WithCertDir(value string) *PullOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *PullOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithUsername
+func (o *PullOptions) WithUsername(value string) *PullOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *PullOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *PullOptions) WithPassword(value string) *PullOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *PullOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithOverrideArch
+func (o *PullOptions) WithOverrideArch(value string) *PullOptions {
+ v := &value
+ o.OverrideArch = v
+ return o
+}
+
+// GetOverrideArch
+func (o *PullOptions) GetOverrideArch() string {
+ var overrideArch string
+ if o.OverrideArch == nil {
+ return overrideArch
+ }
+ return *o.OverrideArch
+}
+
+// WithOverrideOS
+func (o *PullOptions) WithOverrideOS(value string) *PullOptions {
+ v := &value
+ o.OverrideOS = v
+ return o
+}
+
+// GetOverrideOS
+func (o *PullOptions) GetOverrideOS() string {
+ var overrideOS string
+ if o.OverrideOS == nil {
+ return overrideOS
+ }
+ return *o.OverrideOS
+}
+
+// WithOverrideVariant
+func (o *PullOptions) WithOverrideVariant(value string) *PullOptions {
+ v := &value
+ o.OverrideVariant = v
+ return o
+}
+
+// GetOverrideVariant
+func (o *PullOptions) GetOverrideVariant() string {
+ var overrideVariant string
+ if o.OverrideVariant == nil {
+ return overrideVariant
+ }
+ return *o.OverrideVariant
+}
+
+// WithQuiet
+func (o *PullOptions) WithQuiet(value bool) *PullOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *PullOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithSignaturePolicy
+func (o *PullOptions) WithSignaturePolicy(value string) *PullOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *PullOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSkipTLSVerify
+func (o *PullOptions) WithSkipTLSVerify(value bool) *PullOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *PullOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithPullPolicy
+func (o *PullOptions) WithPullPolicy(value config.PullPolicy) *PullOptions {
+ v := &value
+ o.PullPolicy = v
+ return o
+}
+
+// GetPullPolicy
+func (o *PullOptions) GetPullPolicy() config.PullPolicy {
+ var pullPolicy config.PullPolicy
+ if o.PullPolicy == nil {
+ return pullPolicy
+ }
+ return *o.PullPolicy
+}
diff --git a/pkg/bindings/images/types_push_options.go b/pkg/bindings/images/types_push_options.go
new file mode 100644
index 000000000..f9ce1b835
--- /dev/null
+++ b/pkg/bindings/images/types_push_options.go
@@ -0,0 +1,280 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.881232044 -0600 CST m=+0.000242458
+*/
+
+// Changed
+func (o *PushOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PushOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *PushOptions) WithAuthfile(value string) *PushOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *PushOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *PushOptions) WithCertDir(value string) *PushOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *PushOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithCompress
+func (o *PushOptions) WithCompress(value bool) *PushOptions {
+ v := &value
+ o.Compress = v
+ return o
+}
+
+// GetCompress
+func (o *PushOptions) GetCompress() bool {
+ var compress bool
+ if o.Compress == nil {
+ return compress
+ }
+ return *o.Compress
+}
+
+// WithUsername
+func (o *PushOptions) WithUsername(value string) *PushOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *PushOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *PushOptions) WithPassword(value string) *PushOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *PushOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithDigestFile
+func (o *PushOptions) WithDigestFile(value string) *PushOptions {
+ v := &value
+ o.DigestFile = v
+ return o
+}
+
+// GetDigestFile
+func (o *PushOptions) GetDigestFile() string {
+ var digestFile string
+ if o.DigestFile == nil {
+ return digestFile
+ }
+ return *o.DigestFile
+}
+
+// WithFormat
+func (o *PushOptions) WithFormat(value string) *PushOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *PushOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
+
+// WithQuiet
+func (o *PushOptions) WithQuiet(value bool) *PushOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *PushOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithRemoveSignatures
+func (o *PushOptions) WithRemoveSignatures(value bool) *PushOptions {
+ v := &value
+ o.RemoveSignatures = v
+ return o
+}
+
+// GetRemoveSignatures
+func (o *PushOptions) GetRemoveSignatures() bool {
+ var removeSignatures bool
+ if o.RemoveSignatures == nil {
+ return removeSignatures
+ }
+ return *o.RemoveSignatures
+}
+
+// WithSignaturePolicy
+func (o *PushOptions) WithSignaturePolicy(value string) *PushOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *PushOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSignBy
+func (o *PushOptions) WithSignBy(value string) *PushOptions {
+ v := &value
+ o.SignBy = v
+ return o
+}
+
+// GetSignBy
+func (o *PushOptions) GetSignBy() string {
+ var signBy string
+ if o.SignBy == nil {
+ return signBy
+ }
+ return *o.SignBy
+}
+
+// WithSkipTLSVerify
+func (o *PushOptions) WithSkipTLSVerify(value bool) *PushOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *PushOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
diff --git a/pkg/bindings/images/types_remove_options.go b/pkg/bindings/images/types_remove_options.go
new file mode 100644
index 000000000..c9692c2b7
--- /dev/null
+++ b/pkg/bindings/images/types_remove_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.180391541 -0600 CST m=+0.000290244
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *RemoveOptions) WithAll(value bool) *RemoveOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *RemoveOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/images/types_search_options.go b/pkg/bindings/images/types_search_options.go
new file mode 100644
index 000000000..e6168ac33
--- /dev/null
+++ b/pkg/bindings/images/types_search_options.go
@@ -0,0 +1,184 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:28.023569573 -0600 CST m=+0.000245548
+*/
+
+// Changed
+func (o *SearchOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *SearchOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *SearchOptions) WithAuthfile(value string) *SearchOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *SearchOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithFilters
+func (o *SearchOptions) WithFilters(value map[string][]string) *SearchOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *SearchOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithLimit
+func (o *SearchOptions) WithLimit(value int) *SearchOptions {
+ v := &value
+ o.Limit = v
+ return o
+}
+
+// GetLimit
+func (o *SearchOptions) GetLimit() int {
+ var limit int
+ if o.Limit == nil {
+ return limit
+ }
+ return *o.Limit
+}
+
+// WithNoTrunc
+func (o *SearchOptions) WithNoTrunc(value bool) *SearchOptions {
+ v := &value
+ o.NoTrunc = v
+ return o
+}
+
+// GetNoTrunc
+func (o *SearchOptions) GetNoTrunc() bool {
+ var noTrunc bool
+ if o.NoTrunc == nil {
+ return noTrunc
+ }
+ return *o.NoTrunc
+}
+
+// WithSkipTLSVerify
+func (o *SearchOptions) WithSkipTLSVerify(value bool) *SearchOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *SearchOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithListTags
+func (o *SearchOptions) WithListTags(value bool) *SearchOptions {
+ v := &value
+ o.ListTags = v
+ return o
+}
+
+// GetListTags
+func (o *SearchOptions) GetListTags() bool {
+ var listTags bool
+ if o.ListTags == nil {
+ return listTags
+ }
+ return *o.ListTags
+}
diff --git a/pkg/bindings/images/types_tag_options.go b/pkg/bindings/images/types_tag_options.go
new file mode 100644
index 000000000..f6396e590
--- /dev/null
+++ b/pkg/bindings/images/types_tag_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.457906682 -0600 CST m=+0.000245071
+*/
+
+// Changed
+func (o *TagOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TagOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_tree_options.go b/pkg/bindings/images/types_tree_options.go
new file mode 100644
index 000000000..fb2493f85
--- /dev/null
+++ b/pkg/bindings/images/types_tree_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.749625305 -0600 CST m=+0.000267624
+*/
+
+// Changed
+func (o *TreeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TreeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithWhatRequires
+func (o *TreeOptions) WithWhatRequires(value bool) *TreeOptions {
+ v := &value
+ o.WhatRequires = v
+ return o
+}
+
+// GetWhatRequires
+func (o *TreeOptions) GetWhatRequires() bool {
+ var whatRequires bool
+ if o.WhatRequires == nil {
+ return whatRequires
+ }
+ return *o.WhatRequires
+}
diff --git a/pkg/bindings/images/types_untag_options.go b/pkg/bindings/images/types_untag_options.go
new file mode 100644
index 000000000..8faf5c14e
--- /dev/null
+++ b/pkg/bindings/images/types_untag_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.600379913 -0600 CST m=+0.000251449
+*/
+
+// Changed
+func (o *UntagOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UntagOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 0330b13e2..ef4e2a908 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -5,11 +5,9 @@ import (
"errors"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/image/v5/manifest"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
jsoniter "github.com/json-iterator/go"
@@ -19,8 +17,11 @@ import (
// the new manifest can also be specified. The all boolean specifies to add all entries
// of a list if the name provided is a manifest list. The ID of the new manifest list
// is returned as a string.
-func Create(ctx context.Context, names, images []string, all *bool) (string, error) {
+func Create(ctx context.Context, names, images []string, options *CreateOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(CreateOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -28,9 +29,9 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err
if len(names) < 1 {
return "", errors.New("creating a manifest requires at least one name argument")
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
+ params, err := options.ToParams()
+ if err != nil {
+ return "", err
}
for _, name := range names {
params.Add("name", name)
@@ -47,8 +48,12 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err
}
// Inspect returns a manifest list for a given name.
-func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) {
+func Inspect(ctx context.Context, name string, options *InspectOptions) (*manifest.Schema2List, error) {
var list manifest.Schema2List
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -62,8 +67,11 @@ func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) {
// Add adds a manifest to a given manifest list. Additional options for the manifest
// can also be specified. The ID of the new manifest list is returned as a string
-func Add(ctx context.Context, name string, options image.ManifestAddOpts) (string, error) {
+func Add(ctx context.Context, name string, options *AddOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(AddOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -82,8 +90,12 @@ func Add(ctx context.Context, name string, options image.ManifestAddOpts) (strin
// Remove deletes a manifest entry from a manifest list. Both name and the digest to be
// removed are mandatory inputs. The ID of the new manifest list is returned as a string.
-func Remove(ctx context.Context, name, digest string) (string, error) {
+func Remove(ctx context.Context, name, digest string, options *RemoveOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(RemoveOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -100,24 +112,26 @@ func Remove(ctx context.Context, name, digest string) (string, error) {
// Push takes a manifest list and pushes to a destination. If the destination is not specified,
// the name will be used instead. If the optional all boolean is specified, all images specified
// in the list will be pushed as well.
-func Push(ctx context.Context, name string, destination *string, all *bool) (string, error) {
+func Push(ctx context.Context, name, destination string, options *PushOptions) (string, error) {
var (
idr handlers.IDResponse
)
- dest := name
+ if options == nil {
+ options = new(PushOptions)
+ }
+ if len(destination) < 1 {
+ destination = name
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
}
- params := url.Values{}
- params.Set("image", name)
- if destination != nil {
- dest = *destination
- }
- params.Set("destination", dest)
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
+ params, err := options.ToParams()
+ if err != nil {
+ return "", err
}
+ params.Set("image", name)
+ params.Set("destination", destination)
_, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
if err != nil {
return "", err
diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go
new file mode 100644
index 000000000..f5054d424
--- /dev/null
+++ b/pkg/bindings/manifests/types.go
@@ -0,0 +1,36 @@
+package manifests
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting manifests
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating manifests
+type CreateOptions struct {
+ All *bool
+}
+
+//go:generate go run ../generator/generator.go AddOptions
+// AddOptions are optional options for adding manifests
+type AddOptions struct {
+ All *bool
+ Annotation map[string]string
+ Arch *string
+ Features []string
+ Images []string
+ OS *string
+ OSVersion *string
+ Variant *string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing manifests
+type RemoveOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PushOptions
+// RemoveOptions are optional options for pushing manifests
+type PushOptions struct {
+ All *bool
+}
diff --git a/pkg/bindings/manifests/types_add_options.go b/pkg/bindings/manifests/types_add_options.go
new file mode 100644
index 000000000..d45effedc
--- /dev/null
+++ b/pkg/bindings/manifests/types_add_options.go
@@ -0,0 +1,216 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.92237379 -0600 CST m=+0.000150701
+*/
+
+// Changed
+func (o *AddOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *AddOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *AddOptions) WithAll(value bool) *AddOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *AddOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithAnnotation
+func (o *AddOptions) WithAnnotation(value map[string]string) *AddOptions {
+ v := value
+ o.Annotation = v
+ return o
+}
+
+// GetAnnotation
+func (o *AddOptions) GetAnnotation() map[string]string {
+ var annotation map[string]string
+ if o.Annotation == nil {
+ return annotation
+ }
+ return o.Annotation
+}
+
+// WithArch
+func (o *AddOptions) WithArch(value string) *AddOptions {
+ v := &value
+ o.Arch = v
+ return o
+}
+
+// GetArch
+func (o *AddOptions) GetArch() string {
+ var arch string
+ if o.Arch == nil {
+ return arch
+ }
+ return *o.Arch
+}
+
+// WithFeatures
+func (o *AddOptions) WithFeatures(value []string) *AddOptions {
+ v := value
+ o.Features = v
+ return o
+}
+
+// GetFeatures
+func (o *AddOptions) GetFeatures() []string {
+ var features []string
+ if o.Features == nil {
+ return features
+ }
+ return o.Features
+}
+
+// WithImages
+func (o *AddOptions) WithImages(value []string) *AddOptions {
+ v := value
+ o.Images = v
+ return o
+}
+
+// GetImages
+func (o *AddOptions) GetImages() []string {
+ var images []string
+ if o.Images == nil {
+ return images
+ }
+ return o.Images
+}
+
+// WithOS
+func (o *AddOptions) WithOS(value string) *AddOptions {
+ v := &value
+ o.OS = v
+ return o
+}
+
+// GetOS
+func (o *AddOptions) GetOS() string {
+ var oS string
+ if o.OS == nil {
+ return oS
+ }
+ return *o.OS
+}
+
+// WithOSVersion
+func (o *AddOptions) WithOSVersion(value string) *AddOptions {
+ v := &value
+ o.OSVersion = v
+ return o
+}
+
+// GetOSVersion
+func (o *AddOptions) GetOSVersion() string {
+ var oSVersion string
+ if o.OSVersion == nil {
+ return oSVersion
+ }
+ return *o.OSVersion
+}
+
+// WithVariant
+func (o *AddOptions) WithVariant(value string) *AddOptions {
+ v := &value
+ o.Variant = v
+ return o
+}
+
+// GetVariant
+func (o *AddOptions) GetVariant() string {
+ var variant string
+ if o.Variant == nil {
+ return variant
+ }
+ return *o.Variant
+}
diff --git a/pkg/bindings/manifests/types_create_options.go b/pkg/bindings/manifests/types_create_options.go
new file mode 100644
index 000000000..da07f1abf
--- /dev/null
+++ b/pkg/bindings/manifests/types_create_options.go
@@ -0,0 +1,104 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.784206871 -0600 CST m=+0.000157049
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *CreateOptions) WithAll(value bool) *CreateOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *CreateOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/manifests/types_inspect_options.go b/pkg/bindings/manifests/types_inspect_options.go
new file mode 100644
index 000000000..0d32d5bb9
--- /dev/null
+++ b/pkg/bindings/manifests/types_inspect_options.go
@@ -0,0 +1,88 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.631746481 -0600 CST m=+0.000143104
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/manifests/types_push_options.go b/pkg/bindings/manifests/types_push_options.go
new file mode 100644
index 000000000..4226733c9
--- /dev/null
+++ b/pkg/bindings/manifests/types_push_options.go
@@ -0,0 +1,104 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:56.197438009 -0600 CST m=+0.000149060
+*/
+
+// Changed
+func (o *PushOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PushOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PushOptions) WithAll(value bool) *PushOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PushOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/manifests/types_remove_options.go b/pkg/bindings/manifests/types_remove_options.go
new file mode 100644
index 000000000..f99220f6c
--- /dev/null
+++ b/pkg/bindings/manifests/types_remove_options.go
@@ -0,0 +1,88 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:56.059954408 -0600 CST m=+0.000146015
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 347f97703..7cd251b0e 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -2,10 +2,8 @@ package network
import (
"context"
- "encoding/json"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/bindings"
@@ -14,15 +12,18 @@ import (
)
// Create makes a new CNI network configuration
-func Create(ctx context.Context, options entities.NetworkCreateOptions, name *string) (*entities.NetworkCreateReport, error) {
+func Create(ctx context.Context, options *CreateOptions) (*entities.NetworkCreateReport, error) {
var report entities.NetworkCreateReport
+ if options == nil {
+ options = new(CreateOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
- if name != nil {
- params.Set("name", *name)
+ if options.Name != nil {
+ params.Set("name", options.GetName())
}
networkConfig, err := jsoniter.MarshalToString(options)
if err != nil {
@@ -37,8 +38,12 @@ func Create(ctx context.Context, options entities.NetworkCreateOptions, name *st
}
// Inspect returns low level information about a CNI network configuration
-func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectReport, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) ([]entities.NetworkInspectReport, error) {
var reports []entities.NetworkInspectReport
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -53,15 +58,18 @@ func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectRep
// Remove deletes a defined CNI network configuration by name. The optional force boolean
// will remove all containers associated with the network when set to true. A slice
// of NetworkRemoveReports are returned.
-func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.NetworkRmReport, error) {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) ([]*entities.NetworkRmReport, error) {
var reports []*entities.NetworkRmReport
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nil, nameOrID)
if err != nil {
@@ -71,21 +79,20 @@ func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.Netw
}
// List returns a summary of all CNI network configurations
-func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.NetworkListReport, error) {
var (
netList []*entities.NetworkListReport
)
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if options.Filters != nil {
- b, err := json.Marshal(options.Filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", string(b))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", params, nil)
if err != nil {
@@ -95,13 +102,28 @@ func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities
}
// Disconnect removes a container from a given network
-func Disconnect(ctx context.Context, networkName string, options entities.NetworkDisconnectOptions) error {
+func Disconnect(ctx context.Context, networkName string, ContainerNameOrId string, options *DisconnectOptions) error {
+ if options == nil {
+ options = new(DisconnectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
+ // No params are used for disconnect
params := url.Values{}
- body, err := jsoniter.MarshalToString(options)
+ // Disconnect sends everything in body
+ disconnect := struct {
+ Container string
+ Force bool
+ }{
+ Container: ContainerNameOrId,
+ }
+ if force := options.GetForce(); options.Changed("Force") {
+ disconnect.Force = force
+ }
+
+ body, err := jsoniter.MarshalToString(disconnect)
if err != nil {
return err
}
@@ -114,13 +136,27 @@ func Disconnect(ctx context.Context, networkName string, options entities.Networ
}
// Connect adds a container to a network
-func Connect(ctx context.Context, networkName string, options entities.NetworkConnectOptions) error {
+func Connect(ctx context.Context, networkName string, ContainerNameOrId string, options *ConnectOptions) error {
+ if options == nil {
+ options = new(ConnectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
+ // No params are used in connect
params := url.Values{}
- body, err := jsoniter.MarshalToString(options)
+ // Connect sends everything in body
+ connect := struct {
+ Container string
+ Aliases []string
+ }{
+ Container: ContainerNameOrId,
+ }
+ if aliases := options.GetAliases(); options.Changed("Aliases") {
+ connect.Aliases = aliases
+ }
+ body, err := jsoniter.MarshalToString(connect)
if err != nil {
return err
}
diff --git a/pkg/bindings/network/types.go b/pkg/bindings/network/types.go
new file mode 100644
index 000000000..2a7e500dd
--- /dev/null
+++ b/pkg/bindings/network/types.go
@@ -0,0 +1,70 @@
+package network
+
+import "net"
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating networks
+type CreateOptions struct {
+ // DisableDNS turns off use of DNSMasq for name resolution
+ // on the network
+ DisableDNS *bool
+ // Driver is the name of network driver
+ Driver *string
+ // Gateway of the network
+ Gateway *net.IP
+ // Internal turns off communication outside the networking
+ // being created
+ Internal *bool
+ // Labels are metadata that can be associated with the network
+ Labels map[string]string
+ // MacVLAN is the name of the macvlan network to associate with
+ MacVLAN *string
+ // Range is the CIDR description of leasable IP addresses
+ IPRange *net.IPNet `scheme:"range"`
+ // Subnet to use
+ Subnet *net.IPNet
+ // IPv6 means the network is ipv6 capable
+ IPv6 *bool
+ // Options are a mapping of driver options and values.
+ Options map[string]string
+ // Name of the network
+ Name *string
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting networks
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for inspecting networks
+type RemoveOptions struct {
+ // Force removes the network even if it is being used
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing networks
+type ListOptions struct {
+ // Filters are applied to the list of networks to be more
+ // specific on the output
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go DisconnectOptions
+// DisconnectOptions are optional options for disconnecting
+// containers from a network
+type DisconnectOptions struct {
+ // Force indicates to remove the container from
+ // the network forcibly
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go ConnectOptions
+// ConnectOptions are optional options for connecting
+// containers from a network
+type ConnectOptions struct {
+ // Aliases are names the container will be known as
+ // when using the dns plugin
+ Aliases *[]string
+}
diff --git a/pkg/bindings/network/types_connect_options.go b/pkg/bindings/network/types_connect_options.go
new file mode 100644
index 000000000..6fcc4536e
--- /dev/null
+++ b/pkg/bindings/network/types_connect_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:34.075822786 -0600 CST m=+0.000167237
+*/
+
+// Changed
+func (o *ConnectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ConnectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAliases
+func (o *ConnectOptions) WithAliases(value []string) *ConnectOptions {
+ v := &value
+ o.Aliases = v
+ return o
+}
+
+// GetAliases
+func (o *ConnectOptions) GetAliases() []string {
+ var aliases []string
+ if o.Aliases == nil {
+ return aliases
+ }
+ return *o.Aliases
+}
diff --git a/pkg/bindings/network/types_create_options.go b/pkg/bindings/network/types_create_options.go
new file mode 100644
index 000000000..daec6a254
--- /dev/null
+++ b/pkg/bindings/network/types_create_options.go
@@ -0,0 +1,265 @@
+package network
+
+import (
+ "net"
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.37307678 -0600 CST m=+0.000176739
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDisableDNS
+func (o *CreateOptions) WithDisableDNS(value bool) *CreateOptions {
+ v := &value
+ o.DisableDNS = v
+ return o
+}
+
+// GetDisableDNS
+func (o *CreateOptions) GetDisableDNS() bool {
+ var disableDNS bool
+ if o.DisableDNS == nil {
+ return disableDNS
+ }
+ return *o.DisableDNS
+}
+
+// WithDriver
+func (o *CreateOptions) WithDriver(value string) *CreateOptions {
+ v := &value
+ o.Driver = v
+ return o
+}
+
+// GetDriver
+func (o *CreateOptions) GetDriver() string {
+ var driver string
+ if o.Driver == nil {
+ return driver
+ }
+ return *o.Driver
+}
+
+// WithGateway
+func (o *CreateOptions) WithGateway(value net.IP) *CreateOptions {
+ v := &value
+ o.Gateway = v
+ return o
+}
+
+// GetGateway
+func (o *CreateOptions) GetGateway() net.IP {
+ var gateway net.IP
+ if o.Gateway == nil {
+ return gateway
+ }
+ return *o.Gateway
+}
+
+// WithInternal
+func (o *CreateOptions) WithInternal(value bool) *CreateOptions {
+ v := &value
+ o.Internal = v
+ return o
+}
+
+// GetInternal
+func (o *CreateOptions) GetInternal() bool {
+ var internal bool
+ if o.Internal == nil {
+ return internal
+ }
+ return *o.Internal
+}
+
+// WithLabels
+func (o *CreateOptions) WithLabels(value map[string]string) *CreateOptions {
+ v := value
+ o.Labels = v
+ return o
+}
+
+// GetLabels
+func (o *CreateOptions) GetLabels() map[string]string {
+ var labels map[string]string
+ if o.Labels == nil {
+ return labels
+ }
+ return o.Labels
+}
+
+// WithMacVLAN
+func (o *CreateOptions) WithMacVLAN(value string) *CreateOptions {
+ v := &value
+ o.MacVLAN = v
+ return o
+}
+
+// GetMacVLAN
+func (o *CreateOptions) GetMacVLAN() string {
+ var macVLAN string
+ if o.MacVLAN == nil {
+ return macVLAN
+ }
+ return *o.MacVLAN
+}
+
+// WithIPRange
+func (o *CreateOptions) WithIPRange(value net.IPNet) *CreateOptions {
+ v := &value
+ o.IPRange = v
+ return o
+}
+
+// GetIPRange
+func (o *CreateOptions) GetIPRange() net.IPNet {
+ var ipRange net.IPNet
+ if o.IPRange == nil {
+ return ipRange
+ }
+ return *o.IPRange
+}
+
+// WithSubnet
+func (o *CreateOptions) WithSubnet(value net.IPNet) *CreateOptions {
+ v := &value
+ o.Subnet = v
+ return o
+}
+
+// GetSubnet
+func (o *CreateOptions) GetSubnet() net.IPNet {
+ var subnet net.IPNet
+ if o.Subnet == nil {
+ return subnet
+ }
+ return *o.Subnet
+}
+
+// WithIPv6
+func (o *CreateOptions) WithIPv6(value bool) *CreateOptions {
+ v := &value
+ o.IPv6 = v
+ return o
+}
+
+// GetIPv6
+func (o *CreateOptions) GetIPv6() bool {
+ var iPv6 bool
+ if o.IPv6 == nil {
+ return iPv6
+ }
+ return *o.IPv6
+}
+
+// WithOptions
+func (o *CreateOptions) WithOptions(value map[string]string) *CreateOptions {
+ v := value
+ o.Options = v
+ return o
+}
+
+// GetOptions
+func (o *CreateOptions) GetOptions() map[string]string {
+ var options map[string]string
+ if o.Options == nil {
+ return options
+ }
+ return o.Options
+}
+
+// WithName
+func (o *CreateOptions) WithName(value string) *CreateOptions {
+ v := &value
+ o.Name = v
+ return o
+}
+
+// GetName
+func (o *CreateOptions) GetName() string {
+ var name string
+ if o.Name == nil {
+ return name
+ }
+ return *o.Name
+}
diff --git a/pkg/bindings/network/types_disconnect_options.go b/pkg/bindings/network/types_disconnect_options.go
new file mode 100644
index 000000000..821279976
--- /dev/null
+++ b/pkg/bindings/network/types_disconnect_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.936088242 -0600 CST m=+0.000168680
+*/
+
+// Changed
+func (o *DisconnectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DisconnectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *DisconnectOptions) WithForce(value bool) *DisconnectOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *DisconnectOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/network/types_inspect_options.go b/pkg/bindings/network/types_inspect_options.go
new file mode 100644
index 000000000..7704904ce
--- /dev/null
+++ b/pkg/bindings/network/types_inspect_options.go
@@ -0,0 +1,88 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.520438264 -0600 CST m=+0.000172934
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/network/types_list_options.go b/pkg/bindings/network/types_list_options.go
new file mode 100644
index 000000000..bbd2a71db
--- /dev/null
+++ b/pkg/bindings/network/types_list_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.796794129 -0600 CST m=+0.000180368
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/network/types_remove_options.go b/pkg/bindings/network/types_remove_options.go
new file mode 100644
index 000000000..b24835ae4
--- /dev/null
+++ b/pkg/bindings/network/types_remove_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.658228151 -0600 CST m=+0.000172527
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index cfb40d74b..9ee02a093 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -3,18 +3,19 @@ package play
import (
"context"
"net/http"
- "net/url"
"os"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
+ if options == nil {
+ options = new(KubeOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -26,18 +27,19 @@ func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*
}
defer f.Close()
- params := url.Values{}
- params.Set("network", options.Network)
- params.Set("logDriver", options.LogDriver)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
- params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify != types.OptionalBoolTrue))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
+ if options.SkipTLSVerify != nil {
+ params.Set("tlsVerify", strconv.FormatBool(options.GetSkipTLSVerify()))
}
- if options.Start != types.OptionalBoolUndefined {
- params.Set("start", strconv.FormatBool(options.Start == types.OptionalBoolTrue))
+ if options.Start != nil {
+ params.Set("start", strconv.FormatBool(options.GetStart()))
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go
new file mode 100644
index 000000000..5fb9a4d41
--- /dev/null
+++ b/pkg/bindings/play/types.go
@@ -0,0 +1,32 @@
+package play
+
+//go:generate go run ../generator/generator.go KubeOptions
+// KubeOptions are optional options for replaying kube YAML files
+type KubeOptions struct {
+ // Authfile - path to an authentication file.
+ Authfile *string
+ // CertDir - to a directory containing TLS certifications and keys.
+ CertDir *string
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // Network - name of the CNI network to connect to.
+ Network *string
+ // Quiet - suppress output when pulling images.
+ Quiet *bool
+ // SignaturePolicy - path to a signature-policy file.
+ SignaturePolicy *string
+ // SkipTLSVerify - skip https and certificate validation when
+ // contacting container registries.
+ SkipTLSVerify *bool
+ // SeccompProfileRoot - path to a directory containing seccomp
+ // profiles.
+ SeccompProfileRoot *string
+ // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
+ ConfigMaps *[]string
+ // LogDriver for the container. For example: journald
+ LogDriver *string
+ // Start - don't start the pod if false
+ Start *bool
+}
diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go
new file mode 100644
index 000000000..91cdd30aa
--- /dev/null
+++ b/pkg/bindings/play/types_kube_options.go
@@ -0,0 +1,280 @@
+package play
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:02.386833736 -0600 CST m=+0.000171080
+*/
+
+// Changed
+func (o *KubeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KubeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *KubeOptions) WithAuthfile(value string) *KubeOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *KubeOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *KubeOptions) WithCertDir(value string) *KubeOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *KubeOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithUsername
+func (o *KubeOptions) WithUsername(value string) *KubeOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *KubeOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *KubeOptions) WithPassword(value string) *KubeOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *KubeOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithNetwork
+func (o *KubeOptions) WithNetwork(value string) *KubeOptions {
+ v := &value
+ o.Network = v
+ return o
+}
+
+// GetNetwork
+func (o *KubeOptions) GetNetwork() string {
+ var network string
+ if o.Network == nil {
+ return network
+ }
+ return *o.Network
+}
+
+// WithQuiet
+func (o *KubeOptions) WithQuiet(value bool) *KubeOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *KubeOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithSignaturePolicy
+func (o *KubeOptions) WithSignaturePolicy(value string) *KubeOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *KubeOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSkipTLSVerify
+func (o *KubeOptions) WithSkipTLSVerify(value bool) *KubeOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *KubeOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithSeccompProfileRoot
+func (o *KubeOptions) WithSeccompProfileRoot(value string) *KubeOptions {
+ v := &value
+ o.SeccompProfileRoot = v
+ return o
+}
+
+// GetSeccompProfileRoot
+func (o *KubeOptions) GetSeccompProfileRoot() string {
+ var seccompProfileRoot string
+ if o.SeccompProfileRoot == nil {
+ return seccompProfileRoot
+ }
+ return *o.SeccompProfileRoot
+}
+
+// WithConfigMaps
+func (o *KubeOptions) WithConfigMaps(value []string) *KubeOptions {
+ v := &value
+ o.ConfigMaps = v
+ return o
+}
+
+// GetConfigMaps
+func (o *KubeOptions) GetConfigMaps() []string {
+ var configMaps []string
+ if o.ConfigMaps == nil {
+ return configMaps
+ }
+ return *o.ConfigMaps
+}
+
+// WithLogDriver
+func (o *KubeOptions) WithLogDriver(value string) *KubeOptions {
+ v := &value
+ o.LogDriver = v
+ return o
+}
+
+// GetLogDriver
+func (o *KubeOptions) GetLogDriver() string {
+ var logDriver string
+ if o.LogDriver == nil {
+ return logDriver
+ }
+ return *o.LogDriver
+}
+
+// WithStart
+func (o *KubeOptions) WithStart(value bool) *KubeOptions {
+ v := &value
+ o.Start = v
+ return o
+}
+
+// GetStart
+func (o *KubeOptions) GetStart() bool {
+ var start bool
+ if o.Start == nil {
+ return start
+ }
+ return *o.Start
+}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index c3f98eaab..4fcaf81f1 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -2,10 +2,8 @@ package pods
import (
"context"
- "errors"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/api/handlers"
@@ -15,10 +13,14 @@ import (
jsoniter "github.com/json-iterator/go"
)
-func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator) (*entities.PodCreateReport, error) {
+func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator, options *CreateOptions) (*entities.PodCreateReport, error) {
var (
pcr entities.PodCreateReport
)
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -49,10 +51,14 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
}
// Inspect returns low-level information about the given pod.
-func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*entities.PodInspectReport, error) {
var (
report entities.PodInspectReport
)
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -66,17 +72,20 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport,
// Kill sends a SIGTERM to all the containers in a pod. The optional signal parameter
// can be used to override SIGTERM.
-func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKillReport, error) {
+func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities.PodKillReport, error) {
var (
report entities.PodKillReport
)
+ if options == nil {
+ options = new(KillOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if signal != nil {
- params.Set("signal", *signal)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nil, nameOrID)
if err != nil {
@@ -86,8 +95,12 @@ func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKi
}
// Pause pauses all running containers in a given pod.
-func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, error) {
+func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entities.PodPauseReport, error) {
var report entities.PodPauseReport
+ if options == nil {
+ options = new(PauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -101,8 +114,12 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro
// Prune by default removes all non-running pods in local storage.
// And with force set true removes all pods.
-func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*entities.PodPruneReport, error) {
var reports []*entities.PodPruneReport
+ if options == nil {
+ options = new(PruneOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -116,21 +133,20 @@ func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
// List returns all pods in local storage. The optional filters parameter can
// be used to refine which pods should be listed.
-func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPodsReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.ListPodsReport, error) {
var (
podsReports []*entities.ListPodsReport
)
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if filters != nil {
- stringFilter, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", stringFilter)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params, nil)
if err != nil {
@@ -140,8 +156,12 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPod
}
// Restart restarts all containers in a pod.
-func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport, error) {
+func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*entities.PodRestartReport, error) {
var report entities.PodRestartReport
+ if options == nil {
+ options = new(RestartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -155,15 +175,18 @@ func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport,
// Remove deletes a Pod from from local storage. The optional force parameter denotes
// that the Pod can be removed even if in a running state.
-func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmReport, error) {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*entities.PodRmReport, error) {
var report entities.PodRmReport
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nil, nameOrID)
if err != nil {
@@ -173,8 +196,12 @@ func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmR
}
// Start starts all containers in a pod.
-func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, error) {
+func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entities.PodStartReport, error) {
var report entities.PodStartReport
+ if options == nil {
+ options = new(StartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -192,15 +219,18 @@ func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, erro
// Stop stops all containers in a Pod. The optional timeout parameter can be
// used to override the timeout before the container is killed.
-func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStopReport, error) {
+func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities.PodStopReport, error) {
var report entities.PodStopReport
+ if options == nil {
+ options = new(StopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if timeout != nil {
- params.Set("t", strconv.Itoa(*timeout))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nil, nameOrID)
if err != nil {
@@ -215,15 +245,16 @@ func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStop
// Top gathers statistics about the running processes in a pod. The nameOrID can be a pod name
// or a partial/full ID. The descriptors allow for specifying which data to collect from each process.
-func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, error) {
+func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, error) {
+ if options == nil {
+ options = new(TopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
-
- if len(descriptors) > 0 {
- // flatten the slice into one string
+ if descriptors := options.GetDescriptors(); len(descriptors) > 0 {
params.Set("ps_args", strings.Join(descriptors, ","))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nil, nameOrID)
@@ -248,7 +279,11 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
}
// Unpause unpauses all paused containers in a Pod.
-func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport, error) {
+func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*entities.PodUnpauseReport, error) {
+ if options == nil {
+ options = new(UnpauseOptions)
+ }
+ _ = options
var report entities.PodUnpauseReport
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -262,19 +297,21 @@ func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport,
}
// Stats display resource-usage statistics of one or more pods.
-func Stats(ctx context.Context, namesOrIDs []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
- if options.Latest {
- return nil, errors.New("latest is not supported")
+func Stats(ctx context.Context, namesOrIDs []string, options *StatsOptions) ([]*entities.PodStatsReport, error) {
+ if options == nil {
+ options = new(StatsOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
for _, i := range namesOrIDs {
params.Add("namesOrIDs", i)
}
- params.Set("all", strconv.FormatBool(options.All))
var reports []*entities.PodStatsReport
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params, nil)
diff --git a/pkg/bindings/pods/types.go b/pkg/bindings/pods/types.go
new file mode 100644
index 000000000..370c1aaa9
--- /dev/null
+++ b/pkg/bindings/pods/types.go
@@ -0,0 +1,72 @@
+package pods
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating pods
+type CreateOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting pods
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go KillOptions
+// KillOptions are optional options for killing pods
+type KillOptions struct {
+ Signal *string
+}
+
+//go:generate go run ../generator/generator.go PauseOptions
+// PauseOptions are optional options for pausing pods
+type PauseOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning pods
+type PruneOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing pods
+type ListOptions struct {
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RestartOptions
+// RestartOptions are optional options for restarting pods
+type RestartOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StartOptions
+// StartOptions are optional options for starting pods
+type StartOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StopOptions
+// StopOptions are optional options for stopping pods
+type StopOptions struct {
+ Timeout *int
+}
+
+//go:generate go run ../generator/generator.go TopOptions
+// TopOptions are optional options for getting top on pods
+type TopOptions struct {
+ Descriptors []string
+}
+
+//go:generate go run ../generator/generator.go UnpauseOptions
+// UnpauseOptions are optional options for unpausinging pods
+type UnpauseOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StatsOptions
+// StatsOptions are optional options for getting stats of pods
+type StatsOptions struct {
+ All *bool
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing pods
+type RemoveOptions struct {
+ Force *bool
+}
diff --git a/pkg/bindings/pods/types_create_options.go b/pkg/bindings/pods/types_create_options.go
new file mode 100644
index 000000000..b6cf0fc53
--- /dev/null
+++ b/pkg/bindings/pods/types_create_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.05490508 -0600 CST m=+0.000156396
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_inspect_options.go b/pkg/bindings/pods/types_inspect_options.go
new file mode 100644
index 000000000..1c881ce9c
--- /dev/null
+++ b/pkg/bindings/pods/types_inspect_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.258801519 -0600 CST m=+0.000175055
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_kill_options.go b/pkg/bindings/pods/types_kill_options.go
new file mode 100644
index 000000000..cb5bdfd01
--- /dev/null
+++ b/pkg/bindings/pods/types_kill_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.398857339 -0600 CST m=+0.000160135
+*/
+
+// Changed
+func (o *KillOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KillOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSignal
+func (o *KillOptions) WithSignal(value string) *KillOptions {
+ v := &value
+ o.Signal = v
+ return o
+}
+
+// GetSignal
+func (o *KillOptions) GetSignal() string {
+ var signal string
+ if o.Signal == nil {
+ return signal
+ }
+ return *o.Signal
+}
diff --git a/pkg/bindings/pods/types_list_options.go b/pkg/bindings/pods/types_list_options.go
new file mode 100644
index 000000000..d095bf3db
--- /dev/null
+++ b/pkg/bindings/pods/types_list_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.818123838 -0600 CST m=+0.000164328
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/pods/types_pause_options.go b/pkg/bindings/pods/types_pause_options.go
new file mode 100644
index 000000000..06ee6f81d
--- /dev/null
+++ b/pkg/bindings/pods/types_pause_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.538407099 -0600 CST m=+0.000193274
+*/
+
+// Changed
+func (o *PauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_prune_options.go b/pkg/bindings/pods/types_prune_options.go
new file mode 100644
index 000000000..6610aa7cc
--- /dev/null
+++ b/pkg/bindings/pods/types_prune_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.678507342 -0600 CST m=+0.000183891
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_remove_options.go b/pkg/bindings/pods/types_remove_options.go
new file mode 100644
index 000000000..8f18e43c9
--- /dev/null
+++ b/pkg/bindings/pods/types_remove_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.80320679 -0600 CST m=+0.000158149
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/pods/types_restart_options.go b/pkg/bindings/pods/types_restart_options.go
new file mode 100644
index 000000000..9030de1e7
--- /dev/null
+++ b/pkg/bindings/pods/types_restart_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.958315383 -0600 CST m=+0.000168360
+*/
+
+// Changed
+func (o *RestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_start_options.go b/pkg/bindings/pods/types_start_options.go
new file mode 100644
index 000000000..0fce21099
--- /dev/null
+++ b/pkg/bindings/pods/types_start_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.099102916 -0600 CST m=+0.000159629
+*/
+
+// Changed
+func (o *StartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_stats_options.go b/pkg/bindings/pods/types_stats_options.go
new file mode 100644
index 000000000..d38a9a115
--- /dev/null
+++ b/pkg/bindings/pods/types_stats_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.658228243 -0600 CST m=+0.000160769
+*/
+
+// Changed
+func (o *StatsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StatsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *StatsOptions) WithAll(value bool) *StatsOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *StatsOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/pods/types_stop_options.go b/pkg/bindings/pods/types_stop_options.go
new file mode 100644
index 000000000..ac698b8c5
--- /dev/null
+++ b/pkg/bindings/pods/types_stop_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.237892781 -0600 CST m=+0.000155040
+*/
+
+// Changed
+func (o *StopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *StopOptions) WithTimeout(value int) *StopOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *StopOptions) GetTimeout() int {
+ var timeout int
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/pods/types_top_options.go b/pkg/bindings/pods/types_top_options.go
new file mode 100644
index 000000000..895f62957
--- /dev/null
+++ b/pkg/bindings/pods/types_top_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.375876994 -0600 CST m=+0.000154839
+*/
+
+// Changed
+func (o *TopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDescriptors
+func (o *TopOptions) WithDescriptors(value []string) *TopOptions {
+ v := value
+ o.Descriptors = v
+ return o
+}
+
+// GetDescriptors
+func (o *TopOptions) GetDescriptors() []string {
+ var descriptors []string
+ if o.Descriptors == nil {
+ return descriptors
+ }
+ return o.Descriptors
+}
diff --git a/pkg/bindings/pods/types_unpause_options.go b/pkg/bindings/pods/types_unpause_options.go
new file mode 100644
index 000000000..3d647cf25
--- /dev/null
+++ b/pkg/bindings/pods/types_unpause_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.515225789 -0600 CST m=+0.000158667
+*/
+
+// Changed
+func (o *UnpauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnpauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/info.go b/pkg/bindings/system/info.go
index 79ee5cada..798010333 100644
--- a/pkg/bindings/system/info.go
+++ b/pkg/bindings/system/info.go
@@ -9,7 +9,11 @@ import (
)
// Info returns information about the libpod environment and its stores
-func Info(ctx context.Context) (*define.Info, error) {
+func Info(ctx context.Context, options *InfoOptions) (*define.Info, error) {
+ if options == nil {
+ options = new(InfoOptions)
+ }
+ _ = options
info := define.Info{}
conn, err := bindings.GetClient(ctx)
if err != nil {
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index 1203f5c3c..815c967f1 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -6,8 +6,6 @@ import (
"fmt"
"io"
"net/http"
- "net/url"
- "strconv"
"time"
"github.com/containers/podman/v2/libpod/define"
@@ -20,27 +18,14 @@ import (
// Events allows you to monitor libdpod related events like container creation and
// removal. The events are then passed to the eventChan provided. The optional cancelChan
// can be used to cancel the read of events and close down the HTTP connection.
-func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan bool, since, until *string, filters map[string][]string, stream *bool) error {
+func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan bool, options *EventsOptions) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if since != nil {
- params.Set("since", *since)
- }
- if until != nil {
- params.Set("until", *until)
- }
- if stream != nil {
- params.Set("stream", strconv.FormatBool(*stream))
- }
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return errors.Wrap(err, "invalid filters")
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/events", params, nil)
if err != nil {
@@ -74,7 +59,7 @@ func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan
}
// Prune removes all unused system data.
-func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) (*entities.SystemPruneReport, error) {
var (
report entities.SystemPruneReport
)
@@ -82,12 +67,9 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("All", strconv.FormatBool(*all))
- }
- if volumes != nil {
- params.Set("Volumes", strconv.FormatBool(*volumes))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params, nil)
if err != nil {
@@ -96,10 +78,15 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport
return &report, response.Process(&report)
}
-func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
- var report entities.SystemVersionReport
- var component entities.ComponentVersion
-
+func Version(ctx context.Context, options *VersionOptions) (*entities.SystemVersionReport, error) {
+ var (
+ component entities.ComponentVersion
+ report entities.SystemVersionReport
+ )
+ if options == nil {
+ options = new(VersionOptions)
+ }
+ _ = options
version, err := define.GetVersion()
if err != nil {
return nil, err
@@ -140,8 +127,12 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
// DiskUsage returns information about image, container, and volume disk
// consumption
-func DiskUsage(ctx context.Context) (*entities.SystemDfReport, error) {
+func DiskUsage(ctx context.Context, options *DiskOptions) (*entities.SystemDfReport, error) {
var report entities.SystemDfReport
+ if options == nil {
+ options = new(DiskOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/system/types.go b/pkg/bindings/system/types.go
new file mode 100644
index 000000000..16960b817
--- /dev/null
+++ b/pkg/bindings/system/types.go
@@ -0,0 +1,34 @@
+package system
+
+//go:generate go run ../generator/generator.go EventsOptions
+// EventsOptions are optional options for monitoring events
+type EventsOptions struct {
+ Filters map[string][]string
+ Since *string
+ Stream *bool
+ Until *string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning
+type PruneOptions struct {
+ All *bool
+ Filters map[string][]string
+ Volumes *bool
+}
+
+//go:generate go run ../generator/generator.go VersionOptions
+// VersionOptions are optional options for getting version info
+type VersionOptions struct {
+}
+
+//go:generate go run ../generator/generator.go DiskOptions
+// DiskOptions are optional options for getting storage consumption
+type DiskOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InfoOptions
+// InfoOptions are optional options for getting info
+// about libpod
+type InfoOptions struct {
+}
diff --git a/pkg/bindings/system/types_disk_options.go b/pkg/bindings/system/types_disk_options.go
new file mode 100644
index 000000000..f7d2cca06
--- /dev/null
+++ b/pkg/bindings/system/types_disk_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:08.087362343 -0600 CST m=+0.000150636
+*/
+
+// Changed
+func (o *DiskOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiskOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/types_events_options.go b/pkg/bindings/system/types_events_options.go
new file mode 100644
index 000000000..6dd64b055
--- /dev/null
+++ b/pkg/bindings/system/types_events_options.go
@@ -0,0 +1,152 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.675150173 -0600 CST m=+0.000140977
+*/
+
+// Changed
+func (o *EventsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *EventsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *EventsOptions) WithFilters(value map[string][]string) *EventsOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *EventsOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithSince
+func (o *EventsOptions) WithSince(value string) *EventsOptions {
+ v := &value
+ o.Since = v
+ return o
+}
+
+// GetSince
+func (o *EventsOptions) GetSince() string {
+ var since string
+ if o.Since == nil {
+ return since
+ }
+ return *o.Since
+}
+
+// WithStream
+func (o *EventsOptions) WithStream(value bool) *EventsOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *EventsOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
+
+// WithUntil
+func (o *EventsOptions) WithUntil(value string) *EventsOptions {
+ v := &value
+ o.Until = v
+ return o
+}
+
+// GetUntil
+func (o *EventsOptions) GetUntil() string {
+ var until string
+ if o.Until == nil {
+ return until
+ }
+ return *o.Until
+}
diff --git a/pkg/bindings/system/types_info_options.go b/pkg/bindings/system/types_info_options.go
new file mode 100644
index 000000000..3a8960e1b
--- /dev/null
+++ b/pkg/bindings/system/types_info_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:08.233760126 -0600 CST m=+0.000142369
+*/
+
+// Changed
+func (o *InfoOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InfoOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/types_prune_options.go b/pkg/bindings/system/types_prune_options.go
new file mode 100644
index 000000000..2cd3c8000
--- /dev/null
+++ b/pkg/bindings/system/types_prune_options.go
@@ -0,0 +1,136 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.812719858 -0600 CST m=+0.000143214
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PruneOptions) WithAll(value bool) *PruneOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PruneOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithVolumes
+func (o *PruneOptions) WithVolumes(value bool) *PruneOptions {
+ v := &value
+ o.Volumes = v
+ return o
+}
+
+// GetVolumes
+func (o *PruneOptions) GetVolumes() bool {
+ var volumes bool
+ if o.Volumes == nil {
+ return volumes
+ }
+ return *o.Volumes
+}
diff --git a/pkg/bindings/system/types_version_options.go b/pkg/bindings/system/types_version_options.go
new file mode 100644
index 000000000..4974e8d8f
--- /dev/null
+++ b/pkg/bindings/system/types_version_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.950759332 -0600 CST m=+0.000140376
+*/
+
+// Changed
+func (o *VersionOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *VersionOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go
index 12e51e734..9a46f6309 100644
--- a/pkg/bindings/test/attach_test.go
+++ b/pkg/bindings/test/attach_test.go
@@ -6,7 +6,6 @@ import (
"time"
"github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/specgen"
. "github.com/onsi/ginkgo"
@@ -43,7 +42,7 @@ var _ = Describe("Podman containers attach", func() {
go func() {
<-tickTock.C
timeout := uint(5)
- err := containers.Stop(bt.conn, id, &timeout)
+ err := containers.Stop(bt.conn, id, new(containers.StopOptions).WithTimeout(timeout))
if err != nil {
GinkgoWriter.Write([]byte(err.Error()))
}
@@ -53,8 +52,8 @@ var _ = Describe("Podman containers attach", func() {
stderr := &bytes.Buffer{}
go func() {
defer GinkgoRecover()
-
- err := containers.Attach(bt.conn, id, nil, bindings.PTrue, bindings.PTrue, nil, stdout, stderr, nil)
+ options := new(containers.AttachOptions).WithLogs(true).WithStream(true)
+ err := containers.Attach(bt.conn, id, nil, stdout, stderr, nil, options)
Expect(err).ShouldNot(HaveOccurred())
}()
@@ -69,21 +68,21 @@ var _ = Describe("Podman containers attach", func() {
s.Name = "CatAttachTest"
s.Terminal = true
s.Command = []string{"/bin/cat"}
- ctnr, err := containers.CreateWithSpec(bt.conn, s)
+ ctnr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).ShouldNot(HaveOccurred())
err = containers.Start(bt.conn, ctnr.ID, nil)
Expect(err).ShouldNot(HaveOccurred())
wait := define.ContainerStateRunning
- _, err = containers.Wait(bt.conn, ctnr.ID, &wait)
+ _, err = containers.Wait(bt.conn, ctnr.ID, new(containers.WaitOptions).WithCondition(wait))
Expect(err).ShouldNot(HaveOccurred())
tickTock := time.NewTimer(2 * time.Second)
go func() {
<-tickTock.C
timeout := uint(5)
- err := containers.Stop(bt.conn, ctnr.ID, &timeout)
+ err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(timeout))
if err != nil {
GinkgoWriter.Write([]byte(err.Error()))
}
@@ -97,8 +96,8 @@ var _ = Describe("Podman containers attach", func() {
stderr := &bytes.Buffer{}
go func() {
defer GinkgoRecover()
-
- err := containers.Attach(bt.conn, ctnr.ID, nil, bindings.PFalse, bindings.PTrue, stdin, stdout, stderr, nil)
+ options := new(containers.AttachOptions).WithStream(true)
+ err := containers.Attach(bt.conn, ctnr.ID, stdin, stdout, stderr, nil, options)
Expect(err).ShouldNot(HaveOccurred())
}()
diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go
index 4565b82b0..e647b3c36 100644
--- a/pkg/bindings/test/auth_test.go
+++ b/pkg/bindings/test/auth_test.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/image/v5/types"
podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go"
"github.com/containers/podman/v2/pkg/bindings/images"
- "github.com/containers/podman/v2/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -52,27 +51,19 @@ var _ = Describe("Podman images", func() {
imageRef := imageRep + ":" + imageTag
// Tag the alpine image and verify it has worked.
- err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
- pushOpts := entities.ImagePushOptions{
- Username: registry.User,
- Password: registry.Password,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ pushOpts := new(images.PushOptions)
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
- pullOpts := entities.ImagePullOptions{
- Username: registry.User,
- Password: registry.Password,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ pullOpts := new(images.PullOptions)
+ _, err = images.Pull(bt.conn, imageRef, pullOpts.WithSkipTLSVerify(true).WithPassword(registry.Password).WithUsername(registry.User))
Expect(err).To(BeNil())
})
@@ -110,33 +101,24 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
// Tag the alpine image and verify it has worked.
- err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
- pushOpts := entities.ImagePushOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ pushOpts := new(images.PushOptions)
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
- pullOpts := entities.ImagePullOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ pullOpts := new(images.PullOptions)
+ _, err = images.Pull(bt.conn, imageRef, pullOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Last, but not least, exercise search.
- searchOptions := entities.ImageSearchOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Search(bt.conn, imageRef, searchOptions)
+ searchOptions := new(images.SearchOptions)
+ _, err = images.Search(bt.conn, imageRef, searchOptions.WithSkipTLSVerify(true).WithAuthfile(authFilePath))
Expect(err).To(BeNil())
})
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 9dff2985f..232d7136f 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -198,7 +198,7 @@ func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, po
if insidePod != nil && podName != nil {
s.Pod = *podName
}
- ctr, err := containers.CreateWithSpec(b.conn, s)
+ ctr, err := containers.CreateWithSpec(b.conn, s, nil)
if err != nil {
return "", nil
}
@@ -207,7 +207,7 @@ func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, po
return "", err
}
wait := define.ContainerStateRunning
- _, err = containers.Wait(b.conn, ctr.ID, &wait)
+ _, err = containers.Wait(b.conn, ctr.ID, new(containers.WaitOptions).WithCondition(wait))
return ctr.ID, err
}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 15066ff1a..fa601e7e5 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -37,7 +38,7 @@ var _ = Describe("Podman containers ", func() {
It("podman pause a bogus container", func() {
// Pausing bogus container should return 404
- err = containers.Pause(bt.conn, "foobar")
+ err = containers.Pause(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -45,7 +46,7 @@ var _ = Describe("Podman containers ", func() {
It("podman unpause a bogus container", func() {
// Unpausing bogus container should return 404
- err = containers.Unpause(bt.conn, "foobar")
+ err = containers.Unpause(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -56,7 +57,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is paused
@@ -70,7 +71,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
// Ensure container is paused
@@ -84,9 +85,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is unpaused
@@ -101,11 +102,11 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Pause by name
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
//paused := "paused"
//_, err = containers.Wait(bt.conn, cid, &paused)
//Expect(err).To(BeNil())
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is unpaused
@@ -119,9 +120,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -132,9 +133,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -147,7 +148,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -160,7 +161,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -171,9 +172,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Remove(bt.conn, cid, bindings.PFalse, bindings.PFalse)
+ err = containers.Remove(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -184,9 +185,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Remove(bt.conn, cid, bindings.PTrue, bindings.PFalse)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
})
@@ -195,7 +196,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
@@ -208,7 +209,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
@@ -280,11 +281,11 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, nil, nil)
Expect(err).To(BeNil())
go func() {
- exitCode, err = containers.Wait(bt.conn, name, &pause)
+ exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(pause))
errChan <- err
close(errChan)
}()
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
wait := <-errChan
Expect(wait).To(BeNil())
@@ -294,11 +295,11 @@ var _ = Describe("Podman containers ", func() {
go func() {
defer GinkgoRecover()
- _, waitErr := containers.Wait(bt.conn, name, &running)
+ _, waitErr := containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(running))
unpauseErrChan <- waitErr
close(unpauseErrChan)
}()
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
unPausewait := <-unpauseErrChan
Expect(unPausewait).To(BeNil())
@@ -309,7 +310,7 @@ var _ = Describe("Podman containers ", func() {
bt.runPodman([]string{"run", "-d", "--name", "hc", "--health-interval", "disable", "--health-retries", "2", "--health-cmd", "ls / || exit 1", alpine.name, "top"})
// bogus name should result in 404
- _, err := containers.RunHealthCheck(bt.conn, "foobar")
+ _, err := containers.RunHealthCheck(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -317,7 +318,7 @@ var _ = Describe("Podman containers ", func() {
// a container that has no healthcheck should be a 409
var name = "top"
bt.RunTopContainer(&name, bindings.PFalse, nil)
- _, err = containers.RunHealthCheck(bt.conn, name)
+ _, err = containers.RunHealthCheck(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusConflict))
@@ -355,7 +356,7 @@ var _ = Describe("Podman containers ", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
s.Terminal = true
s.Command = []string{"date", "-R"}
- r, err := containers.CreateWithSpec(bt.conn, s)
+ r, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
err = containers.Start(bt.conn, r.ID, nil)
Expect(err).To(BeNil())
@@ -363,7 +364,7 @@ var _ = Describe("Podman containers ", func() {
_, err = containers.Wait(bt.conn, r.ID, nil)
Expect(err).To(BeNil())
- opts := containers.LogOptions{Stdout: bindings.PTrue, Follow: bindings.PTrue}
+ opts := new(containers.LogOptions).WithStdout(true).WithFollow(true)
go func() {
containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil)
}()
@@ -387,7 +388,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
// With descriptors
- output, err := containers.Top(bt.conn, cid, []string{"user,pid,hpid"})
+ output, err := containers.Top(bt.conn, cid, new(containers.TopOptions).WithDescriptors([]string{"user", "pid", "hpid"}))
Expect(err).To(BeNil())
header := strings.Split(output[0], "\t")
for _, d := range []string{"USER", "PID", "HPID"} {
@@ -399,7 +400,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).ToNot(BeNil())
// With bogus descriptors
- _, err = containers.Top(bt.conn, cid, []string{"Me,Neither"})
+ _, err = containers.Top(bt.conn, cid, new(containers.TopOptions).WithDescriptors([]string{"Me,Neither"}))
Expect(err).To(BeNil())
})
@@ -442,7 +443,7 @@ var _ = Describe("Podman containers ", func() {
It("podman kill bogus container", func() {
// Killing bogus container should return 404
- err := containers.Kill(bt.conn, "foobar", "SIGTERM")
+ err := containers.Kill(bt.conn, "foobar", "SIGTERM", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -453,7 +454,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, name, "SIGINT")
+ err = containers.Kill(bt.conn, name, "SIGINT", nil)
Expect(err).To(BeNil())
_, err = containers.Exists(bt.conn, name, false)
Expect(err).To(BeNil())
@@ -464,7 +465,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "SIGTERM")
+ err = containers.Kill(bt.conn, cid, "SIGTERM", nil)
Expect(err).To(BeNil())
_, err = containers.Exists(bt.conn, cid, false)
Expect(err).To(BeNil())
@@ -475,7 +476,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "SIGKILL")
+ err = containers.Kill(bt.conn, cid, "SIGKILL", nil)
Expect(err).To(BeNil())
})
@@ -484,7 +485,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "foobar")
+ err = containers.Kill(bt.conn, cid, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -494,19 +495,18 @@ var _ = Describe("Podman containers ", func() {
// Killing latest container should work
var name1 = "first"
var name2 = "second"
- var latestContainers = 1
_, err := bt.RunTopContainer(&name1, bindings.PFalse, nil)
Expect(err).To(BeNil())
_, err = bt.RunTopContainer(&name2, bindings.PFalse, nil)
Expect(err).To(BeNil())
- containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
+ containerLatestList, err := containers.List(bt.conn, new(containers.ListOptions).WithLast(1))
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM")
+ err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM", nil)
Expect(err).To(BeNil())
})
It("container init on a bogus container", func() {
- err := containers.ContainerInit(bt.conn, "doesnotexist")
+ err := containers.ContainerInit(bt.conn, "doesnotexist", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -514,12 +514,12 @@ var _ = Describe("Podman containers ", func() {
It("container init", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
- ctr, err := containers.CreateWithSpec(bt.conn, s)
+ ctr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
- err = containers.ContainerInit(bt.conn, ctr.ID)
+ err = containers.ContainerInit(bt.conn, ctr.ID, nil)
Expect(err).To(BeNil())
// trying to init again should be an error
- err = containers.ContainerInit(bt.conn, ctr.ID)
+ err = containers.ContainerInit(bt.conn, ctr.ID, nil)
Expect(err).ToNot(BeNil())
})
@@ -534,8 +534,8 @@ var _ = Describe("Podman containers ", func() {
// Prune container should return no errors and one pruned container ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune stopped containers with filters", func() {
@@ -550,26 +550,26 @@ var _ = Describe("Podman containers ", func() {
filtersIncorrect := map[string][]string{
"status": {"dummy"},
}
- pruneResponse, err := containers.Prune(bt.conn, filtersIncorrect)
+ pruneResponse, err := containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).ToNot(BeNil())
// Mismatched filter params no container should be pruned.
filtersIncorrect = map[string][]string{
"name": {"r"},
}
- pruneResponse, err = containers.Prune(bt.conn, filtersIncorrect)
+ pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
// Valid filter params container should be pruned now.
filters := map[string][]string{
"name": {"top"},
}
- pruneResponse, err = containers.Prune(bt.conn, filters)
+ pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune running containers", func() {
@@ -586,7 +586,7 @@ var _ = Describe("Podman containers ", func() {
// Prune. Should return no error no prune response ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(pruneResponse)).To(Equal(0))
})
It("podman inspect bogus container", func() {
@@ -620,7 +620,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- _, err = containers.Inspect(bt.conn, name, bindings.PTrue)
+ _, err = containers.Inspect(bt.conn, name, new(containers.InspectOptions).WithSize(true))
Expect(err).To(BeNil())
})
@@ -631,12 +631,12 @@ var _ = Describe("Podman containers ", func() {
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
// Inspecting stopped container with size should succeed
- _, err = containers.Inspect(bt.conn, name, bindings.PTrue)
+ _, err = containers.Inspect(bt.conn, name, new(containers.InspectOptions).WithSize(true))
Expect(err).To(BeNil())
})
It("podman remove bogus container", func() {
- err = containers.Remove(bt.conn, "foobar", nil, nil)
+ err = containers.Remove(bt.conn, "foobar", nil)
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
})
@@ -646,7 +646,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, nil, nil)
+ err = containers.Remove(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -657,7 +657,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, nil, nil)
+ err = containers.Remove(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -668,7 +668,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, bindings.PTrue, nil)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -679,7 +679,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, bindings.PTrue, nil)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -690,7 +690,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, nil, bindings.PTrue)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true))
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -701,7 +701,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, nil, bindings.PTrue)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithVolumes(true))
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -712,7 +712,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, bindings.PTrue, bindings.PTrue)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -723,7 +723,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, bindings.PTrue, bindings.PTrue)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true).WithVolumes(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -739,12 +739,12 @@ var _ = Describe("Podman containers ", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
s.Terminal = true
s.Command = []string{"date", "-R"}
- _, err = containers.CreateWithSpec(bt.conn, s)
+ _, err = containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
// Validate list container with id filter
filters := make(map[string][]string)
filters["id"] = []string{cid}
- c, err := containers.List(bt.conn, filters, bindings.PTrue, nil, nil, nil, nil)
+ c, err := containers.List(bt.conn, new(containers.ListOptions).WithFilters(filters).WithAll(true))
Expect(err).To(BeNil())
Expect(len(c)).To(Equal(1))
})
@@ -758,7 +758,7 @@ var _ = Describe("Podman containers ", func() {
lastNum := 1
- c, err := containers.List(bt.conn, nil, bindings.PTrue, &lastNum, nil, nil, nil)
+ c, err := containers.List(bt.conn, new(containers.ListOptions).WithAll(true).WithLast(lastNum))
Expect(err).To(BeNil())
Expect(len(c)).To(Equal(1))
Expect(c[0].PodName).To(Equal(podName))
diff --git a/pkg/bindings/test/create_test.go b/pkg/bindings/test/create_test.go
index fd9ce23ca..2d2d657de 100644
--- a/pkg/bindings/test/create_test.go
+++ b/pkg/bindings/test/create_test.go
@@ -35,7 +35,7 @@ var _ = Describe("Create containers ", func() {
s.Command = []string{"top"}
s.Terminal = true
s.Name = "top"
- ctr, err := containers.CreateWithSpec(bt.conn, s)
+ ctr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
data, err := containers.Inspect(bt.conn, ctr.ID, nil)
Expect(err).To(BeNil())
diff --git a/pkg/bindings/test/exec_test.go b/pkg/bindings/test/exec_test.go
index e3d90b9ea..8e20a192f 100644
--- a/pkg/bindings/test/exec_test.go
+++ b/pkg/bindings/test/exec_test.go
@@ -43,7 +43,7 @@ var _ = Describe("Podman containers exec", func() {
Expect(err).To(BeNil())
Expect(sessionID).To(Not(Equal("")))
- inspectOut, err := containers.ExecInspect(bt.conn, sessionID)
+ inspectOut, err := containers.ExecInspect(bt.conn, sessionID, nil)
Expect(err).To(BeNil())
Expect(inspectOut.ContainerID).To(Equal(cid))
Expect(inspectOut.ProcessConfig.Entrypoint).To(Equal("echo"))
@@ -71,7 +71,7 @@ var _ = Describe("Podman containers exec", func() {
})
It("Podman exec inspect on invalid session fails", func() {
- _, err := containers.ExecInspect(bt.conn, "0000000000000000000000000000000000000000000000000000000000000000")
+ _, err := containers.ExecInspect(bt.conn, "0000000000000000000000000000000000000000000000000000000000000000", nil)
Expect(err).To(Not(BeNil()))
})
})
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 7d9415f91..c6b9c20f9 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,7 +9,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/images"
- "github.com/containers/podman/v2/pkg/domain/entities"
+ dreports "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -71,12 +71,13 @@ var _ = Describe("Podman images", func() {
// Inspect by long name
_, err = images.GetImage(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
- // TODO it looks like the images API alwaays returns size regardless
+ // TODO it looks like the images API always returns size regardless
// of bool or not. What should we do ?
// Expect(data.Size).To(BeZero())
+ options := new(images.GetOptions).WithSize(true)
// Enabling the size parameter should result in size being populated
- data, err = images.GetImage(bt.conn, alpine.name, bindings.PTrue)
+ data, err = images.GetImage(bt.conn, alpine.name, options)
Expect(err).To(BeNil())
Expect(data.Size).To(BeNumerically(">", 0))
})
@@ -84,23 +85,19 @@ var _ = Describe("Podman images", func() {
// Test to validate the remove image api
It("remove image", func() {
// Remove invalid image should be a 404
- response, err := images.Remove(bt.conn, "foobar5000", false)
- Expect(err).ToNot(BeNil())
- Expect(response).To(BeNil())
- code, _ := bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
+ response, errs := images.Remove(bt.conn, []string{"foobar5000"}, nil)
+ Expect(len(errs)).To(BeNumerically(">", 0))
+ code, _ := bindings.CheckResponseCode(errs[0])
// Remove an image by name, validate image is removed and error is nil
inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
Expect(err).To(BeNil())
- response, err = images.Remove(bt.conn, busybox.shortName, false)
- Expect(err).To(BeNil())
- code, _ = bindings.CheckResponseCode(err)
+ response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil)
+ Expect(len(errs)).To(BeZero())
Expect(inspectData.ID).To(Equal(response.Deleted[0]))
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Start a container with alpine image
var top string = "top"
@@ -113,23 +110,21 @@ var _ = Describe("Podman images", func() {
// try to remove the image "alpine". This should fail since we are not force
// deleting hence image cannot be deleted until the container is deleted.
- response, err = images.Remove(bt.conn, alpine.shortName, false)
- code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusConflict))
+ response, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil)
+ code, _ = bindings.CheckResponseCode(errs[0])
// Removing the image "alpine" where force = true
- response, err = images.Remove(bt.conn, alpine.shortName, true)
- Expect(err).To(BeNil())
+ options := new(images.RemoveOptions).WithForce(true)
+ response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
+ Expect(len(errs)).To(BeZero())
// To be extra sure, check if the previously created container
// is gone as well.
- _, err = containers.Inspect(bt.conn, "top", bindings.PFalse)
+ _, err = containers.Inspect(bt.conn, "top", nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Now make sure both images are gone.
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
@@ -138,14 +133,15 @@ var _ = Describe("Podman images", func() {
// Tests to validate the image tag command.
It("tag image", func() {
+
// Validates if invalid image name is given a bad response is encountered.
- err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName)
+ err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Validates if the image is tagged successfully.
- err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName)
+ err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil)
Expect(err).To(BeNil())
// Validates if name updates when the image is retagged.
@@ -157,7 +153,7 @@ var _ = Describe("Podman images", func() {
// Test to validate the List images command.
It("List image", func() {
// Array to hold the list of images returned
- imageSummary, err := images.List(bt.conn, nil, nil)
+ imageSummary, err := images.List(bt.conn, nil)
// There Should be no errors in the response.
Expect(err).To(BeNil())
// Since in the begin context two images are created the
@@ -167,7 +163,7 @@ var _ = Describe("Podman images", func() {
// Adding one more image. There Should be no errors in the response.
// And the count should be three now.
bt.Pull("testimage:20200929")
- imageSummary, err = images.List(bt.conn, nil, nil)
+ imageSummary, err = images.List(bt.conn, nil)
Expect(err).To(BeNil())
Expect(len(imageSummary)).To(Equal(3))
@@ -182,13 +178,15 @@ var _ = Describe("Podman images", func() {
// List images with a filter
filters := make(map[string][]string)
filters["reference"] = []string{alpine.name}
- filteredImages, err := images.List(bt.conn, bindings.PFalse, filters)
+ options := new(images.ListOptions).WithFilters(filters).WithAll(false)
+ filteredImages, err := images.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredImages)).To(BeNumerically("==", 1))
// List images with a bad filter
filters["name"] = []string{alpine.name}
- _, err = images.List(bt.conn, bindings.PFalse, filters)
+ options = new(images.ListOptions).WithFilters(filters)
+ _, err = images.List(bt.conn, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -213,8 +211,8 @@ var _ = Describe("Podman images", func() {
It("Load|Import Image", func() {
// load an image
- _, err := images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
@@ -231,13 +229,14 @@ var _ = Describe("Podman images", func() {
// load with a repo name
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil())
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
newName := "quay.io/newname:fizzle"
- names, err = images.Load(bt.conn, f, &newName)
+ options := new(images.LoadOptions).WithReference(newName)
+ names, err = images.Load(bt.conn, f, options)
Expect(err).To(BeNil())
Expect(names.Names[0]).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, newName)
@@ -247,13 +246,13 @@ var _ = Describe("Podman images", func() {
// load with a bad repo name should trigger a 500
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil())
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
- badName := "quay.io/newName:fizzle"
- _, err = images.Load(bt.conn, f, &badName)
+ options = new(images.LoadOptions).WithReference("quay.io/newName:fizzle")
+ _, err = images.Load(bt.conn, f, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -265,7 +264,7 @@ var _ = Describe("Podman images", func() {
w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName))
defer w.Close()
Expect(err).To(BeNil())
- err = images.Export(bt.conn, alpine.name, w, nil, nil)
+ err = images.Export(bt.conn, []string{alpine.name}, w, nil)
Expect(err).To(BeNil())
_, err = os.Stat(exportPath)
Expect(err).To(BeNil())
@@ -275,8 +274,8 @@ var _ = Describe("Podman images", func() {
It("Import Image", func() {
// load an image
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
@@ -285,7 +284,8 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
changes := []string{"CMD /bin/foobar"}
testMessage := "test_import"
- _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f)
+ options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name)
+ _, err = images.Import(bt.conn, f, options)
Expect(err).To(BeNil())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
@@ -298,7 +298,7 @@ var _ = Describe("Podman images", func() {
It("History Image", func() {
// a bogus name should return a 404
- _, err := images.History(bt.conn, "foobar")
+ _, err := images.History(bt.conn, "foobar", nil)
Expect(err).To(Not(BeNil()))
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -306,7 +306,7 @@ var _ = Describe("Podman images", func() {
var foundID bool
data, err := images.GetImage(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
- history, err := images.History(bt.conn, alpine.name)
+ history, err := images.History(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
for _, i := range history {
if i.ID == data.ID {
@@ -318,7 +318,7 @@ var _ = Describe("Podman images", func() {
})
It("Search for an image", func() {
- reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{})
+ reports, err := images.Search(bt.conn, "alpine", nil)
Expect(err).To(BeNil())
Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool
@@ -331,35 +331,39 @@ var _ = Describe("Podman images", func() {
Expect(foundAlpine).To(BeTrue())
// Search for alpine with a limit of 10
- reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10})
+ options := new(images.SearchOptions).WithLimit(10)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", options)
Expect(err).To(BeNil())
Expect(len(reports)).To(BeNumerically("<=", 10))
+ filters := make(map[string][]string)
+ filters["stars"] = []string{"100"}
// Search for alpine with stars greater than 100
- reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}})
+ options = new(images.SearchOptions).WithFilters(filters)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", options)
Expect(err).To(BeNil())
for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100))
}
// Search with a fqdn
- reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{})
+ reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil)
Expect(len(reports)).To(BeNumerically(">=", 1))
})
It("Prune images", func() {
- trueBoxed := true
- results, err := images.Prune(bt.conn, &trueBoxed, nil)
+ options := new(images.PruneOptions).WithAll(true)
+ results, err := images.Prune(bt.conn, options)
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0))
- Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
+ Expect(dreports.PruneReportsIds(results)).To(ContainElement("docker.io/library/alpine:latest"))
})
// TODO: we really need to extent to pull tests once we have a more sophisticated CI.
It("Image Pull", func() {
rawImage := "docker.io/library/busybox:latest"
- pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{})
+ pulledImages, err := images.Pull(bt.conn, rawImage, nil)
Expect(err).NotTo(HaveOccurred())
Expect(len(pulledImages)).To(Equal(1))
@@ -368,11 +372,11 @@ var _ = Describe("Podman images", func() {
Expect(exists).To(BeTrue())
// Make sure the normalization AND the full-transport reference works.
- _, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{})
+ _, err = images.Pull(bt.conn, "docker://"+rawImage, nil)
Expect(err).NotTo(HaveOccurred())
// The v2 endpoint only supports the docker transport. Let's see if that's really true.
- _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{})
+ _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil)
Expect(err).To(HaveOccurred())
})
})
diff --git a/pkg/bindings/test/info_test.go b/pkg/bindings/test/info_test.go
index 6cd5d6724..4d696b59e 100644
--- a/pkg/bindings/test/info_test.go
+++ b/pkg/bindings/test/info_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman info", func() {
var (
bt *bindingTest
s *gexec.Session
- t bool = true
)
BeforeEach(func() {
@@ -35,23 +34,24 @@ var _ = Describe("Podman info", func() {
})
It("podman info", func() {
- info, err := system.Info(bt.conn)
+ info, err := system.Info(bt.conn, nil)
Expect(err).To(BeNil())
Expect(info.Host.Arch).To(Equal(runtime.GOARCH))
Expect(info.Host.OS).To(Equal(runtime.GOOS))
- i, err := images.List(bt.conn, &t, nil)
+ listOptions := new(images.ListOptions)
+ i, err := images.List(bt.conn, listOptions.WithAll(true))
Expect(err).To(BeNil())
Expect(info.Store.ImageStore.Number).To(Equal(len(i)))
})
It("podman info container counts", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
- _, err := containers.CreateWithSpec(bt.conn, s)
+ _, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
idPause, err := bt.RunTopContainer(nil, nil, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, idPause)
+ err = containers.Pause(bt.conn, idPause, nil)
Expect(err).To(BeNil())
idStop, err := bt.RunTopContainer(nil, nil, nil)
@@ -62,7 +62,7 @@ var _ = Describe("Podman info", func() {
_, err = bt.RunTopContainer(nil, nil, nil)
Expect(err).To(BeNil())
- info, err := system.Info(bt.conn)
+ info, err := system.Info(bt.conn, nil)
Expect(err).To(BeNil())
Expect(info.Store.ContainerStore.Number).To(BeNumerically("==", 4))
diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go
index 55fc4cb0d..b93f64b4b 100644
--- a/pkg/bindings/test/manifests_test.go
+++ b/pkg/bindings/test/manifests_test.go
@@ -4,7 +4,6 @@ import (
"net/http"
"time"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/bindings/manifests"
@@ -37,7 +36,7 @@ var _ = Describe("Podman containers ", func() {
// create manifest list without images
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
Expect(err).To(BeNil())
- list, err := manifests.Inspect(bt.conn, id)
+ list, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeZero())
@@ -47,19 +46,19 @@ var _ = Describe("Podman containers ", func() {
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
- _, err = images.Remove(bt.conn, id, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{id}, nil)
+ Expect(len(errs)).To(BeZero())
// create manifest list with images
id, err = manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil)
Expect(err).To(BeNil())
- list, err = manifests.Inspect(bt.conn, id)
+ list, err = manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeNumerically("==", 1))
})
It("inspect bogus manifest", func() {
- _, err := manifests.Inspect(bt.conn, "larry")
+ _, err := manifests.Inspect(bt.conn, "larry", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -67,23 +66,23 @@ var _ = Describe("Podman containers ", func() {
It("add manifest", func() {
// add to bogus should 404
- _, err := manifests.Add(bt.conn, "foobar", image.ManifestAddOpts{})
+ _, err := manifests.Add(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
Expect(err).To(BeNil())
- opts := image.ManifestAddOpts{Images: []string{alpine.name}}
- _, err = manifests.Add(bt.conn, id, opts)
+ options := new(manifests.AddOptions).WithImages([]string{alpine.name})
+ _, err = manifests.Add(bt.conn, id, options)
Expect(err).To(BeNil())
- list, err := manifests.Inspect(bt.conn, id)
+ list, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeNumerically("==", 1))
// add bogus name to existing list should fail
- opts.Images = []string{"larry"}
- _, err = manifests.Add(bt.conn, id, opts)
+ options.WithImages([]string{"larry"})
+ _, err = manifests.Add(bt.conn, id, options)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -91,29 +90,29 @@ var _ = Describe("Podman containers ", func() {
It("remove manifest", func() {
// removal on bogus manifest list should be 404
- _, err := manifests.Remove(bt.conn, "larry", "1234")
+ _, err := manifests.Remove(bt.conn, "larry", "1234", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil)
Expect(err).To(BeNil())
- data, err := manifests.Inspect(bt.conn, id)
+ data, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(data.Manifests)).To(BeNumerically("==", 1))
// removal on a good manifest list with a bad digest should be 400
- _, err = manifests.Remove(bt.conn, id, "!234")
+ _, err = manifests.Remove(bt.conn, id, "!234", nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusBadRequest))
digest := data.Manifests[0].Digest.String()
- _, err = manifests.Remove(bt.conn, id, digest)
+ _, err = manifests.Remove(bt.conn, id, digest, nil)
Expect(err).To(BeNil())
// removal on good manifest with good digest should work
- data, err = manifests.Inspect(bt.conn, id)
+ data, err = manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(data.Manifests)).To(BeZero())
})
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 8498de020..38c5997ef 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -40,13 +40,13 @@ var _ = Describe("Podman pods", func() {
It("inspect pod", func() {
//Inspect an invalid pod name
- _, err := pods.Inspect(bt.conn, "dummyname")
+ _, err := pods.Inspect(bt.conn, "dummyname", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
//Inspect an valid pod name
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.Name).To(Equal(newpod))
})
@@ -59,7 +59,7 @@ var _ = Describe("Podman pods", func() {
Expect(len(podSummary)).To(Equal(1))
// Start the pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Adding an alpine container to the existing pod
@@ -90,7 +90,7 @@ var _ = Describe("Podman pods", func() {
bt.Podcreate(&newpod2)
// Start the pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = bt.RunTopContainer(nil, bindings.PTrue, &newpod)
@@ -99,7 +99,8 @@ var _ = Describe("Podman pods", func() {
// Expected err with invalid filter params
filters := make(map[string][]string)
filters["dummy"] = []string{"dummy"}
- filteredPods, err := pods.List(bt.conn, filters)
+ options := new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err := pods.List(bt.conn, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -107,14 +108,16 @@ var _ = Describe("Podman pods", func() {
// Expected empty response with invalid filters
filters = make(map[string][]string)
filters["name"] = []string{"dummy"}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 0))
// Validate list pod with name filter
filters = make(map[string][]string)
filters["name"] = []string{newpod2}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
var names []string
@@ -125,11 +128,12 @@ var _ = Describe("Podman pods", func() {
// Validate list pod with id filter
filters = make(map[string][]string)
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
id := response.ID
filters["id"] = []string{id}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
names = names[:0]
@@ -140,7 +144,8 @@ var _ = Describe("Podman pods", func() {
// Using multiple filters
filters["name"] = []string{newpod}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
names = names[:0]
@@ -164,11 +169,11 @@ var _ = Describe("Podman pods", func() {
// This test validates if All running containers within
// each specified pod are paused and unpaused
- It("pause upause pod", func() {
+ It("pause unpause pod", func() {
// TODO fix this
Skip("Pod behavior is jacked right now.")
// Pause invalid container
- _, err := pods.Pause(bt.conn, "dummyName")
+ _, err := pods.Pause(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -180,9 +185,9 @@ var _ = Describe("Podman pods", func() {
// Binding needs to be modified to inspect the pod state.
// Since we don't have a pod state we inspect the states of the containers within the pod.
// Pause a valid container
- _, err = pods.Pause(bt.conn, newpod)
+ _, err = pods.Pause(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStatePaused))
for _, i := range response.Containers {
@@ -191,9 +196,9 @@ var _ = Describe("Podman pods", func() {
}
// Unpause a valid container
- _, err = pods.Unpause(bt.conn, newpod)
+ _, err = pods.Unpause(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod)
+ response, err = pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
@@ -204,7 +209,7 @@ var _ = Describe("Podman pods", func() {
It("start stop restart pod", func() {
// Start an invalid pod
- _, err = pods.Start(bt.conn, "dummyName")
+ _, err = pods.Start(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -216,16 +221,16 @@ var _ = Describe("Podman pods", func() {
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Restart an invalid pod
- _, err = pods.Restart(bt.conn, "dummyName")
+ _, err = pods.Restart(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Start a valid pod and inspect status of each container
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
@@ -234,13 +239,13 @@ var _ = Describe("Podman pods", func() {
}
// Start an already running pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Stop the running pods
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, _ = pods.Inspect(bt.conn, newpod)
+ response, _ = pods.Inspect(bt.conn, newpod, nil)
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
@@ -251,9 +256,9 @@ var _ = Describe("Podman pods", func() {
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- _, err = pods.Restart(bt.conn, newpod)
+ _, err = pods.Restart(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, _ = pods.Inspect(bt.conn, newpod)
+ response, _ = pods.Inspect(bt.conn, newpod, nil)
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
@@ -267,7 +272,7 @@ var _ = Describe("Podman pods", func() {
var newpod2 string = "newpod2"
bt.Podcreate(&newpod2)
// No pods pruned since no pod in exited state
- pruneResponse, err := pods.Prune(bt.conn)
+ pruneResponse, err := pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
podSummary, err := pods.List(bt.conn, nil)
Expect(err).To(BeNil())
@@ -276,14 +281,14 @@ var _ = Describe("Podman pods", func() {
// Prune only one pod which is in exited state.
// Start then stop a pod.
// pod moves to exited state one pod should be pruned now.
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
- pruneResponse, err = pods.Prune(bt.conn)
+ pruneResponse, err = pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
// Validate status and record pod id of pod to be pruned
Expect(response.State).To(Equal(define.PodStateExited))
@@ -298,13 +303,13 @@ var _ = Describe("Podman pods", func() {
// Test prune multiple pods.
bt.Podcreate(&newpod)
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- _, err = pods.Start(bt.conn, newpod2)
+ _, err = pods.Start(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod)
+ response, err = pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
@@ -313,14 +318,14 @@ var _ = Describe("Podman pods", func() {
}
_, err = pods.Stop(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod2)
+ response, err = pods.Inspect(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateExited))
}
- _, err = pods.Prune(bt.conn)
+ _, err = pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
podSummary, err = pods.List(bt.conn, nil)
Expect(err).To(BeNil())
@@ -330,7 +335,7 @@ var _ = Describe("Podman pods", func() {
It("simple create pod", func() {
ps := specgen.PodSpecGenerator{}
ps.Name = "foobar"
- _, err := pods.CreatePodFromSpec(bt.conn, &ps)
+ _, err := pods.CreatePodFromSpec(bt.conn, &ps, nil)
Expect(err).To(BeNil())
exists, err := pods.Exists(bt.conn, "foobar")
@@ -343,7 +348,7 @@ var _ = Describe("Podman pods", func() {
var name string = "podA"
bt.Podcreate(&name)
- _, err := pods.Start(bt.conn, name)
+ _, err := pods.Start(bt.conn, name, nil)
Expect(err).To(BeNil())
// By name
@@ -351,7 +356,8 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
// With descriptors
- output, err := pods.Top(bt.conn, name, []string{"user,pid,hpid"})
+ options := new(pods.TopOptions).WithDescriptors([]string{"user,pid,hpid"})
+ output, err := pods.Top(bt.conn, name, options)
Expect(err).To(BeNil())
header := strings.Split(output[0], "\t")
for _, d := range []string{"USER", "PID", "HPID"} {
@@ -363,7 +369,8 @@ var _ = Describe("Podman pods", func() {
Expect(err).ToNot(BeNil())
// With bogus descriptors
- _, err = pods.Top(bt.conn, name, []string{"Me,Neither"})
+ options = new(pods.TopOptions).WithDescriptors([]string{"Me,Neither"})
+ _, err = pods.Top(bt.conn, name, options)
Expect(err).ToNot(BeNil())
})
})
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 82e5c7541..44067b61d 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/system"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -56,8 +57,8 @@ var _ = Describe("Podman system", func() {
eventCounter++
}
}()
-
- err = system.Events(bt.conn, binChan, nil, nil, nil, filters, bindings.PFalse)
+ options := new(system.EventsOptions).WithFilters(filters).WithStream(false)
+ err = system.Events(bt.conn, binChan, nil, options)
Expect(err).To(BeNil())
done.Lock()
Expect(eventCounter).To(BeNumerically(">", 0))
@@ -65,7 +66,7 @@ var _ = Describe("Podman system", func() {
It("podman system prune - pod,container stopped", func() {
// Start and stop a pod to enter in exited state.
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
@@ -76,20 +77,21 @@ var _ = Describe("Podman system", func() {
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PFalse)
+ options := new(system.PruneOptions).WithAll(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
To(ContainElement("docker.io/library/alpine:latest"))
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container", func() {
// Start and stop a pod to enter in exited state.
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
@@ -107,25 +109,25 @@ var _ = Describe("Podman system", func() {
Expect(err).To(BeNil())
// Adding an unused volume
- _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
-
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PFalse)
+ options := new(system.PruneOptions).WithAll(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Though unused volume is available it should not be pruned as flag set to false.
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container volume prune", func() {
// Start a pod and leave it running
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Start and stop a container to enter in exited state.
@@ -141,19 +143,77 @@ var _ = Describe("Podman system", func() {
Expect(err).To(BeNil())
// Adding an unused volume should work
- _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PTrue)
+ options := new(system.PruneOptions).WithAll(true).WithVolumes(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Volume should be pruned now as flag set true
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
+ })
+
+ It("podman system prune running alpine container volume prune --filter", func() {
+ // Start a pod and leave it running
+ _, err := pods.Start(bt.conn, newpod, nil)
+ Expect(err).To(BeNil())
+
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Start second container and leave in running
+ var name2 = "top2"
+ _, err = bt.RunTopContainer(&name2, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume with label should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }}, nil)
+ Expect(err).To(BeNil())
+
+ f := make(map[string][]string)
+ f["label"] = []string{"label1=idontmatch"}
+
+ options := new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
+ Expect(err).To(BeNil())
+ Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
+ // TODO fix system filter handling so all components can handle filters
+ // This check **should** be "Equal(0)" since we are passing label
+ // filters however the Prune function doesn't seem to pass filters
+ // to each component.
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
+ To(BeNumerically(">", 0))
+ // Alpine image should not be pruned as used by running container
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
+ ToNot(ContainElement("docker.io/library/alpine:latest"))
+ // Volume shouldn't be pruned because the PruneOptions filters doesn't match
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
+
+ // Fix filter and re prune
+ f["label"] = []string{"label1=value1"}
+ options = new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ systemPruneResponse, err = system.Prune(bt.conn, options)
+ Expect(err).To(BeNil())
+
+ // Volume should be pruned because the PruneOptions filters now match
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
})
})
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index dc90d4d00..1f1da3cfa 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -52,7 +53,7 @@ var _ = Describe("Podman volumes", func() {
It("create volume", func() {
// create a volume with blank config should work
- _, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
vcc := entities.VolumeCreateOptions{
@@ -60,21 +61,21 @@ var _ = Describe("Podman volumes", func() {
Label: nil,
Options: nil,
}
- vol, err := volumes.Create(connText, vcc)
+ vol, err := volumes.Create(connText, vcc, nil)
Expect(err).To(BeNil())
Expect(vol.Name).To(Equal("foobar"))
// create volume with same name should 500
- _, err = volumes.Create(connText, vcc)
+ _, err = volumes.Create(connText, vcc, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
})
It("inspect volume", func() {
- vol, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- data, err := volumes.Inspect(connText, vol.Name)
+ data, err := volumes.Inspect(connText, vol.Name, nil)
Expect(err).To(BeNil())
Expect(data.Name).To(Equal(vol.Name))
})
@@ -86,13 +87,13 @@ var _ = Describe("Podman volumes", func() {
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Removing an unused volume should work
- vol, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
err = volumes.Remove(connText, vol.Name, nil)
Expect(err).To(BeNil())
// Removing a volume that is being used without force should be 409
- vol, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/foobar", vol.Name), "--name", "vtest", alpine.name, "top"})
session.Wait(45)
@@ -102,10 +103,10 @@ var _ = Describe("Podman volumes", func() {
Expect(code).To(BeNumerically("==", http.StatusConflict))
// Removing with a volume in use with force should work with a stopped container
- zero := uint(0)
- err = containers.Stop(connText, "vtest", &zero)
+ err = containers.Stop(connText, "vtest", new(containers.StopOptions).WithTimeout(0))
Expect(err).To(BeNil())
- err = volumes.Remove(connText, vol.Name, bindings.PTrue)
+ options := new(volumes.RemoveOptions).WithForce(true)
+ err = volumes.Remove(connText, vol.Name, options)
Expect(err).To(BeNil())
})
@@ -118,7 +119,7 @@ var _ = Describe("Podman volumes", func() {
// create a bunch of named volumes and make verify with list
volNames := []string{"homer", "bart", "lisa", "maggie", "marge"}
for i := 0; i < 5; i++ {
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: volNames[i]})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: volNames[i]}, nil)
Expect(err).To(BeNil())
}
vols, err = volumes.List(connText, nil)
@@ -131,43 +132,81 @@ var _ = Describe("Podman volumes", func() {
// list with bad filter should be 500
filters := make(map[string][]string)
filters["foobar"] = []string{"1234"}
- _, err = volumes.List(connText, filters)
+ options := new(volumes.ListOptions).WithFilters(filters)
+ _, err = volumes.List(connText, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
filters = make(map[string][]string)
filters["name"] = []string{"homer"}
- vols, err = volumes.List(connText, filters)
+ options = new(volumes.ListOptions).WithFilters(filters)
+ vols, err = volumes.List(connText, options)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
Expect(vols[0].Name).To(Equal("homer"))
})
- // TODO we need to add filtering to tests
It("prune unused volume", func() {
// Pruning when no volumes present should be ok
- _, err := volumes.Prune(connText)
+ _, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
// Removing an unused volume should work
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- vols, err := volumes.Prune(connText)
+ vols, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: "homer"})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: "homer"}, nil)
Expect(err).To(BeNil())
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/homer", "homer"), "--name", "vtest", alpine.name, "top"})
session.Wait(45)
- vols, err = volumes.Prune(connText)
+ vols, err = volumes.Prune(connText, nil)
+ Expect(err).To(BeNil())
+ Expect(len(reports.PruneReportsIds(vols))).To(BeNumerically("==", 1))
+ _, err = volumes.Inspect(connText, "homer", nil)
+ Expect(err).To(BeNil())
+
+ // Removing volume with non matching filter shouldn't prune any volumes
+ filters := make(map[string][]string)
+ filters["label"] = []string{"label1=idontmatch"}
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }}, nil)
+ Expect(err).To(BeNil())
+ options := new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
+ Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 0))
+ vol2, err := volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value2",
+ }}, nil)
+ Expect(err).To(BeNil())
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value3",
+ }}, nil)
+ Expect(err).To(BeNil())
+
+ // Removing volume with matching filter label and value should remove specific entry
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1=value2"}
+ options = new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
- _, err = volumes.Inspect(connText, "homer")
+ Expect(vols[0].Id).To(Equal(vol2.Name))
+
+ // Removing volumes with matching filter label should remove all matching volumes
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1"}
+ options = new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 2))
})
})
diff --git a/pkg/bindings/volumes/types.go b/pkg/bindings/volumes/types.go
new file mode 100644
index 000000000..379174e33
--- /dev/null
+++ b/pkg/bindings/volumes/types.go
@@ -0,0 +1,32 @@
+package volumes
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating volumes
+type CreateOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting volumes
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing volumes
+type ListOptions struct {
+ // Filters applied to the listing of volumes
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning volumes
+type PruneOptions struct {
+ // Filters applied to the pruning of volumes
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing volumes
+type RemoveOptions struct {
+ // Force removes the volume even if it is being used
+ Force *bool
+}
diff --git a/pkg/bindings/volumes/types_create_options.go b/pkg/bindings/volumes/types_create_options.go
new file mode 100644
index 000000000..80bdac2d2
--- /dev/null
+++ b/pkg/bindings/volumes/types_create_options.go
@@ -0,0 +1,88 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.043860791 -0600 CST m=+0.000188944
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/volumes/types_inspect_options.go b/pkg/bindings/volumes/types_inspect_options.go
new file mode 100644
index 000000000..ba8c70b63
--- /dev/null
+++ b/pkg/bindings/volumes/types_inspect_options.go
@@ -0,0 +1,88 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.189902005 -0600 CST m=+0.000151439
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/volumes/types_list_options.go b/pkg/bindings/volumes/types_list_options.go
new file mode 100644
index 000000000..99dec132c
--- /dev/null
+++ b/pkg/bindings/volumes/types_list_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.326721724 -0600 CST m=+0.000172471
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/volumes/types_prune_options.go b/pkg/bindings/volumes/types_prune_options.go
new file mode 100644
index 000000000..cdbc03fc9
--- /dev/null
+++ b/pkg/bindings/volumes/types_prune_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.463307398 -0600 CST m=+0.000180868
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/volumes/types_remove_options.go b/pkg/bindings/volumes/types_remove_options.go
new file mode 100644
index 000000000..923d1353c
--- /dev/null
+++ b/pkg/bindings/volumes/types_remove_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.60278922 -0600 CST m=+0.000134408
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index 00f1e5720..fe081eb46 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -3,20 +3,23 @@ package volumes
import (
"context"
"net/http"
- "net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
jsoniter "github.com/json-iterator/go"
)
// Create creates a volume given its configuration.
-func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities.VolumeConfigResponse, error) {
+func Create(ctx context.Context, config entities.VolumeCreateOptions, options *CreateOptions) (*entities.VolumeConfigResponse, error) {
var (
v entities.VolumeConfigResponse
)
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -34,10 +37,14 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities
}
// Inspect returns low-level information about a volume.
-func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigResponse, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*entities.VolumeConfigResponse, error) {
var (
inspect entities.VolumeConfigResponse
)
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -51,7 +58,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigRespon
// List returns the configurations for existing volumes in the form of a slice. Optionally, filters
// can be used to refine the list of volumes.
-func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeListReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListReport, error) {
var (
vols []*entities.VolumeListReport
)
@@ -59,13 +66,9 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
if err != nil {
return nil, err
}
- params := url.Values{}
- if len(filters) > 0 {
- strFilters, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", strFilters)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params, nil)
if err != nil {
@@ -75,15 +78,19 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
}
// Prune removes unused volumes from the local filesystem.
-func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- pruned []*entities.VolumePruneReport
+ pruned []*reports.PruneReport
)
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil, nil)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", params, nil)
if err != nil {
return nil, err
}
@@ -92,14 +99,14 @@ func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
// Remove deletes the given volume from storage. The optional force parameter
// is used to remove a volume even if it is being used by a container.
-func Remove(ctx context.Context, nameOrID string, force *bool) error {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nil, nameOrID)
if err != nil {
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 0d7ed05b2..c200dd01a 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -22,7 +22,7 @@ import (
var (
// ErrCgroupDeleted means the cgroup was deleted
ErrCgroupDeleted = errors.New("cgroup deleted")
- // ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environmen
+ // ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environment
ErrCgroupV1Rootless = errors.New("no support for CGroups V1 in rootless environments")
)
diff --git a/pkg/copy/copy.go b/pkg/copy/copy.go
deleted file mode 100644
index 13893deb2..000000000
--- a/pkg/copy/copy.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package copy
-
-import (
- "io"
- "os"
- "path/filepath"
- "strings"
-
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/storage/pkg/archive"
- securejoin "github.com/cyphar/filepath-securejoin"
- "github.com/pkg/errors"
-)
-
-// ********************************* NOTE *************************************
-//
-// Most security bugs are caused by attackers playing around with symlinks
-// trying to escape from the container onto the host and/or trick into data
-// corruption on the host. Hence, file operations on containers (including
-// *stat) should always be handled by `github.com/containers/buildah/copier`
-// which makes sure to evaluate files in a chroot'ed environment.
-//
-// Please make sure to add verbose comments when changing code to make the
-// lives of future readers easier.
-//
-// ****************************************************************************
-
-// Copier copies data from a source to a destination CopyItem.
-type Copier struct {
- copyFunc func() error
- cleanUpFuncs []deferFunc
-}
-
-// cleanUp releases resources the Copier may hold open.
-func (c *Copier) cleanUp() {
- for _, f := range c.cleanUpFuncs {
- f()
- }
-}
-
-// Copy data from a source to a destination CopyItem.
-func (c *Copier) Copy() error {
- defer c.cleanUp()
- return c.copyFunc()
-}
-
-// GetCopiers returns a Copier to copy the source item to destination. Use
-// extract to untar the source if it's a tar archive.
-func GetCopier(source *CopyItem, destination *CopyItem, extract bool) (*Copier, error) {
- copier := &Copier{}
-
- // First, do the man-page dance. See podman-cp(1) for details.
- if err := enforceCopyRules(source, destination); err != nil {
- return nil, err
- }
-
- // Destination is a stream (e.g., stdout or an http body).
- if destination.info.IsStream {
- // Source is a stream (e.g., stdin or an http body).
- if source.info.IsStream {
- copier.copyFunc = func() error {
- _, err := io.Copy(destination.writer, source.reader)
- return err
- }
- return copier, nil
- }
- root, glob, err := source.buildahGlobs()
- if err != nil {
- return nil, err
- }
- copier.copyFunc = func() error {
- return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer)
- }
- return copier, nil
- }
-
- // Destination is either a file or a directory.
- if source.info.IsStream {
- copier.copyFunc = func() error {
- return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader)
- }
- return copier, nil
- }
-
- tarOptions := &archive.TarOptions{
- Compression: archive.Uncompressed,
- CopyPass: true,
- }
-
- root := destination.root
- dir := destination.resolved
- if !source.info.IsDir {
- // When copying a file, make sure to rename the
- // destination base path.
- nameMap := make(map[string]string)
- nameMap[filepath.Base(source.resolved)] = filepath.Base(destination.resolved)
- tarOptions.RebaseNames = nameMap
- dir = filepath.Dir(dir)
- }
-
- var tarReader io.ReadCloser
- if extract && archive.IsArchivePath(source.resolved) {
- if !destination.info.IsDir {
- return nil, errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original)
- }
-
- reader, err := os.Open(source.resolved)
- if err != nil {
- return nil, err
- }
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
-
- // The stream from stdin may be compressed (e.g., via gzip).
- decompressedStream, err := archive.DecompressStream(reader)
- if err != nil {
- return nil, err
- }
-
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { decompressedStream.Close() })
- tarReader = decompressedStream
- } else {
- reader, err := archive.TarWithOptions(source.resolved, tarOptions)
- if err != nil {
- return nil, err
- }
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
- tarReader = reader
- }
-
- copier.copyFunc = func() error {
- return buildahCopiah.Put(root, dir, source.putOptions(), tarReader)
- }
- return copier, nil
-}
-
-// enforceCopyRules enforces the rules for copying from a source to a
-// destination as mentioned in the podman-cp(1) man page. Please refer to the
-// man page and/or the inline comments for further details. Note that source
-// and destination are passed by reference and the their data may be changed.
-func enforceCopyRules(source, destination *CopyItem) error {
- if source.statError != nil {
- return source.statError
- }
-
- // We can copy everything to a stream.
- if destination.info.IsStream {
- return nil
- }
-
- if source.info.IsStream {
- if !(destination.info.IsDir || destination.info.IsStream) {
- return errors.New("destination must be a directory or stream when copying from a stream")
- }
- return nil
- }
-
- // Source is a *directory*.
- if source.info.IsDir {
- if destination.statError != nil {
- // It's okay if the destination does not exist. We
- // made sure before that it's parent exists, so it
- // would be created while copying.
- if os.IsNotExist(destination.statError) {
- return nil
- }
- // Could be a permission error.
- return destination.statError
- }
-
- // If the destination exists and is not a directory, we have a
- // problem.
- if !destination.info.IsDir {
- return errors.Errorf("cannot copy directory %q to file %q", source.original, destination.original)
- }
-
- // If the destination exists and is a directory, we need to
- // append the source base directory to it. This makes sure
- // that copying "/foo/bar" "/tmp" will copy to "/tmp/bar" (and
- // not "/tmp").
- newDestination, err := securejoin.SecureJoin(destination.resolved, filepath.Base(source.resolved))
- if err != nil {
- return err
- }
- destination.resolved = newDestination
- return nil
- }
-
- // Source is a *file*.
- if destination.statError != nil {
- // It's okay if the destination does not exist, unless it ends
- // with "/".
- if !os.IsNotExist(destination.statError) {
- return destination.statError
- } else if strings.HasSuffix(destination.resolved, "/") {
- // Note: this is practically unreachable code as the
- // existence of parent directories is enforced early
- // on. It's left here as an extra security net.
- return errors.Errorf("destination directory %q must exist (trailing %q)", destination.original, "/")
- }
- // Does not exist and does not end with "/".
- return nil
- }
-
- // If the destination is a file, we're good. We will overwrite the
- // contents while copying.
- if !destination.info.IsDir {
- return nil
- }
-
- // If the destination exists and is a directory, we need to append the
- // source base directory to it. This makes sure that copying
- // "/foo/bar" "/tmp" will copy to "/tmp/bar" (and not "/tmp").
- newDestination, err := securejoin.SecureJoin(destination.resolved, filepath.Base(source.resolved))
- if err != nil {
- return err
- }
-
- destination.resolved = newDestination
- return nil
-}
diff --git a/pkg/copy/fileinfo.go b/pkg/copy/fileinfo.go
index 08b4eb377..ddb9b629c 100644
--- a/pkg/copy/fileinfo.go
+++ b/pkg/copy/fileinfo.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"os"
+ "path/filepath"
"strings"
"time"
@@ -15,6 +16,10 @@ import (
// base64 encoded JSON payload of stating a path in a container.
const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat"
+// ENOENT mimics the stdlib's ENOENT and can be used to implement custom logic
+// while preserving the user-visible error message.
+var ENOENT = errors.New("No such file or directory")
+
// FileInfo describes a file or directory and is returned by
// (*CopyItem).Stat().
type FileInfo struct {
@@ -23,7 +28,6 @@ type FileInfo struct {
Mode os.FileMode `json:"mode"`
ModTime time.Time `json:"mtime"`
IsDir bool `json:"isDir"`
- IsStream bool `json:"isStream"`
LinkTarget string `json:"linkTarget"`
}
@@ -54,3 +58,54 @@ func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) {
return &info, nil
}
+
+// ResolveHostPath resolves the specified, possibly relative, path on the host.
+func ResolveHostPath(path string) (*FileInfo, error) {
+ resolvedHostPath, err := filepath.Abs(path)
+ if err != nil {
+ return nil, err
+ }
+ resolvedHostPath = PreserveBasePath(path, resolvedHostPath)
+
+ statInfo, err := os.Stat(resolvedHostPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, ENOENT
+ }
+ return nil, err
+ }
+
+ return &FileInfo{
+ Name: statInfo.Name(),
+ Size: statInfo.Size(),
+ Mode: statInfo.Mode(),
+ ModTime: statInfo.ModTime(),
+ IsDir: statInfo.IsDir(),
+ LinkTarget: resolvedHostPath,
+ }, nil
+}
+
+// PreserveBasePath makes sure that the original base path (e.g., "/" or "./")
+// is preserved. The filepath API among tends to clean up a bit too much but
+// we *must* preserve this data by all means.
+func PreserveBasePath(original, resolved string) string {
+ // Handle "/"
+ if strings.HasSuffix(original, "/") {
+ if !strings.HasSuffix(resolved, "/") {
+ resolved += "/"
+ }
+ return resolved
+ }
+
+ // Handle "/."
+ if strings.HasSuffix(original, "/.") {
+ if strings.HasSuffix(resolved, "/") { // could be root!
+ resolved += "."
+ } else if !strings.HasSuffix(resolved, "/.") {
+ resolved += "/."
+ }
+ return resolved
+ }
+
+ return resolved
+}
diff --git a/pkg/copy/item.go b/pkg/copy/item.go
deleted file mode 100644
index df8bf30b9..000000000
--- a/pkg/copy/item.go
+++ /dev/null
@@ -1,588 +0,0 @@
-package copy
-
-import (
- "io"
- "os"
- "path/filepath"
- "strings"
-
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/buildah/pkg/chrootuser"
- "github.com/containers/buildah/util"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/containers/storage"
- "github.com/containers/storage/pkg/archive"
- "github.com/containers/storage/pkg/idtools"
- securejoin "github.com/cyphar/filepath-securejoin"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// ********************************* NOTE *************************************
-//
-// Most security bugs are caused by attackers playing around with symlinks
-// trying to escape from the container onto the host and/or trick into data
-// corruption on the host. Hence, file operations on containers (including
-// *stat) should always be handled by `github.com/containers/buildah/copier`
-// which makes sure to evaluate files in a chroot'ed environment.
-//
-// Please make sure to add verbose comments when changing code to make the
-// lives of future readers easier.
-//
-// ****************************************************************************
-
-var (
- _stdin = os.Stdin.Name()
- _stdout = os.Stdout.Name()
-)
-
-// CopyItem is the source or destination of a copy operation. Use the
-// CopyItemFrom* functions to create one for the specific source/destination
-// item.
-type CopyItem struct {
- // The original path provided by the caller. Useful in error messages.
- original string
- // The resolved path on the host or container. Maybe altered at
- // multiple stages when copying.
- resolved string
- // The root for copying data in a chroot'ed environment.
- root string
-
- // IDPair of the resolved path.
- idPair *idtools.IDPair
- // Storage ID mappings.
- idMappings *storage.IDMappingOptions
-
- // Internal FileInfo. We really don't want users to mess with a
- // CopyItem but only plug and play with it.
- info FileInfo
- // Error when creating the upper FileInfo. Some errors are non-fatal,
- // for instance, when a destination *base* path does not exist.
- statError error
-
- writer io.Writer
- reader io.Reader
-
- // Needed to clean up resources (e.g., unmount a container).
- cleanUpFuncs []deferFunc
-}
-
-// deferFunc allows for returning functions that must be deferred at call sites.
-type deferFunc func()
-
-// Stat returns the FileInfo.
-func (item *CopyItem) Stat() (*FileInfo, error) {
- return &item.info, item.statError
-}
-
-// CleanUp releases resources such as the container mounts. It *must* be
-// called even in case of errors.
-func (item *CopyItem) CleanUp() {
- for _, f := range item.cleanUpFuncs {
- f()
- }
-}
-
-// CopyItemForWriter returns a CopyItem for the specified io.WriteCloser. Note
-// that the returned item can only act as a copy destination.
-func CopyItemForWriter(writer io.Writer) (item CopyItem, _ error) {
- item.writer = writer
- item.info.IsStream = true
- return item, nil
-}
-
-// CopyItemForReader returns a CopyItem for the specified io.ReaderCloser. Note
-// that the returned item can only act as a copy source.
-//
-// Note that the specified reader will be auto-decompressed if needed.
-func CopyItemForReader(reader io.Reader) (item CopyItem, _ error) {
- item.info.IsStream = true
- decompressed, err := archive.DecompressStream(reader)
- if err != nil {
- return item, err
- }
- item.reader = decompressed
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := decompressed.Close(); err != nil {
- logrus.Errorf("Error closing decompressed reader of copy item: %v", err)
- }
- })
- return item, nil
-}
-
-// CopyItemForHost creates a CopyItem for the specified host path. It's a
-// destination by default. Use isSource to set it as a destination.
-//
-// Note that callers *must* call (CopyItem).CleanUp(), even in case of errors.
-func CopyItemForHost(hostPath string, isSource bool) (item CopyItem, _ error) {
- if hostPath == "-" {
- if isSource {
- hostPath = _stdin
- } else {
- hostPath = _stdout
- }
- }
-
- if hostPath == _stdin {
- return CopyItemForReader(os.Stdin)
- }
-
- if hostPath == _stdout {
- return CopyItemForWriter(os.Stdout)
- }
-
- // Now do the dance for the host data.
- resolvedHostPath, err := filepath.Abs(hostPath)
- if err != nil {
- return item, err
- }
-
- resolvedHostPath = preserveBasePath(hostPath, resolvedHostPath)
- item.original = hostPath
- item.resolved = resolvedHostPath
- item.root = "/"
-
- statInfo, statError := os.Stat(resolvedHostPath)
- item.statError = statError
-
- // It exists, we're done.
- if statError == nil {
- item.info.Name = statInfo.Name()
- item.info.Size = statInfo.Size()
- item.info.Mode = statInfo.Mode()
- item.info.ModTime = statInfo.ModTime()
- item.info.IsDir = statInfo.IsDir()
- item.info.LinkTarget = resolvedHostPath
- return item, nil
- }
-
- // The source must exist, but let's try to give some human-friendly
- // errors.
- if isSource {
- if os.IsNotExist(item.statError) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on the host", hostPath)
- }
- return item, item.statError // could be a permission error
- }
-
- // If we're a destination, we need to make sure that the parent
- // directory exists.
- parent := filepath.Dir(resolvedHostPath)
- if _, err := os.Stat(parent); err != nil {
- if os.IsNotExist(err) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on the host", parent)
- }
- return item, err
- }
-
- return item, nil
-}
-
-// CopyItemForContainer creates a CopyItem for the specified path on the
-// container. It's a destination by default. Use isSource to set it as a
-// destination. Note that the container path may resolve to a path outside of
-// the container's mount point if the path hits a volume or mount on the
-// container.
-//
-// Note that callers *must* call (CopyItem).CleanUp(), even in case of errors.
-func CopyItemForContainer(container *libpod.Container, containerPath string, pause bool, isSource bool) (item CopyItem, _ error) {
- // Mount and pause the container.
- containerMountPoint, err := item.mountAndPauseContainer(container, pause)
- if err != nil {
- return item, err
- }
-
- // Make sure that "/" copies the *contents* of the mount point and not
- // the directory.
- if containerPath == "/" {
- containerPath += "/."
- }
-
- // Now resolve the container's path. It may hit a volume, it may hit a
- // bind mount, it may be relative.
- resolvedRoot, resolvedContainerPath, err := resolveContainerPaths(container, containerMountPoint, containerPath)
- if err != nil {
- return item, err
- }
- resolvedContainerPath = preserveBasePath(containerPath, resolvedContainerPath)
-
- idMappings, idPair, err := getIDMappingsAndPair(container, containerMountPoint)
- if err != nil {
- return item, err
- }
-
- item.original = containerPath
- item.resolved = resolvedContainerPath
- item.root = resolvedRoot
- item.idMappings = idMappings
- item.idPair = idPair
-
- statInfo, statError := secureStat(resolvedRoot, resolvedContainerPath)
- item.statError = statError
-
- // It exists, we're done.
- if statError == nil {
- item.info.IsDir = statInfo.IsDir
- item.info.Name = filepath.Base(statInfo.Name)
- item.info.Size = statInfo.Size
- item.info.Mode = statInfo.Mode
- item.info.ModTime = statInfo.ModTime
- item.info.IsDir = statInfo.IsDir
- item.info.LinkTarget = resolvedContainerPath
- return item, nil
- }
-
- // The source must exist, but let's try to give some human-friendly
- // errors.
- if isSource {
- if os.IsNotExist(statError) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on container %s (resolved to %q)", containerPath, container.ID(), resolvedContainerPath)
- }
- return item, item.statError // could be a permission error
- }
-
- // If we're a destination, we need to make sure that the parent
- // directory exists.
- parent := filepath.Dir(resolvedContainerPath)
- if _, err := secureStat(resolvedRoot, parent); err != nil {
- if os.IsNotExist(err) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on container %s (resolved to %q)", containerPath, container.ID(), resolvedContainerPath)
- }
- return item, err
- }
-
- return item, nil
-}
-
-// putOptions returns PUT options for buildah's copier package.
-func (item *CopyItem) putOptions() buildahCopiah.PutOptions {
- options := buildahCopiah.PutOptions{}
- if item.idMappings != nil {
- options.UIDMap = item.idMappings.UIDMap
- options.GIDMap = item.idMappings.GIDMap
- }
- if item.idPair != nil {
- options.ChownDirs = item.idPair
- options.ChownFiles = item.idPair
- }
- return options
-}
-
-// getOptions returns GET options for buildah's copier package.
-func (item *CopyItem) getOptions() buildahCopiah.GetOptions {
- options := buildahCopiah.GetOptions{}
- if item.idMappings != nil {
- options.UIDMap = item.idMappings.UIDMap
- options.GIDMap = item.idMappings.GIDMap
- }
- if item.idPair != nil {
- options.ChownDirs = item.idPair
- options.ChownFiles = item.idPair
- }
- return options
-
-}
-
-// mount and pause the container. Also set the item's cleanUpFuncs. Those
-// *must* be invoked by callers, even in case of errors.
-func (item *CopyItem) mountAndPauseContainer(container *libpod.Container, pause bool) (string, error) {
- // Make sure to pause and unpause the container. We cannot pause on
- // cgroupsv1 as rootless user, in which case we turn off pausing.
- if pause && rootless.IsRootless() {
- cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
- if !cgroupv2 {
- logrus.Debugf("Cannot pause container for copying as a rootless user on cgroupsv1: default to not pause")
- pause = false
- }
- }
-
- // Mount and unmount the container.
- mountPoint, err := container.Mount()
- if err != nil {
- return "", err
- }
-
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := container.Unmount(false); err != nil {
- logrus.Errorf("Error unmounting container after copy operation: %v", err)
- }
- })
-
- // Pause and unpause the container.
- if pause {
- if err := container.Pause(); err != nil {
- // Ignore errors when the container isn't running. No
- // need to pause.
- if errors.Cause(err) != define.ErrCtrStateInvalid {
- return "", err
- }
- } else {
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := container.Unpause(); err != nil {
- logrus.Errorf("Error unpausing container after copy operation: %v", err)
- }
- })
- }
- }
-
- return mountPoint, nil
-}
-
-// buildahGlobs returns the root, dir and glob used in buildah's copier
-// package.
-//
-// Note that dir is always empty.
-func (item *CopyItem) buildahGlobs() (root string, glob string, err error) {
- root = item.root
-
- // If the root and the resolved path are equal, then dir must be empty
- // and the glob must be ".".
- if filepath.Clean(root) == filepath.Clean(item.resolved) {
- glob = "."
- return
- }
-
- glob, err = filepath.Rel(root, item.resolved)
- return
-}
-
-// preserveBasePath makes sure that the original base path (e.g., "/" or "./")
-// is preserved. The filepath API among tends to clean up a bit too much but
-// we *must* preserve this data by all means.
-func preserveBasePath(original, resolved string) string {
- // Handle "/"
- if strings.HasSuffix(original, "/") {
- if !strings.HasSuffix(resolved, "/") {
- resolved += "/"
- }
- return resolved
- }
-
- // Handle "/."
- if strings.HasSuffix(original, "/.") {
- if strings.HasSuffix(resolved, "/") { // could be root!
- resolved += "."
- } else if !strings.HasSuffix(resolved, "/.") {
- resolved += "/."
- }
- return resolved
- }
-
- return resolved
-}
-
-// secureStat extracts file info for path in a chroot'ed environment in root.
-func secureStat(root string, path string) (*buildahCopiah.StatForItem, error) {
- var glob string
- var err error
-
- // If root and path are equal, then dir must be empty and the glob must
- // be ".".
- if filepath.Clean(root) == filepath.Clean(path) {
- glob = "."
- } else {
- glob, err = filepath.Rel(root, path)
- if err != nil {
- return nil, err
- }
- }
-
- globStats, err := buildahCopiah.Stat(root, "", buildahCopiah.StatOptions{}, []string{glob})
- if err != nil {
- return nil, err
- }
-
- if len(globStats) != 1 {
- return nil, errors.Errorf("internal libpod error: secureStat: expected 1 item but got %d", len(globStats))
- }
-
- stat, exists := globStats[0].Results[glob] // only one glob passed, so that's okay
- if !exists {
- return stat, os.ErrNotExist
- }
-
- var statErr error
- if stat.Error != "" {
- statErr = errors.New(stat.Error)
- }
- return stat, statErr
-}
-
-// resolveContainerPaths resolves the container's mount point and the container
-// path as specified by the user. Both may resolve to paths outside of the
-// container's mount point when the container path hits a volume or bind mount.
-//
-// NOTE: We must take volumes and bind mounts into account as, regrettably, we
-// can copy to/from stopped containers. In that case, the volumes and bind
-// mounts are not present. For running containers, the runtime (e.g., runc or
-// crun) takes care of these mounts. For stopped ones, we need to do quite
-// some dance, as done below.
-func resolveContainerPaths(container *libpod.Container, mountPoint string, containerPath string) (string, string, error) {
- // Let's first make sure we have a path relative to the mount point.
- pathRelativeToContainerMountPoint := containerPath
- if !filepath.IsAbs(containerPath) {
- // If the containerPath is not absolute, it's relative to the
- // container's working dir. To be extra careful, let's first
- // join the working dir with "/", and the add the containerPath
- // to it.
- pathRelativeToContainerMountPoint = filepath.Join(filepath.Join("/", container.WorkingDir()), containerPath)
- }
- // NOTE: the secure join makes sure that we follow symlinks. This way,
- // we catch scenarios where the container path symlinks to a volume or
- // bind mount.
- resolvedPathOnTheContainerMountPoint, err := securejoin.SecureJoin(mountPoint, pathRelativeToContainerMountPoint)
- if err != nil {
- return "", "", err
- }
- pathRelativeToContainerMountPoint = strings.TrimPrefix(pathRelativeToContainerMountPoint, mountPoint)
- pathRelativeToContainerMountPoint = filepath.Join("/", pathRelativeToContainerMountPoint)
-
- // Now we have an "absolute container Path" but not yet resolved on the
- // host (e.g., "/foo/bar/file.txt"). As mentioned above, we need to
- // check if "/foo/bar/file.txt" is on a volume or bind mount. To do
- // that, we need to walk *down* the paths to the root. Assuming
- // volume-1 is mounted to "/foo" and volume-2 is mounted to "/foo/bar",
- // we must select "/foo/bar". Once selected, we need to rebase the
- // remainder (i.e, "/file.txt") on the volume's mount point on the
- // host. Same applies to bind mounts.
-
- searchPath := pathRelativeToContainerMountPoint
- for {
- volume, err := findVolume(container, searchPath)
- if err != nil {
- return "", "", err
- }
- if volume != nil {
- logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath)
- // We found a matching volume for searchPath. We now
- // need to first find the relative path of our input
- // path to the searchPath, and then join it with the
- // volume's mount point.
- pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
- absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume)
- if err != nil {
- return "", "", err
- }
- return volume.MountPoint(), absolutePathOnTheVolumeMount, nil
- }
-
- if mount := findBindMount(container, searchPath); mount != nil {
- logrus.Debugf("Container path %q resolved to bind mount %q:%q on path %q", containerPath, mount.Source, mount.Destination, searchPath)
- // We found a matching bind mount for searchPath. We
- // now need to first find the relative path of our
- // input path to the searchPath, and then join it with
- // the source of the bind mount.
- pathRelativeToBindMount := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
- absolutePathOnTheBindMount, err := securejoin.SecureJoin(mount.Source, pathRelativeToBindMount)
- if err != nil {
- return "", "", err
- }
- return mount.Source, absolutePathOnTheBindMount, nil
-
- }
-
- if searchPath == "/" {
- // Cannot go beyond "/", so we're done.
- break
- }
-
- // Walk *down* the path (e.g., "/foo/bar/x" -> "/foo/bar").
- searchPath = filepath.Dir(searchPath)
- }
-
- // No volume, no bind mount but just a normal path on the container.
- return mountPoint, resolvedPathOnTheContainerMountPoint, nil
-}
-
-// findVolume checks if the specified container path matches a volume inside
-// the container. It returns a matching volume or nil.
-func findVolume(c *libpod.Container, containerPath string) (*libpod.Volume, error) {
- runtime := c.Runtime()
- cleanedContainerPath := filepath.Clean(containerPath)
- for _, vol := range c.Config().NamedVolumes {
- if cleanedContainerPath == filepath.Clean(vol.Dest) {
- return runtime.GetVolume(vol.Name)
- }
- }
- return nil, nil
-}
-
-// findBindMount checks if the specified container path matches a bind mount
-// inside the container. It returns a matching mount or nil.
-func findBindMount(c *libpod.Container, containerPath string) *specs.Mount {
- cleanedPath := filepath.Clean(containerPath)
- for _, m := range c.Config().Spec.Mounts {
- if m.Type != "bind" {
- continue
- }
- if cleanedPath == filepath.Clean(m.Destination) {
- mount := m
- return &mount
- }
- }
- return nil
-}
-
-// getIDMappingsAndPair returns the ID mappings for the container and the host
-// ID pair.
-func getIDMappingsAndPair(container *libpod.Container, containerMount string) (*storage.IDMappingOptions, *idtools.IDPair, error) {
- user, err := getContainerUser(container, containerMount)
- if err != nil {
- return nil, nil, err
- }
-
- idMappingOpts, err := container.IDMappings()
- if err != nil {
- return nil, nil, err
- }
-
- hostUID, hostGID, err := util.GetHostIDs(idtoolsToRuntimeSpec(idMappingOpts.UIDMap), idtoolsToRuntimeSpec(idMappingOpts.GIDMap), user.UID, user.GID)
- if err != nil {
- return nil, nil, err
- }
-
- idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
- return &idMappingOpts, &idPair, nil
-}
-
-// getContainerUser returns the specs.User of the container.
-func getContainerUser(container *libpod.Container, mountPoint string) (specs.User, error) {
- userspec := container.Config().User
-
- uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
- u := specs.User{
- UID: uid,
- GID: gid,
- Username: userspec,
- }
-
- if !strings.Contains(userspec, ":") {
- groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
- if err2 != nil {
- if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
- err = err2
- }
- } else {
- u.AdditionalGids = groups
- }
- }
-
- return u, err
-}
-
-// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
-func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
- for _, idmap := range idMaps {
- tempIDMap := specs.LinuxIDMapping{
- ContainerID: uint32(idmap.ContainerID),
- HostID: uint32(idmap.HostID),
- Size: uint32(idmap.Size),
- }
- convertedIDMap = append(convertedIDMap, tempIDMap)
- }
- return convertedIDMap
-}
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index b4e8446cb..ff3b087ed 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -12,6 +12,8 @@ import (
// Listcontainer describes a container suitable for listing
type ListContainer struct {
+ // AutoRemove
+ AutoRemove bool
// Container command
Command []string
// Container creation time
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 39d679eaf..05b9b774e 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/copy"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
)
@@ -103,9 +104,10 @@ type TopOptions struct {
}
type KillOptions struct {
- All bool
- Latest bool
- Signal string
+ All bool
+ Latest bool
+ Signal string
+ CIDFiles []string
}
type KillReport struct {
@@ -143,6 +145,10 @@ type ContainerInspectReport struct {
*define.InspectContainerData
}
+type ContainerStatReport struct {
+ copy.FileInfo
+}
+
type CommitOptions struct {
Author string
Changes []string
@@ -227,8 +233,10 @@ type ContainerLogsOptions struct {
Tail int64
// Show timestamps in the logs.
Timestamps bool
- // Write the logs to Writer.
- Writer io.Writer
+ // Write the stdout to this Writer.
+ StdoutWriter io.Writer
+ // Write the stderr to this Writer.
+ StderrWriter io.Writer
}
// ExecOptions describes the cli values to exec into
@@ -382,13 +390,6 @@ type ContainerPruneOptions struct {
Filters url.Values `json:"filters" schema:"filters"`
}
-// ContainerPruneReport describes the results after pruning the
-// stopped containers.
-type ContainerPruneReport struct {
- ID map[string]int64
- Err map[string]error
-}
-
// ContainerPortOptions describes the options to obtain
// port information on containers
type ContainerPortOptions struct {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5ad475133..7d38a97f2 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -2,13 +2,17 @@ package entities
import (
"context"
+ "io"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/spf13/cobra"
)
+type ContainerCopyFunc func() error
+
type ContainerEngine interface {
AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
@@ -16,7 +20,8 @@ type ContainerEngine interface {
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error)
ContainerCommit(ctx context.Context, nameOrID string, options CommitOptions) (*CommitReport, error)
- ContainerCp(ctx context.Context, source, dest string, options ContainerCpOptions) error
+ ContainerCopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (ContainerCopyFunc, error)
+ ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (ContainerCopyFunc, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
@@ -31,13 +36,14 @@ type ContainerEngine interface {
ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
- ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
+ ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
+ ContainerStat(ctx context.Context, nameOrDir string, path string) (*ContainerStatReport, error)
ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) (chan ContainerStatsReport, error)
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
@@ -80,6 +86,6 @@ type ContainerEngine interface {
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
- VolumePrune(ctx context.Context) ([]*VolumePruneReport, error)
+ VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*reports.PruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
}
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 594f9617f..26a136f13 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -4,6 +4,7 @@ import (
"context"
"github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
type ImageEngine interface {
@@ -17,7 +18,7 @@ type ImageEngine interface {
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error)
- Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
+ Prune(ctx context.Context, opts ImagePruneOptions) ([]*reports.PruneReport, error)
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
@@ -35,6 +36,6 @@ type ImageEngine interface {
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
ManifestAnnotate(ctx context.Context, names []string, opts ManifestAnnotateOptions) (string, error)
ManifestRemove(ctx context.Context, names []string) (string, error)
- ManifestPush(ctx context.Context, names []string, manifestPushOpts ManifestPushOptions) error
+ ManifestPush(ctx context.Context, name, destination string, manifestPushOpts ManifestPushOptions) error
Sign(ctx context.Context, names []string, options SignOptions) (*SignReport, error)
}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 81f12bff7..d5f88502a 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -222,7 +222,7 @@ type ImageSearchOptions struct {
type ImageSearchReport struct {
// Index is the image index (e.g., "docker.io" or "quay.io")
Index string
- // Name is the canoncical name of the image (e.g., "docker.io/library/alpine").
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
Name string
// Description of the image.
Description string
@@ -247,11 +247,6 @@ type ImagePruneOptions struct {
Filter []string `json:"filter" schema:"filter"`
}
-type ImagePruneReport struct {
- Report Report
- Size int64
-}
-
type ImageTagOptions struct{}
type ImageUntagOptions struct{}
@@ -344,6 +339,7 @@ type SignOptions struct {
Directory string
SignBy string
CertDir string
+ All bool
}
// SignReport describes the result of signing
diff --git a/pkg/domain/entities/reports/prune.go b/pkg/domain/entities/reports/prune.go
new file mode 100644
index 000000000..5494ac3ae
--- /dev/null
+++ b/pkg/domain/entities/reports/prune.go
@@ -0,0 +1,40 @@
+package reports
+
+type PruneReport struct {
+ Id string //nolint
+ Err error
+ Size uint64
+}
+
+func PruneReportsIds(r []*PruneReport) []string {
+ ids := make([]string, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Id == "" {
+ continue
+ }
+ ids = append(ids, v.Id)
+ }
+ return ids
+}
+
+func PruneReportsErrs(r []*PruneReport) []error {
+ errs := make([]error, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Err == nil {
+ continue
+ }
+ errs = append(errs, v.Err)
+ }
+ return errs
+}
+
+func PruneReportsSize(r []*PruneReport) uint64 {
+ size := uint64(0)
+ for _, v := range r {
+ if v == nil {
+ continue
+ }
+ size = size + v.Size
+ }
+ return size
+}
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index bde2b6ef2..99fa947f0 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -4,6 +4,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
@@ -17,16 +18,18 @@ type ServiceOptions struct {
// SystemPruneOptions provides options to prune system.
type SystemPruneOptions struct {
- All bool
- Volume bool
+ All bool
+ Volume bool
+ Filters map[string][]string `json:"filters" schema:"filters"`
}
// SystemPruneReport provides report after system prune is executed.
type SystemPruneReport struct {
- PodPruneReport []*PodPruneReport
- *ContainerPruneReport
- *ImagePruneReport
- VolumePruneReport []*VolumePruneReport
+ PodPruneReport []*PodPruneReport
+ ContainerPruneReports []*reports.PruneReport
+ ImagePruneReports []*reports.PruneReport
+ VolumePruneReports []*reports.PruneReport
+ ReclaimedSpace uint64
}
// SystemMigrateOptions describes the options needed for the
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 1bc1e4301..06438f5e9 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -1,6 +1,7 @@
package entities
import (
+ "net/url"
"time"
docker_api_types "github.com/docker/docker/api/types"
@@ -109,9 +110,10 @@ type VolumeInspectReport struct {
*VolumeConfigResponse
}
-type VolumePruneReport struct {
- Err error
- Id string //nolint
+// VolumePruneOptions describes the options needed
+// to prune a volume from the CLI
+type VolumePruneOptions struct {
+ Filters url.Values `json:"filters" schema:"filters"`
}
type VolumeListOptions struct {
diff --git a/libpod/filters/containers.go b/pkg/domain/filters/containers.go
index 2520c4f30..ce6c12b71 100644
--- a/libpod/filters/containers.go
+++ b/pkg/domain/filters/containers.go
@@ -1,4 +1,4 @@
-package lpfilters
+package filters
import (
"strconv"
@@ -203,6 +203,36 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
}
return false
}, nil
+ case "pod":
+ var pods []*libpod.Pod
+ for _, podNameOrID := range filterValues {
+ p, err := r.LookupPod(podNameOrID)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchPod {
+ continue
+ }
+ return nil, err
+ }
+ pods = append(pods, p)
+ }
+ return func(c *libpod.Container) bool {
+ // if no pods match, quick out
+ if len(pods) < 1 {
+ return false
+ }
+ // if the container has no pod id, quick out
+ if len(c.PodID()) < 1 {
+ return false
+ }
+ for _, p := range pods {
+ // we already looked up by name or id, so id match
+ // here is ok
+ if p.ID() == c.PodID() {
+ return true
+ }
+ }
+ return false
+ }, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
diff --git a/pkg/domain/filters/helpers.go b/pkg/domain/filters/helpers.go
new file mode 100644
index 000000000..6a5fb68b1
--- /dev/null
+++ b/pkg/domain/filters/helpers.go
@@ -0,0 +1,20 @@
+package filters
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+func ParseFilterArgumentsIntoFilters(filters []string) (url.Values, error) {
+ parsedFilters := make(url.Values)
+ for _, f := range filters {
+ t := strings.SplitN(f, "=", 2)
+ if len(t) < 2 {
+ return parsedFilters, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ parsedFilters.Add(t[0], t[1])
+ }
+ return parsedFilters, nil
+}
diff --git a/libpod/filters/pods.go b/pkg/domain/filters/pods.go
index 17b3f3ca9..7e6b7f2cc 100644
--- a/libpod/filters/pods.go
+++ b/pkg/domain/filters/pods.go
@@ -1,4 +1,4 @@
-package lpfilters
+package filters
import (
"strconv"
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index 7819d3cdf..69bef4961 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -1,13 +1,14 @@
package filters
import (
+ "net/url"
"strings"
"github.com/containers/podman/v2/libpod"
"github.com/pkg/errors"
)
-func GenerateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter, error) {
+func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
var vf []libpod.VolumeFilter
for filter, v := range filters {
for _, val := range v {
diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go
new file mode 100644
index 000000000..809813756
--- /dev/null
+++ b/pkg/domain/infra/abi/archive.go
@@ -0,0 +1,172 @@
+package abi
+
+import (
+ "context"
+ "io"
+ "strings"
+
+ buildahCopiah "github.com/containers/buildah/copier"
+ "github.com/containers/buildah/pkg/chrootuser"
+ "github.com/containers/buildah/util"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/idtools"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// NOTE: Only the parent directory of the container path must exist. The path
+// itself may be created while copying.
+func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID string, containerPath string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ unmount := func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }
+
+ _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ decompressed, err := archive.DecompressStream(reader)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
+
+ return func() error {
+ defer unmount()
+ defer decompressed.Close()
+ putOptions := buildahCopiah.PutOptions{
+ UIDMap: idMappings.UIDMap,
+ GIDMap: idMappings.GIDMap,
+ ChownDirs: idPair,
+ ChownFiles: idPair,
+ }
+ return buildahCopiah.Put(resolvedRoot, resolvedContainerPath, putOptions, decompressed)
+ }, nil
+}
+
+func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, containerPath string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ unmount := func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }
+
+ // Make sure that "/" copies the *contents* of the mount point and not
+ // the directory.
+ if containerPath == "/" {
+ containerPath = "/."
+ }
+
+ _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
+
+ return func() error {
+ defer container.Unmount(false)
+ getOptions := buildahCopiah.GetOptions{
+ // Unless the specified path ends with ".", we want to copy the base directory.
+ KeepDirectoryNames: !strings.HasSuffix(resolvedContainerPath, "."),
+ UIDMap: idMappings.UIDMap,
+ GIDMap: idMappings.GIDMap,
+ ChownDirs: idPair,
+ ChownFiles: idPair,
+ }
+ return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedContainerPath}, writer)
+ }, nil
+}
+
+// getIDMappingsAndPair returns the ID mappings for the container and the host
+// ID pair.
+func getIDMappingsAndPair(container *libpod.Container, containerMount string) (*storage.IDMappingOptions, *idtools.IDPair, error) {
+ user, err := getContainerUser(container, containerMount)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ idMappingOpts, err := container.IDMappings()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ hostUID, hostGID, err := util.GetHostIDs(idtoolsToRuntimeSpec(idMappingOpts.UIDMap), idtoolsToRuntimeSpec(idMappingOpts.GIDMap), user.UID, user.GID)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
+ return &idMappingOpts, &idPair, nil
+}
+
+// getContainerUser returns the specs.User of the container.
+func getContainerUser(container *libpod.Container, mountPoint string) (specs.User, error) {
+ userspec := container.Config().User
+
+ uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
+ u := specs.User{
+ UID: uid,
+ GID: gid,
+ Username: userspec,
+ }
+
+ if !strings.Contains(userspec, ":") {
+ groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
+ if err2 != nil {
+ if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
+ err = err2
+ }
+ } else {
+ u.AdditionalGids = groups
+ }
+ }
+
+ return u, err
+}
+
+// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
+func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
+ for _, idmap := range idMaps {
+ tempIDMap := specs.LinuxIDMapping{
+ ContainerID: uint32(idmap.ContainerID),
+ HostID: uint32(idmap.HostID),
+ Size: uint32(idmap.Size),
+ }
+ convertedIDMap = append(convertedIDMap, tempIDMap)
+ }
+ return convertedIDMap
+}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index ff4277a2e..9d7c2daea 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -16,12 +16,13 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/libpod/logs"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/checkpoint"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
"github.com/containers/podman/v2/pkg/ps"
@@ -204,31 +205,27 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
+ generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
if err != nil {
return nil, err
}
filterFuncs = append(filterFuncs, generatedFunc)
}
- return ic.pruneContainersHelper(filterFuncs)
-}
-
-func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
- prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
- if err != nil {
- return nil, err
- }
- report := entities.ContainerPruneReport{
- ID: prunedContainers,
- Err: pruneErrors,
- }
- return &report, nil
+ return ic.Libpod.PruneContainers(filterFuncs)
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
if err != nil {
return nil, err
@@ -246,6 +243,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
}
return reports, nil
}
+
func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
ctrs []*libpod.Container
@@ -925,7 +923,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
- if options.Writer == nil {
+ if options.StdoutWriter == nil && options.StderrWriter == nil {
return errors.New("no io.Writer set for container logs")
}
@@ -963,7 +961,7 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin
}()
for line := range logChannel {
- fmt.Fprintln(options.Writer, line.String(logOpts))
+ line.Write(options.StdoutWriter, options.StderrWriter, logOpts)
}
return nil
diff --git a/pkg/domain/infra/abi/containers_stat.go b/pkg/domain/infra/abi/containers_stat.go
new file mode 100644
index 000000000..5b43ee2f4
--- /dev/null
+++ b/pkg/domain/infra/abi/containers_stat.go
@@ -0,0 +1,251 @@
+package abi
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "strings"
+
+ buildahCopiah "github.com/containers/buildah/copier"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/copy"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (ic *ContainerEngine) containerStat(container *libpod.Container, containerPath string) (*entities.ContainerStatReport, string, string, error) {
+ containerMountPoint, err := container.Mount()
+ if err != nil {
+ return nil, "", "", err
+ }
+
+ // Make sure that "/" copies the *contents* of the mount point and not
+ // the directory.
+ if containerPath == "/" {
+ containerPath += "/."
+ }
+
+ // Now resolve the container's path. It may hit a volume, it may hit a
+ // bind mount, it may be relative.
+ resolvedRoot, resolvedContainerPath, err := resolveContainerPaths(container, containerMountPoint, containerPath)
+ if err != nil {
+ return nil, "", "", err
+ }
+
+ statInfo, statInfoErr := secureStat(resolvedRoot, resolvedContainerPath)
+ if statInfoErr != nil {
+ // Not all errors from secureStat map to ErrNotExist, so we
+ // have to look into the error string. Turning it into an
+ // ENOENT let's the API handlers return the correct status code
+ // which is crucial for the remote client.
+ if os.IsNotExist(err) || strings.Contains(statInfoErr.Error(), "o such file or directory") {
+ statInfoErr = copy.ENOENT
+ }
+ // If statInfo is nil, there's nothing we can do anymore. A
+ // non-nil statInfo may indicate a symlink where we must have
+ // a closer look.
+ if statInfo == nil {
+ return nil, "", "", statInfoErr
+ }
+ }
+
+ // Now make sure that the info's LinkTarget is relative to the
+ // container's mount.
+ var absContainerPath string
+
+ if statInfo.IsSymlink {
+ // Evaluated symlinks are always relative to the container's mount point.
+ absContainerPath = statInfo.ImmediateTarget
+ } else if strings.HasPrefix(resolvedContainerPath, containerMountPoint) {
+ // If the path is on the container's mount point, strip it off.
+ absContainerPath = strings.TrimPrefix(resolvedContainerPath, containerMountPoint)
+ absContainerPath = filepath.Join("/", absContainerPath)
+ } else {
+ // No symlink and not on the container's mount point, so let's
+ // move it back to the original input. It must have evaluated
+ // to a volume or bind mount but we cannot return host paths.
+ absContainerPath = containerPath
+ }
+
+ // Now we need to make sure to preserve the base path as specified by
+ // the user. The `filepath` packages likes to remove trailing slashes
+ // and dots that are crucial to the copy logic.
+ absContainerPath = copy.PreserveBasePath(containerPath, absContainerPath)
+ resolvedContainerPath = copy.PreserveBasePath(containerPath, resolvedContainerPath)
+
+ info := copy.FileInfo{
+ IsDir: statInfo.IsDir,
+ Name: filepath.Base(absContainerPath),
+ Size: statInfo.Size,
+ Mode: statInfo.Mode,
+ ModTime: statInfo.ModTime,
+ LinkTarget: absContainerPath,
+ }
+
+ return &entities.ContainerStatReport{FileInfo: info}, resolvedRoot, resolvedContainerPath, statInfoErr
+}
+
+func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, containerPath string) (*entities.ContainerStatReport, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ defer func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }()
+
+ statReport, _, _, err := ic.containerStat(container, containerPath)
+ return statReport, err
+}
+
+// resolveContainerPaths resolves the container's mount point and the container
+// path as specified by the user. Both may resolve to paths outside of the
+// container's mount point when the container path hits a volume or bind mount.
+//
+// NOTE: We must take volumes and bind mounts into account as, regrettably, we
+// can copy to/from stopped containers. In that case, the volumes and bind
+// mounts are not present. For running containers, the runtime (e.g., runc or
+// crun) takes care of these mounts. For stopped ones, we need to do quite
+// some dance, as done below.
+func resolveContainerPaths(container *libpod.Container, mountPoint string, containerPath string) (string, string, error) {
+ // Let's first make sure we have a path relative to the mount point.
+ pathRelativeToContainerMountPoint := containerPath
+ if !filepath.IsAbs(containerPath) {
+ // If the containerPath is not absolute, it's relative to the
+ // container's working dir. To be extra careful, let's first
+ // join the working dir with "/", and the add the containerPath
+ // to it.
+ pathRelativeToContainerMountPoint = filepath.Join(filepath.Join("/", container.WorkingDir()), containerPath)
+ }
+ resolvedPathOnTheContainerMountPoint := filepath.Join(mountPoint, pathRelativeToContainerMountPoint)
+ pathRelativeToContainerMountPoint = strings.TrimPrefix(pathRelativeToContainerMountPoint, mountPoint)
+ pathRelativeToContainerMountPoint = filepath.Join("/", pathRelativeToContainerMountPoint)
+
+ // Now we have an "absolute container Path" but not yet resolved on the
+ // host (e.g., "/foo/bar/file.txt"). As mentioned above, we need to
+ // check if "/foo/bar/file.txt" is on a volume or bind mount. To do
+ // that, we need to walk *down* the paths to the root. Assuming
+ // volume-1 is mounted to "/foo" and volume-2 is mounted to "/foo/bar",
+ // we must select "/foo/bar". Once selected, we need to rebase the
+ // remainder (i.e, "/file.txt") on the volume's mount point on the
+ // host. Same applies to bind mounts.
+
+ searchPath := pathRelativeToContainerMountPoint
+ for {
+ volume, err := findVolume(container, searchPath)
+ if err != nil {
+ return "", "", err
+ }
+ if volume != nil {
+ logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath)
+ // We found a matching volume for searchPath. We now
+ // need to first find the relative path of our input
+ // path to the searchPath, and then join it with the
+ // volume's mount point.
+ pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
+ absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume)
+ if err != nil {
+ return "", "", err
+ }
+ return volume.MountPoint(), absolutePathOnTheVolumeMount, nil
+ }
+
+ if mount := findBindMount(container, searchPath); mount != nil {
+ logrus.Debugf("Container path %q resolved to bind mount %q:%q on path %q", containerPath, mount.Source, mount.Destination, searchPath)
+ // We found a matching bind mount for searchPath. We
+ // now need to first find the relative path of our
+ // input path to the searchPath, and then join it with
+ // the source of the bind mount.
+ pathRelativeToBindMount := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
+ absolutePathOnTheBindMount, err := securejoin.SecureJoin(mount.Source, pathRelativeToBindMount)
+ if err != nil {
+ return "", "", err
+ }
+ return mount.Source, absolutePathOnTheBindMount, nil
+
+ }
+
+ if searchPath == "/" {
+ // Cannot go beyond "/", so we're done.
+ break
+ }
+
+ // Walk *down* the path (e.g., "/foo/bar/x" -> "/foo/bar").
+ searchPath = filepath.Dir(searchPath)
+ }
+
+ // No volume, no bind mount but just a normal path on the container.
+ return mountPoint, resolvedPathOnTheContainerMountPoint, nil
+}
+
+// findVolume checks if the specified container path matches a volume inside
+// the container. It returns a matching volume or nil.
+func findVolume(c *libpod.Container, containerPath string) (*libpod.Volume, error) {
+ runtime := c.Runtime()
+ cleanedContainerPath := filepath.Clean(containerPath)
+ for _, vol := range c.Config().NamedVolumes {
+ if cleanedContainerPath == filepath.Clean(vol.Dest) {
+ return runtime.GetVolume(vol.Name)
+ }
+ }
+ return nil, nil
+}
+
+// findBindMount checks if the specified container path matches a bind mount
+// inside the container. It returns a matching mount or nil.
+func findBindMount(c *libpod.Container, containerPath string) *specs.Mount {
+ cleanedPath := filepath.Clean(containerPath)
+ for _, m := range c.Config().Spec.Mounts {
+ if m.Type != "bind" {
+ continue
+ }
+ if cleanedPath == filepath.Clean(m.Destination) {
+ mount := m
+ return &mount
+ }
+ }
+ return nil
+}
+
+// secureStat extracts file info for path in a chroot'ed environment in root.
+func secureStat(root string, path string) (*buildahCopiah.StatForItem, error) {
+ var glob string
+ var err error
+
+ // If root and path are equal, then dir must be empty and the glob must
+ // be ".".
+ if filepath.Clean(root) == filepath.Clean(path) {
+ glob = "."
+ } else {
+ glob, err = filepath.Rel(root, path)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ globStats, err := buildahCopiah.Stat(root, "", buildahCopiah.StatOptions{}, []string{glob})
+ if err != nil {
+ return nil, err
+ }
+
+ if len(globStats) != 1 {
+ return nil, errors.Errorf("internal error: secureStat: expected 1 item but got %d", len(globStats))
+ }
+
+ stat, exists := globStats[0].Results[glob] // only one glob passed, so that's okay
+ if !exists {
+ return nil, copy.ENOENT
+ }
+
+ var statErr error
+ if stat.Error != "" {
+ statErr = errors.New(stat.Error)
+ }
+ return stat, statErr
+}
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
deleted file mode 100644
index 362053cce..000000000
--- a/pkg/domain/infra/abi/cp.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package abi
-
-import (
- "context"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/copy"
- "github.com/containers/podman/v2/pkg/domain/entities"
-)
-
-func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- // Parse user input.
- sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest)
- if err != nil {
- return err
- }
-
- // Look up containers.
- var sourceContainer, destContainer *libpod.Container
- if len(sourceContainerStr) > 0 {
- sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr)
- if err != nil {
- return err
- }
- }
- if len(destContainerStr) > 0 {
- destContainer, err = ic.Libpod.LookupContainer(destContainerStr)
- if err != nil {
- return err
- }
- }
-
- var sourceItem, destinationItem copy.CopyItem
-
- // Source ... container OR host.
- if sourceContainer != nil {
- sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true)
- defer sourceItem.CleanUp()
- if err != nil {
- return err
- }
- } else {
- sourceItem, err = copy.CopyItemForHost(sourcePath, true)
- if err != nil {
- return err
- }
- }
-
- // Destination ... container OR host.
- if destContainer != nil {
- destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false)
- defer destinationItem.CleanUp()
- if err != nil {
- return err
- }
- } else {
- destinationItem, err = copy.CopyItemForHost(destPath, false)
- defer destinationItem.CleanUp()
- if err != nil {
- return err
- }
- }
-
- // Copy from the host to the container.
- copier, err := copy.GetCopier(&sourceItem, &destinationItem, options.Extract)
- if err != nil {
- return err
- }
- return copier.Copy()
-}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 57a2bc4cf..19f081abb 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -24,10 +24,13 @@ import (
"github.com/containers/podman/v2/libpod/image"
libpodImage "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
domainUtils "github.com/containers/podman/v2/pkg/domain/utils"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
+ dockerRef "github.com/docker/distribution/reference"
+ "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -47,19 +50,12 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
return &entities.BoolReport{Value: err == nil}, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
- results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
+ reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
if err != nil {
return nil, err
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- return &report, nil
+ return reports, err
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
@@ -718,9 +714,9 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
logrus.Errorf("unable to close %s image source %q", srcRef.DockerReference().Name(), err)
}
}()
- getManifest, _, err := rawSource.GetManifest(ctx, nil)
+ topManifestBlob, manifestType, err := rawSource.GetManifest(ctx, nil)
if err != nil {
- return errors.Wrapf(err, "error getting getManifest")
+ return errors.Wrapf(err, "error getting manifest blob")
}
dockerReference := rawSource.Reference().DockerReference()
if dockerReference == nil {
@@ -743,34 +739,34 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return err
}
}
- manifestDigest, err := manifest.Digest(getManifest)
+ manifestDigest, err := manifest.Digest(topManifestBlob)
if err != nil {
return err
}
- // create signature
- newSig, err := signature.SignDockerManifest(getManifest, dockerReference.String(), mech, options.SignBy)
- if err != nil {
- return errors.Wrapf(err, "error creating new signature")
- }
- // create the signstore file
- signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, manifestDigest.Algorithm(), manifestDigest.Hex())
- if err := os.MkdirAll(signatureDir, 0751); err != nil {
- // The directory is allowed to exist
- if !os.IsExist(err) {
- logrus.Error(err)
- return nil
+ if options.All {
+ if !manifest.MIMETypeIsMultiImage(manifestType) {
+ return errors.Errorf("%s is not a multi-architecture image (manifest type %s)", signimage, manifestType)
+ }
+ list, err := manifest.ListFromBlob(topManifestBlob, manifestType)
+ if err != nil {
+ return errors.Wrapf(err, "Error parsing manifest list %q", string(topManifestBlob))
+ }
+ instanceDigests := list.Instances()
+ for _, instanceDigest := range instanceDigests {
+ digest := instanceDigest
+ man, _, err := rawSource.GetManifest(ctx, &digest)
+ if err != nil {
+ return err
+ }
+ if err = putSignature(man, mech, sigStoreDir, instanceDigest, dockerReference, options); err != nil {
+ return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), instanceDigest)
+ }
}
- }
- sigFilename, err := getSigFilename(signatureDir)
- if err != nil {
- logrus.Errorf("error creating sigstore file: %v", err)
return nil
}
- err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644)
- if err != nil {
- logrus.Errorf("error storing signature for %s", rawSource.Reference().DockerReference().String())
- return nil
+ if err = putSignature(topManifestBlob, mech, sigStoreDir, manifestDigest, dockerReference, options); err != nil {
+ return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), manifestDigest)
}
return nil
}()
@@ -806,3 +802,26 @@ func localPathFromURI(url *url.URL) (string, error) {
}
return url.Path, nil
}
+
+// putSignature creates signature and saves it to the signstore file
+func putSignature(manifestBlob []byte, mech signature.SigningMechanism, sigStoreDir string, instanceDigest digest.Digest, dockerReference dockerRef.Reference, options entities.SignOptions) error {
+ newSig, err := signature.SignDockerManifest(manifestBlob, dockerReference.String(), mech, options.SignBy)
+ if err != nil {
+ return err
+ }
+ signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, instanceDigest.Algorithm(), instanceDigest.Hex())
+ if err := os.MkdirAll(signatureDir, 0751); err != nil {
+ // The directory is allowed to exist
+ if !os.IsExist(err) {
+ return err
+ }
+ }
+ sigFilename, err := getSigFilename(signatureDir)
+ if err != nil {
+ return err
+ }
+ if err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 600d64b1d..0c734d10d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -244,15 +244,16 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
}
// ManifestPush pushes a manifest list or image index to the destination
-func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error {
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
+func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ManifestPushOptions) error {
+ listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name)
if err != nil {
- return errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+ return errors.Wrapf(err, "error retrieving local image from image name %s", name)
}
- dest, err := alltransports.ParseImageName(names[1])
+ dest, err := alltransports.ParseImageName(destination)
if err != nil {
return err
}
+
var manifestType string
if opts.Format != "" {
switch opts.Format {
@@ -267,8 +268,8 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts en
// Set the system context.
sys := ir.Libpod.SystemContext()
- if sys != nil {
- sys = &types.SystemContext{}
+ if sys == nil {
+ sys = new(types.SystemContext)
}
sys.AuthFilePath = opts.Authfile
sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
@@ -296,12 +297,12 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts en
if !opts.Quiet {
options.ReportWriter = os.Stderr
}
- digest, err := listImage.PushManifest(dest, options)
+ manDigest, err := listImage.PushManifest(dest, options)
if err == nil && opts.Purge {
_, err = ir.Libpod.GetStore().DeleteImage(listImage.ID(), true)
}
if opts.DigestFile != "" {
- if err = ioutil.WriteFile(opts.DigestFile, []byte(digest.String()), 0644); err != nil {
+ if err = ioutil.WriteFile(opts.DigestFile, []byte(manDigest.String()), 0644); err != nil {
return buildahUtil.GetFailureCause(err, errors.Wrapf(err, "failed to write digest to file %q", opts.DigestFile))
}
}
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
index 37568ea11..6a6380e33 100644
--- a/pkg/domain/infra/abi/parse/parse.go
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -38,6 +38,9 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
}
logrus.Debugf("Removing uid= from options and adding WithVolumeUID for UID %d", intUID)
libpodOptions = append(libpodOptions, libpod.WithVolumeUID(intUID))
+ finalVal = append(finalVal, o)
+ // set option "UID": "$uid"
+ volumeOptions["UID"] = splitO[1]
case "gid":
if len(splitO) != 2 {
return nil, errors.Wrapf(define.ErrInvalidArg, "gid option must provide a GID")
@@ -48,6 +51,9 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
}
logrus.Debugf("Removing gid= from options and adding WithVolumeGID for GID %d", intGID)
libpodOptions = append(libpodOptions, libpod.WithVolumeGID(intGID))
+ finalVal = append(finalVal, o)
+ // set option "GID": "$gid"
+ volumeOptions["GID"] = splitO[1]
default:
finalVal = append(finalVal, o)
}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 3aeb6a2ee..cbc74a2f2 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -212,8 +212,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, errors.Wrapf(err, "Failed to parse image %q", container.Image)
}
// In kube, if the image is tagged with latest, it should always pull
+ // but if the domain is localhost, that means the image was built locally
+ // so do not attempt a pull.
if tagged, isTagged := named.(reference.NamedTagged); isTagged {
- if tagged.Tag() == image.LatestTag {
+ if tagged.Tag() == image.LatestTag && reference.Domain(named) != image.DefaultLocalRegistry {
pullPolicy = util.PullImageAlways
}
}
@@ -224,7 +226,19 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, err
}
- specGen, err := kube.ToSpecGen(ctx, container, container.Image, newImage, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths, ctrRestartPolicy)
+ specgenOpts := kube.CtrSpecGenOptions{
+ Container: container,
+ Image: newImage,
+ Volumes: volumes,
+ PodID: pod.ID(),
+ PodName: podName,
+ PodInfraID: podInfraID,
+ ConfigMaps: configMaps,
+ SeccompPaths: seccompPaths,
+ RestartPolicy: ctrRestartPolicy,
+ NetNSIsHost: p.NetNS.IsHost(),
+ }
+ specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 11374e513..f108b770c 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -5,8 +5,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/signal"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/specgen/generate"
@@ -288,7 +288,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
filters := make([]libpod.PodFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- f, err := lpfilters.GeneratePodFilterFunc(k, v)
+ f, err := dfilters.GeneratePodFilterFunc(k, v)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 7ed58092b..67c018122 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io/ioutil"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -15,6 +16,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
@@ -168,6 +170,8 @@ func checkInput() error { // nolint:deadcode,unused
// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
var systemPruneReport = new(entities.SystemPruneReport)
+ var filters []string
+ reclaimedSpace := (uint64)(0)
found := true
for found {
found = false
@@ -179,51 +183,46 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
found = true
}
systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...)
- containerPruneReport, err := ic.pruneContainersHelper(nil)
+
+ // TODO: Figure out cleaner way to handle all of the different PruneOptions
+ containerPruneOptions := entities.ContainerPruneOptions{}
+ containerPruneOptions.Filters = (url.Values)(options.Filters)
+
+ containerPruneReports, err := ic.ContainerPrune(ctx, containerPruneOptions)
if err != nil {
return nil, err
}
- if len(containerPruneReport.ID) > 0 {
- found = true
- }
- if systemPruneReport.ContainerPruneReport == nil {
- systemPruneReport.ContainerPruneReport = containerPruneReport
- } else {
- for name, val := range containerPruneReport.ID {
- systemPruneReport.ContainerPruneReport.ID[name] = val
- }
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports)
+ systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
+ for k, v := range options.Filters {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
}
-
- results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, nil)
+ imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
if err != nil {
return nil, err
}
- if len(results) > 0 {
+ if len(imagePruneReports) > 0 {
found = true
}
- if systemPruneReport.ImagePruneReport == nil {
- systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- } else {
- systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
- }
+ systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...)
if options.Volume {
- volumePruneReport, err := ic.pruneVolumesHelper(ctx)
+ volumePruneOptions := entities.VolumePruneOptions{}
+ volumePruneOptions.Filters = (url.Values)(options.Filters)
+ volumePruneReport, err := ic.VolumePrune(ctx, volumePruneOptions)
if err != nil {
return nil, err
}
if len(volumePruneReport) > 0 {
found = true
}
- systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(volumePruneReport)
+ systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...)
}
}
+ systemPruneReport.ReclaimedSpace = reclaimedSpace
return systemPruneReport, nil
}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index a7262f61b..3c9dd9fc0 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/pkg/errors"
@@ -127,23 +128,20 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return ic.pruneVolumesHelper(ctx)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
+ filterFuncs, err := filters.GenerateVolumeFilters(options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ return ic.pruneVolumesHelper(ctx, filterFuncs)
}
-func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- pruned, err := ic.Libpod.PruneVolumes(ctx)
+func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*reports.PruneReport, error) {
+ pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
- }
- return reports, nil
+ return pruned, nil
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index 3a64cb72a..a25d165c9 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -21,7 +21,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine,
return r, err
case entities.TunnelMode:
ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ContainerEngine{ClientCxt: ctx}, err
+ return &tunnel.ContainerEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
@@ -34,7 +34,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
return r, err
case entities.TunnelMode:
ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ImageEngine{ClientCxt: ctx}, err
+ return &tunnel.ImageEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go
index 6c85e837e..b8aefaa35 100644
--- a/pkg/domain/infra/runtime_tunnel.go
+++ b/pkg/domain/infra/runtime_tunnel.go
@@ -5,19 +5,39 @@ package infra
import (
"context"
"fmt"
+ "sync"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/tunnel"
)
+var (
+ connectionMutex = &sync.Mutex{}
+ connection *context.Context
+)
+
+func newConnection(uri string, identity string) (context.Context, error) {
+ connectionMutex.Lock()
+ defer connectionMutex.Unlock()
+
+ if connection == nil {
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), uri, identity)
+ if err != nil {
+ return ctx, err
+ }
+ connection = &ctx
+ }
+ return *connection, nil
+}
+
func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
return nil, fmt.Errorf("direct runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ContainerEngine{ClientCxt: ctx}, err
+ ctx, err := newConnection(facts.URI, facts.Identity)
+ return &tunnel.ContainerEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
@@ -28,8 +48,8 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
case entities.ABIMode:
return nil, fmt.Errorf("direct image runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ImageEngine{ClientCxt: ctx}, err
+ ctx, err := newConnection(facts.URI, facts.Identity)
+ return &tunnel.ImageEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index e65fef0a4..3366cb425 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -16,9 +16,9 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/pkg/api/handlers"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/util"
@@ -31,19 +31,20 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
}
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
- exists, err := containers.Exists(ic.ClientCxt, nameOrID, options.External)
+ exists, err := containers.Exists(ic.ClientCtx, nameOrID, options.External)
return &entities.BoolReport{Value: exists}, err
}
-func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
- cons, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, opts entities.WaitOptions) ([]entities.WaitReport, error) {
+ cons, err := getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
responses := make([]entities.WaitReport, 0, len(cons))
+ options := new(containers.WaitOptions).WithCondition(opts.Condition)
for _, c := range cons {
response := entities.WaitReport{Id: c.ID}
- exitCode, err := containers.Wait(ic.ClientCxt, c.ID, &options.Condition)
+ exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options)
if err != nil {
response.Error = err
} else {
@@ -55,34 +56,34 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
- err := containers.Pause(ic.ClientCxt, c.ID)
+ err := containers.Pause(ic.ClientCtx, c.ID, nil)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
}
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
- err := containers.Unpause(ic.ClientCxt, c.ID)
+ err := containers.Unpause(ic.ClientCtx, c.ID, nil)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
+func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, opts entities.StopOptions) ([]*entities.StopReport, error) {
reports := []*entities.StopReport{}
- for _, cidFile := range options.CIDFiles {
+ for _, cidFile := range opts.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
return nil, errors.Wrap(err, "error reading CIDFile")
@@ -90,19 +91,23 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
if err != nil {
return nil, err
}
+ options := new(containers.StopOptions)
+ if to := opts.Timeout; to != nil {
+ options.WithTimeout(*to)
+ }
for _, c := range ctrs {
report := entities.StopReport{Id: c.ID}
- if err = containers.Stop(ic.ClientCxt, c.ID, options.Timeout); err != nil {
+ if err = containers.Stop(ic.ClientCtx, c.ID, options); err != nil {
// These first two are considered non-fatal under the right conditions
if errors.Cause(err).Error() == define.ErrCtrStopped.Error() {
logrus.Debugf("Container %s is already stopped", c.ID)
reports = append(reports, &report)
continue
- } else if options.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
+ } else if opts.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
logrus.Debugf("Container %s is not running, could not stop", c.ID)
reports = append(reports, &report)
continue
@@ -120,8 +125,16 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, opts entities.KillOptions) ([]*entities.KillReport, error) {
+ for _, cidFile := range opts.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -129,40 +142,38 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
for _, c := range ctrs {
reports = append(reports, &entities.KillReport{
Id: c.ID,
- Err: containers.Kill(ic.ClientCxt, c.ID, options.Signal),
+ Err: containers.Kill(ic.ClientCtx, c.ID, opts.Signal, nil),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
+func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, opts entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
reports = []*entities.RestartReport{}
- timeout *int
)
- if options.Timeout != nil {
- t := int(*options.Timeout)
- timeout = &t
+ options := new(containers.RestartOptions)
+ if to := opts.Timeout; to != nil {
+ options.WithTimeout(int(*to))
}
-
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
if err != nil {
return nil, err
}
for _, c := range ctrs {
- if options.Running && c.State != define.ContainerStateRunning.String() {
+ if opts.Running && c.State != define.ContainerStateRunning.String() {
continue
}
reports = append(reports, &entities.RestartReport{
Id: c.ID,
- Err: containers.Restart(ic.ClientCxt, c.ID, timeout),
+ Err: containers.Restart(ic.ClientCtx, c.ID, options),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
- for _, cidFile := range options.CIDFiles {
+func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) {
+ for _, cidFile := range opts.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
return nil, errors.Wrap(err, "error reading CIDFile")
@@ -170,32 +181,35 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
if err != nil {
return nil, err
}
// TODO there is no endpoint for container eviction. Need to discuss
reports := make([]*entities.RmReport, 0, len(ctrs))
+ options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes)
for _, c := range ctrs {
reports = append(reports, &entities.RmReport{
Id: c.ID,
- Err: containers.Remove(ic.ClientCxt, c.ID, &options.Force, &options.Volumes),
+ Err: containers.Remove(ic.ClientCtx, c.ID, options),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
- return containers.Prune(ic.ClientCxt, options.Filters)
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
+ options := new(containers.PruneOptions).WithFilters(opts.Filters)
+ return containers.Prune(ic.ClientCtx, options)
}
-func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
+func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
var (
reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
errs = []error{}
)
+ options := new(containers.InspectOptions).WithSize(opts.Size)
for _, name := range namesOrIds {
- inspect, err := containers.Inspect(ic.ClientCxt, name, &options.Size)
+ inspect, err := containers.Inspect(ic.ClientCtx, name, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -212,30 +226,30 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st
return reports, errs, nil
}
-func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
+func (ic *ContainerEngine) ContainerTop(ctx context.Context, opts entities.TopOptions) (*entities.StringSliceReport, error) {
switch {
- case options.Latest:
+ case opts.Latest:
return nil, errors.New("latest is not supported")
- case options.NameOrID == "":
+ case opts.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
-
- topOutput, err := containers.Top(ic.ClientCxt, options.NameOrID, options.Descriptors)
+ options := new(containers.TopOptions).WithDescriptors(opts.Descriptors)
+ topOutput, err := containers.Top(ic.ClientCtx, opts.NameOrID, options)
if err != nil {
return nil, err
}
return &entities.StringSliceReport{Value: topOutput}, nil
}
-func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, opts entities.CommitOptions) (*entities.CommitReport, error) {
var (
repo string
tag = "latest"
)
- if len(options.ImageName) > 0 {
- ref, err := reference.Parse(options.ImageName)
+ if len(opts.ImageName) > 0 {
+ ref, err := reference.Parse(opts.ImageName)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing reference %q", options.ImageName)
+ return nil, errors.Wrapf(err, "error parsing reference %q", opts.ImageName)
}
if t, ok := ref.(reference.Tagged); ok {
tag = t.Tag()
@@ -244,19 +258,12 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
repo = r.Name()
}
if len(repo) < 1 {
- return nil, errors.Errorf("invalid image name %q", options.ImageName)
+ return nil, errors.Errorf("invalid image name %q", opts.ImageName)
}
}
- commitOpts := containers.CommitOptions{
- Author: &options.Author,
- Changes: options.Changes,
- Comment: &options.Message,
- Format: &options.Format,
- Pause: &options.Pause,
- Repo: &repo,
- Tag: &tag,
- }
- response, err := containers.Commit(ic.ClientCxt, nameOrID, commitOpts)
+ options := new(containers.CommitOptions).WithAuthor(opts.Author).WithChanges(opts.Changes).WithComment(opts.Message)
+ options.WithFormat(opts.Format).WithPause(opts.Pause).WithRepo(repo).WithTag(tag)
+ response, err := containers.Commit(ic.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -274,17 +281,17 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
return err
}
}
- return containers.Export(ic.ClientCxt, nameOrID, w)
+ return containers.Export(ic.ClientCtx, nameOrID, w, nil)
}
-func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
+func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
var (
err error
ctrs = []entities.ListContainer{}
)
- if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
+ if opts.All {
+ allCtrs, err := getContainersByContext(ic.ClientCtx, true, false, []string{})
if err != nil {
return nil, err
}
@@ -296,14 +303,16 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
}
reports := make([]*entities.CheckpointReport, 0, len(ctrs))
+ options := new(containers.CheckpointOptions).WithExport(opts.Export).WithIgnoreRootfs(opts.IgnoreRootFS).WithKeep(opts.Keep)
+ options.WithLeaveRunning(opts.LeaveRunning).WithTCPEstablished(opts.TCPEstablished)
for _, c := range ctrs {
- report, err := containers.Checkpoint(ic.ClientCxt, c.ID, &options.Keep, &options.LeaveRunning, &options.TCPEstablished, &options.IgnoreRootFS, &options.Export)
+ report, err := containers.Checkpoint(ic.ClientCtx, c.ID, options)
if err != nil {
reports = append(reports, &entities.CheckpointReport{Id: c.ID, Err: err})
}
@@ -312,13 +321,13 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
return reports, nil
}
-func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
+func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
var (
err error
ctrs = []entities.ListContainer{}
)
- if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
+ if opts.All {
+ allCtrs, err := getContainersByContext(ic.ClientCtx, true, false, []string{})
if err != nil {
return nil, err
}
@@ -330,14 +339,15 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
}
reports := make([]*entities.RestoreReport, 0, len(ctrs))
+ options := new(containers.RestoreOptions)
for _, c := range ctrs {
- report, err := containers.Restore(ic.ClientCxt, c.ID, &options.Keep, &options.TCPEstablished, &options.IgnoreRootFS, &options.IgnoreStaticIP, &options.IgnoreStaticMAC, &options.Name, &options.Import)
+ report, err := containers.Restore(ic.ClientCtx, c.ID, options)
if err != nil {
reports = append(reports, &entities.RestoreReport{Id: c.ID, Err: err})
}
@@ -347,7 +357,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
- response, err := containers.CreateWithSpec(ic.ClientCxt, s)
+ response, err := containers.CreateWithSpec(ic.ClientCtx, s, nil)
if err != nil {
return nil, err
}
@@ -357,25 +367,20 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
return &entities.ContainerCreateReport{Id: response.ID}, nil
}
-func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, options entities.ContainerLogsOptions) error {
- since := options.Since.Format(time.RFC3339)
- tail := strconv.FormatInt(options.Tail, 10)
- stdout := options.Writer != nil
- opts := containers.LogOptions{
- Follow: &options.Follow,
- Since: &since,
- Stderr: &stdout,
- Stdout: &stdout,
- Tail: &tail,
- Timestamps: &options.Timestamps,
- Until: nil,
- }
+func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, opts entities.ContainerLogsOptions) error {
+ since := opts.Since.Format(time.RFC3339)
+ tail := strconv.FormatInt(opts.Tail, 10)
+ stdout := opts.StdoutWriter != nil
+ stderr := opts.StderrWriter != nil
+ options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithStderr(stderr)
+ options.WithStdout(stdout).WithTail(tail)
var err error
- outCh := make(chan string)
+ stdoutCh := make(chan string)
+ stderrCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
go func() {
- err = containers.Logs(ic.ClientCxt, nameOrIDs[0], opts, outCh, outCh)
+ err = containers.Logs(ic.ClientCtx, nameOrIDs[0], options, stdoutCh, stderrCh)
cancel()
}()
@@ -383,14 +388,20 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string,
select {
case <-ctx.Done():
return err
- case line := <-outCh:
- _, _ = io.WriteString(options.Writer, line+"\n")
+ case line := <-stdoutCh:
+ if opts.StdoutWriter != nil {
+ _, _ = io.WriteString(opts.StdoutWriter, line+"\n")
+ }
+ case line := <-stderrCh:
+ if opts.StderrWriter != nil {
+ _, _ = io.WriteString(opts.StderrWriter, line+"\n")
+ }
}
}
}
-func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
- ctrs, err := getContainersByContext(ic.ClientCxt, false, false, []string{nameOrID})
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, opts entities.AttachOptions) error {
+ ctrs, err := getContainersByContext(ic.ClientCtx, false, false, []string{nameOrID})
if err != nil {
return err
}
@@ -398,8 +409,8 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string,
if ctr.State != define.ContainerStateRunning.String() {
return errors.Errorf("you can only attach to running containers")
}
-
- return containers.Attach(ic.ClientCxt, nameOrID, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
+ options := new(containers.AttachOptions).WithStream(true).WithDetachKeys(opts.DetachKeys)
+ return containers.Attach(ic.ClientCtx, nameOrID, opts.Stdin, opts.Stdout, opts.Stderr, nil, options)
}
func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
@@ -427,16 +438,21 @@ func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCtx, nameOrID, createConfig)
if err != nil {
return 125, err
}
-
- if err := containers.ExecStartAndAttach(ic.ClientCxt, sessionID, &streams); err != nil {
+ startAndAttachOptions := new(containers.ExecStartAndAttachOptions)
+ startAndAttachOptions.WithOutputStream(streams.OutputStream).WithErrorStream(streams.ErrorStream)
+ if streams.InputStream != nil {
+ startAndAttachOptions.WithInputStream(*streams.InputStream)
+ }
+ startAndAttachOptions.WithAttachError(streams.AttachError).WithAttachOutput(streams.AttachOutput).WithAttachInput(streams.AttachInput)
+ if err := containers.ExecStartAndAttach(ic.ClientCtx, sessionID, startAndAttachOptions); err != nil {
return 125, err
}
- inspectOut, err := containers.ExecInspect(ic.ClientCxt, sessionID)
+ inspectOut, err := containers.ExecInspect(ic.ClientCtx, sessionID, nil)
if err != nil {
return 125, err
}
@@ -447,12 +463,12 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, o
func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCtx, nameOrID, createConfig)
if err != nil {
return "", err
}
- if err := containers.ExecStart(ic.ClientCxt, sessionID); err != nil {
+ if err := containers.ExecStart(ic.ClientCtx, sessionID, nil); err != nil {
return "", err
}
@@ -462,15 +478,23 @@ func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID s
func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input, output, errput *os.File) error { //nolint
attachErr := make(chan error)
attachReady := make(chan bool)
+ options := new(containers.AttachOptions).WithStream(true)
+ if dk := detachKeys; dk != nil {
+ options.WithDetachKeys(*dk)
+ }
go func() {
- err := containers.Attach(ic.ClientCxt, name, detachKeys, bindings.PFalse, bindings.PTrue, input, output, errput, attachReady)
+ err := containers.Attach(ic.ClientCtx, name, input, output, errput, attachReady, options)
attachErr <- err
}()
// Wait for the attach to actually happen before starting
// the container.
select {
case <-attachReady:
- if err := containers.Start(ic.ClientCxt, name, detachKeys); err != nil {
+ startOptions := new(containers.StartOptions)
+ if dk := detachKeys; dk != nil {
+ startOptions.WithDetachKeys(*dk)
+ }
+ if err := containers.Start(ic.ClientCtx, name, startOptions); err != nil {
return err
}
case err := <-attachErr:
@@ -483,10 +507,11 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
var exitCode = define.ExecErrorCodeGeneric
- ctrs, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
+ removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false)
// There can only be one container if attach was used
for i, ctr := range ctrs {
name := ctr.ID
@@ -515,7 +540,30 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
reports = append(reports, &report)
return reports, errors.Wrapf(report.Err, "unable to start container %s", name)
}
- exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
+ if ctr.AutoRemove {
+ // Defer the removal, so we can return early if needed and
+ // de-spaghetti the code.
+ defer func() {
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCtx, ctr.ID, nil)
+ if err != nil {
+ logrus.Errorf("Failed to check if %s should restart: %v", ctr.ID, err)
+ return
+ }
+
+ if !shouldRestart {
+ if err := containers.Remove(ic.ClientCtx, ctr.ID, removeOptions); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", ctr.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", ctr.ID, err)
+ }
+ }
+ }
+ }()
+ }
+
+ exitCode, err := containers.Wait(ic.ClientCtx, name, nil)
if err == define.ErrNoSuchCtr {
// Check events
event, err := ic.GetLastContainerEvent(ctx, name, events.Exited)
@@ -533,8 +581,20 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
}
// Start the container if it's not running already.
if !ctrRunning {
- err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
+
+ err = containers.Start(ic.ClientCtx, name, new(containers.StartOptions).WithDetachKeys(options.DetachKeys))
if err != nil {
+ if ctr.AutoRemove {
+ rmOptions := new(containers.RemoveOptions).WithForce(false).WithVolumes(true)
+ if err := containers.Remove(ic.ClientCtx, ctr.ID, rmOptions); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", ctr.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", ctr.ID, err)
+ }
+ }
+ }
report.Err = errors.Wrapf(err, "unable to start container %q", name)
report.ExitCode = define.ExitCode(err)
reports = append(reports, &report)
@@ -547,12 +607,14 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
return reports, nil
}
-func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
- return containers.List(ic.ClientCxt, options.Filters, &options.All, &options.Last, &options.Namespace, &options.Size, &options.Sync)
+func (ic *ContainerEngine) ContainerList(ctx context.Context, opts entities.ContainerListOptions) ([]entities.ListContainer, error) {
+ options := new(containers.ListOptions).WithFilters(opts.Filters).WithAll(opts.All).WithLast(opts.Last)
+ options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync)
+ return containers.List(ic.ClientCtx, options)
}
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
- con, err := containers.CreateWithSpec(ic.ClientCxt, opts.Spec)
+ con, err := containers.CreateWithSpec(ic.ClientCtx, opts.Spec, nil)
if err != nil {
return nil, err
}
@@ -569,7 +631,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if opts.Detach {
// Detach and return early
- err := containers.Start(ic.ClientCxt, con.ID, nil)
+ err := containers.Start(ic.ClientCtx, con.ID, nil)
if err != nil {
report.ExitCode = define.ExitCode(err)
}
@@ -584,7 +646,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
report.ExitCode = define.ExitCode(err)
if opts.Rm {
- if rmErr := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); rmErr != nil {
+ if rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); rmErr != nil {
logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID)
}
}
@@ -595,14 +657,14 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Defer the removal, so we can return early if needed and
// de-spaghetti the code.
defer func() {
- shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCtx, con.ID, nil)
if err != nil {
logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
return
}
if !shouldRestart {
- if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
+ if err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); err != nil {
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
errorhandling.Contains(err, define.ErrCtrRemoved) {
logrus.Warnf("Container %s does not exist: %v", con.ID, err)
@@ -615,7 +677,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
// Wait
- exitCode, waitErr := containers.Wait(ic.ClientCxt, con.ID, nil)
+ exitCode, waitErr := containers.Wait(ic.ClientCtx, con.ID, nil)
if waitErr == nil {
report.ExitCode = int(exitCode)
return &report, nil
@@ -664,7 +726,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := containers.Diff(ic.ClientCxt, nameOrID)
+ changes, err := containers.Diff(ic.ClientCtx, nameOrID, nil)
return &entities.DiffReport{Changes: changes}, err
}
@@ -673,13 +735,13 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
for _, ctr := range ctrs {
- err := containers.ContainerInit(ic.ClientCxt, ctr.ID)
+ err := containers.ContainerInit(ic.ClientCtx, ctr.ID, nil)
// When using all, it is NOT considered an error if a container
// has already been init'd.
if err != nil && options.All && strings.Contains(errors.Cause(err).Error(), define.ErrCtrStateInvalid.Error()) {
@@ -713,7 +775,7 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
if len(nameOrID) > 0 {
namesOrIds = append(namesOrIds, nameOrID)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -731,9 +793,16 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
return reports, nil
}
-func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- return nil
- // return containers.Copy(ic.ClientCxt, source, dest, options)
+func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ return containers.CopyFromArchive(ic.ClientCtx, nameOrID, path, reader)
+}
+
+func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ return containers.CopyToArchive(ic.ClientCtx, nameOrID, path, writer)
+}
+
+func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, path string) (*entities.ContainerStatReport, error) {
+ return containers.Stat(ic.ClientCtx, nameOrID, path)
}
// Shutdown Libpod engine
@@ -744,10 +813,10 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
if options.Latest {
return nil, errors.New("latest is not supported for the remote client")
}
- return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
+ return containers.Stats(ic.ClientCtx, namesOrIds, new(containers.StatsOptions).WithStream(options.Stream))
}
-// ShouldRestart reports back whether the containre will restart
+// ShouldRestart reports back whether the container will restart
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
- return containers.ShouldRestart(ic.ClientCxt, id)
+ return containers.ShouldRestart(ic.ClientCtx, id, nil)
}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
index 53bae6cef..cec6c749c 100644
--- a/pkg/domain/infra/tunnel/events.go
+++ b/pkg/domain/infra/tunnel/events.go
@@ -2,7 +2,6 @@ package tunnel
import (
"context"
- // "fmt"
"strings"
"github.com/containers/podman/v2/libpod/events"
@@ -29,7 +28,8 @@ func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptio
}
close(opts.EventChan)
}()
- return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters, &opts.Stream)
+ options := new(system.EventsOptions).WithFilters(filters).WithSince(opts.Since).WithStream(opts.Stream).WithUntil(opts.Until)
+ return system.Events(ic.ClientCtx, binChan, nil, options)
}
// GetLastContainerEvent takes a container name or ID and an event status and returns
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index ebbfa143f..6d68157c1 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -7,10 +7,16 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
- return generate.Systemd(ic.ClientCxt, nameOrID, options)
+func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, opts entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+ options := new(generate.SystemdOptions).WithUseName(opts.Name).WithContainerPrefix(opts.ContainerPrefix).WithNew(opts.New)
+ options.WithPodPrefix(opts.PodPrefix).WithRestartPolicy(opts.RestartPolicy).WithSeparator(opts.Separator)
+ if to := opts.StopTimeout; to != nil {
+ options.WithStopTimeout(*opts.StopTimeout)
+ }
+ return generate.Systemd(ic.ClientCtx, nameOrID, options)
}
-func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
- return generate.Kube(ic.ClientCxt, nameOrIDs, options)
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, opts entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ options := new(generate.KubeOptions).WithService(opts.Service)
+ return generate.Kube(ic.ClientCtx, nameOrIDs, options)
}
diff --git a/pkg/domain/infra/tunnel/healthcheck.go b/pkg/domain/infra/tunnel/healthcheck.go
index ac28712ce..3daf22647 100644
--- a/pkg/domain/infra/tunnel/healthcheck.go
+++ b/pkg/domain/infra/tunnel/healthcheck.go
@@ -9,5 +9,5 @@ import (
)
func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrID string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
- return containers.RunHealthCheck(ic.ClientCxt, nameOrID)
+ return containers.RunHealthCheck(ic.ClientCtx, nameOrID, nil)
}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 63f9546be..0a806d860 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -4,7 +4,6 @@ import (
"context"
"github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/pods"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -18,8 +17,8 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b
if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup containers and all")
}
-
- allContainers, err := containers.List(contextWithConnection, nil, bindings.PTrue, nil, nil, nil, bindings.PTrue)
+ options := new(containers.ListOptions).WithAll(true).WithSync(true)
+ allContainers, err := containers.List(contextWithConnection, options)
if err != nil {
return nil, err
}
@@ -38,7 +37,7 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b
// First determine if the container exists by doing an inspect.
// Inspect takes supports names and IDs and let's us determine
// a containers full ID.
- inspectData, err := containers.Inspect(contextWithConnection, nameOrID, bindings.PFalse)
+ inspectData, err := containers.Inspect(contextWithConnection, nameOrID, new(containers.InspectOptions).WithSize(false))
if err != nil {
if ignore && errorhandling.Contains(err, define.ErrNoSuchCtr) {
continue
@@ -90,7 +89,7 @@ func getPodsByContext(contextWithConnection context.Context, all bool, namesOrID
// First determine if the pod exists by doing an inspect.
// Inspect takes supports names and IDs and let's us determine
// a containers full ID.
- inspectData, err := pods.Inspect(contextWithConnection, nameOrID)
+ inspectData, err := pods.Inspect(contextWithConnection, nameOrID, nil)
if err != nil {
if errorhandling.Contains(err, define.ErrNoSuchPod) {
return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrID)
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 09931de12..fba60235e 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -4,25 +4,32 @@ import (
"context"
"io/ioutil"
"os"
+ "strconv"
"strings"
"time"
+ "github.com/containers/podman/v2/libpod/image"
+
+ "github.com/containers/image/v5/types"
+
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
images "github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/utils"
utils2 "github.com/containers/podman/v2/utils"
"github.com/pkg/errors"
)
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
- found, err := images.Exists(ir.ClientCxt, nameOrID)
+ found, err := images.Exists(ir.ClientCtx, nameOrID)
return &entities.BoolReport{Value: found}, err
}
func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
- return images.BatchRemove(ir.ClientCxt, imagesArg, opts)
+ options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All)
+ return images.Remove(ir.ClientCtx, imagesArg, options)
}
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
@@ -32,13 +39,14 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
- images, err := images.List(ir.ClientCxt, &opts.All, filters)
+ options := new(images.ListOptions).WithAll(opts.All).WithFilters(filters)
+ psImages, err := images.List(ir.ClientCtx, options)
if err != nil {
return nil, err
}
- is := make([]*entities.ImageSummary, len(images))
- for i, img := range images {
+ is := make([]*entities.ImageSummary, len(psImages))
+ for i, img := range psImages {
hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil {
return nil, err
@@ -57,7 +65,8 @@ func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options ent
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
- results, err := images.History(ir.ClientCxt, nameOrID)
+ options := new(images.HistoryOptions)
+ results, err := images.History(ir.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -82,37 +91,41 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
return &history, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
filters := make(map[string][]string, len(opts.Filter))
for _, filter := range opts.Filter {
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
-
- results, err := images.Prune(ir.ClientCxt, &opts.All, filters)
+ options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
+ reports, err := images.Prune(ir.ClientCtx, options)
if err != nil {
return nil, err
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- Size: 0,
- }
- return &report, nil
+ return reports, nil
}
-func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
- pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options)
+func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) {
+ options := new(images.PullOptions)
+ options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithOverrideArch(opts.OverrideArch).WithOverrideOS(opts.OverrideOS)
+ options.WithOverrideVariant(opts.OverrideVariant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy)
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ options.WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithUsername(opts.Username)
+ pulledImages, err := images.Pull(ir.ClientCtx, rawImage, options)
if err != nil {
return nil, err
}
return &entities.ImagePullReport{Images: pulledImages}, nil
}
-func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
+func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageTagOptions) error {
+ options := new(images.TagOptions)
for _, newTag := range tags {
var (
tag, repo string
@@ -130,16 +143,17 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
+ if err := images.Tag(ir.ClientCtx, nameOrID, tag, repo, options); err != nil {
return err
}
}
return nil
}
-func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
+func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageUntagOptions) error {
+ options := new(images.UntagOptions)
if len(tags) == 0 {
- return images.Untag(ir.ClientCxt, nameOrID, "", "")
+ return images.Untag(ir.ClientCtx, nameOrID, "", "", options)
}
for _, newTag := range tags {
@@ -159,7 +173,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
+ if err := images.Untag(ir.ClientCtx, nameOrID, tag, repo, options); err != nil {
return err
}
}
@@ -167,10 +181,11 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
}
func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
+ options := new(images.GetOptions).WithSize(opts.Size)
reports := []*entities.ImageInspectReport{}
errs := []error{}
for _, i := range namesOrIDs {
- r, err := images.GetImage(ir.ClientCxt, i, &opts.Size)
+ r, err := images.GetImage(ir.ClientCtx, i, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -204,68 +219,73 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
if len(opts.Tag) > 0 {
ref += ":" + opts.Tag
}
- return images.Load(ir.ClientCxt, f, &ref)
+ options := new(images.LoadOptions).WithReference(ref)
+ return images.Load(ir.ClientCtx, f, options)
}
func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
var (
- err error
- sourceURL *string
- f *os.File
+ err error
+ f *os.File
)
+ options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference)
if opts.SourceIsURL {
- sourceURL = &opts.Source
+ options.WithURL(opts.Source)
} else {
f, err = os.Open(opts.Source)
if err != nil {
return nil, err
}
}
- return images.Import(ir.ClientCxt, opts.Changes, &opts.Message, &opts.Reference, sourceURL, f)
+ return images.Import(ir.ClientCtx, f, options)
}
-func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
- return images.Push(ir.ClientCxt, source, destination, options)
+func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, opts entities.ImagePushOptions) error {
+ options := new(images.PushOptions)
+ options.WithUsername(opts.Username).WithSignaturePolicy(opts.SignaturePolicy).WithQuiet(opts.Quiet)
+ options.WithPassword(opts.Password).WithCertDir(opts.CertDir).WithAuthfile(opts.Authfile)
+ options.WithCompress(opts.Compress).WithDigestFile(opts.DigestFile).WithFormat(opts.Format)
+ options.WithRemoveSignatures(opts.RemoveSignatures).WithSignBy(opts.SignBy)
+
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ return images.Push(ir.ClientCtx, source, destination, options)
}
-func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
+func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, opts entities.ImageSaveOptions) error {
var (
f *os.File
err error
)
- switch options.Format {
+ options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress)
+
+ switch opts.Format {
case "oci-dir", "docker-dir":
f, err = ioutil.TempFile("", "podman_save")
if err == nil {
defer func() { _ = os.Remove(f.Name()) }()
}
default:
- f, err = os.Create(options.Output)
+ f, err = os.Create(opts.Output)
}
if err != nil {
return err
}
- if options.MultiImageArchive {
- exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress)
- if err := f.Close(); err != nil {
- return err
- }
- if exErr != nil {
- return exErr
- }
- } else {
- // FIXME: tags are entirely ignored here but shouldn't.
- exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress)
- if err := f.Close(); err != nil {
- return err
- }
- if exErr != nil {
- return exErr
- }
+ exErr := images.Export(ir.ClientCtx, append([]string{nameOrID}, tags...), f, options)
+ if err := f.Close(); err != nil {
+ return err
+ }
+ if exErr != nil {
+ return exErr
}
- if options.Format != "oci-dir" && options.Format != "docker-dir" {
+ if opts.Format != "oci-dir" && opts.Format != "docker-dir" {
return nil
}
@@ -273,25 +293,26 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string,
if err != nil {
return err
}
- info, err := os.Stat(options.Output)
+ info, err := os.Stat(opts.Output)
switch {
case err == nil:
if info.Mode().IsRegular() {
- return errors.Errorf("%q already exists as a regular file", options.Output)
+ return errors.Errorf("%q already exists as a regular file", opts.Output)
}
case os.IsNotExist(err):
- if err := os.Mkdir(options.Output, 0755); err != nil {
+ if err := os.Mkdir(opts.Output, 0755); err != nil {
return err
}
default:
return err
}
- return utils2.UntarToFileSystem(options.Output, f, nil)
+ return utils2.UntarToFileSystem(opts.Output, f, nil)
}
// Diff reports the changes to the given image
func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := images.Diff(ir.ClientCxt, nameOrID)
+ options := new(images.DiffOptions)
+ changes, err := images.Diff(ir.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -299,7 +320,34 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.Dif
}
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
- return images.Search(ir.ClientCxt, term, opts)
+ mappedFilters := make(map[string][]string)
+ filters, err := image.ParseSearchFilter(opts.Filters)
+ if err != nil {
+ return nil, err
+ }
+ if stars := filters.Stars; stars > 0 {
+ mappedFilters["stars"] = []string{strconv.Itoa(stars)}
+ }
+
+ if official := filters.IsOfficial; official != types.OptionalBoolUndefined {
+ mappedFilters["is-official"] = []string{strconv.FormatBool(official == types.OptionalBoolTrue)}
+ }
+
+ if automated := filters.IsAutomated; automated != types.OptionalBoolUndefined {
+ mappedFilters["is-automated"] = []string{strconv.FormatBool(automated == types.OptionalBoolTrue)}
+ }
+
+ options := new(images.SearchOptions)
+ options.WithAuthfile(opts.Authfile).WithFilters(mappedFilters).WithLimit(opts.Limit)
+ options.WithListTags(opts.ListTags).WithNoTrunc(opts.NoTrunc)
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ return images.Search(ir.ClientCtx, term, options)
}
func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
@@ -307,7 +355,7 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
}
func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) {
- report, err := images.Build(ir.ClientCxt, containerFiles, opts)
+ report, err := images.Build(ir.ClientCtx, containerFiles, opts)
if err != nil {
return nil, err
}
@@ -326,7 +374,8 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en
}
func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
- return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires)
+ options := new(images.TreeOptions).WithWhatRequires(opts.WhatRequires)
+ return images.Tree(ir.ClientCtx, nameOrID, options)
}
// Shutdown Libpod engine
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index a09b502b4..c71349fe0 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -6,7 +6,6 @@ import (
"fmt"
"strings"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/bindings/manifests"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -14,7 +13,8 @@ import (
// ManifestCreate implements manifest create via ImageEngine
func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
- imageID, err := manifests.Create(ir.ClientCxt, names, images, &opts.All)
+ options := new(manifests.CreateOptions).WithAll(opts.All)
+ imageID, err := manifests.Create(ir.ClientCtx, names, images, options)
if err != nil {
return imageID, errors.Wrapf(err, "error creating manifest")
}
@@ -23,7 +23,7 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []strin
// ManifestInspect returns contents of manifest list with given name
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
- list, err := manifests.Inspect(ir.ClientCxt, name)
+ list, err := manifests.Inspect(ir.ClientCtx, name, nil)
if err != nil {
return nil, errors.Wrapf(err, "error getting content of manifest list or image %s", name)
}
@@ -37,15 +37,8 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
// ManifestAdd adds images to the manifest list
func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAddOptions) (string, error) {
- manifestAddOpts := image.ManifestAddOpts{
- All: opts.All,
- Arch: opts.Arch,
- Features: opts.Features,
- Images: opts.Images,
- OS: opts.OS,
- OSVersion: opts.OSVersion,
- Variant: opts.Variant,
- }
+ options := new(manifests.AddOptions).WithAll(opts.All).WithArch(opts.Arch).WithVariant(opts.Variant)
+ options.WithFeatures(opts.Features).WithImages(opts.Images).WithOS(opts.OS).WithOSVersion(opts.OSVersion)
if len(opts.Annotation) != 0 {
annotations := make(map[string]string)
for _, annotationSpec := range opts.Annotation {
@@ -55,9 +48,10 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
}
annotations[spec[0]] = spec[1]
}
- manifestAddOpts.Annotation = annotations
+ options.WithAnnotation(annotations)
}
- listID, err := manifests.Add(ir.ClientCxt, opts.Images[1], manifestAddOpts)
+
+ listID, err := manifests.Add(ir.ClientCtx, opts.Images[1], options)
if err != nil {
return listID, errors.Wrapf(err, "error adding to manifest list %s", opts.Images[1])
}
@@ -71,7 +65,7 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
// ManifestRemove removes the digest from manifest list
func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) {
- updatedListID, err := manifests.Remove(ir.ClientCxt, names[0], names[1])
+ updatedListID, err := manifests.Remove(ir.ClientCtx, names[0], names[1], nil)
if err != nil {
return updatedListID, errors.Wrapf(err, "error removing from manifest %s", names[0])
}
@@ -79,7 +73,8 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
}
// ManifestPush pushes a manifest list or image index to the destination
-func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error {
- _, err := manifests.Push(ir.ClientCxt, names[0], &names[1], &opts.All)
+func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ManifestPushOptions) error {
+ options := new(manifests.PushOptions).WithAll(opts.All)
+ _, err := manifests.Push(ir.ClientCtx, name, destination, options)
return err
}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 4845980f6..9afb8db02 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -8,17 +8,19 @@ import (
"github.com/pkg/errors"
)
-func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
- return network.List(ic.ClientCxt, options)
+func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
+ options := new(network.ListOptions).WithFilters(opts.Filters)
+ return network.List(ic.ClientCtx, options)
}
-func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
+func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
var (
reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds))
errs = []error{}
)
+ options := new(network.InspectOptions)
for _, name := range namesOrIds {
- report, err := network.Inspect(ic.ClientCxt, name)
+ report, err := network.Inspect(ic.ClientCtx, name, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -35,14 +37,15 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
return reports, errs, nil
}
-func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, options entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
+func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, opts entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
return nil, errors.New("not implemented")
}
-func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
+func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, opts entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds))
+ options := new(network.RemoveOptions).WithForce(opts.Force)
for _, name := range namesOrIds {
- response, err := network.Remove(ic.ClientCxt, name, &options.Force)
+ response, err := network.Remove(ic.ClientCtx, name, options)
if err != nil {
report := &entities.NetworkRmReport{
Name: name,
@@ -56,16 +59,21 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
return reports, nil
}
-func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
- return network.Create(ic.ClientCxt, options, &name)
+func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, opts entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
+ options := new(network.CreateOptions).WithName(name).WithDisableDNS(opts.DisableDNS).WithDriver(opts.Driver).WithGateway(opts.Gateway)
+ options.WithInternal(opts.Internal).WithIPRange(opts.Range).WithIPv6(opts.IPv6).WithLabels(opts.Labels).WithIPv6(opts.IPv6)
+ options.WithMacVLAN(opts.MacVLAN).WithOptions(opts.Options).WithSubnet(opts.Subnet)
+ return network.Create(ic.ClientCtx, options)
}
// NetworkDisconnect removes a container from a given network
-func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
- return network.Disconnect(ic.ClientCxt, networkname, options)
+func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, opts entities.NetworkDisconnectOptions) error {
+ options := new(network.DisconnectOptions).WithForce(opts.Force)
+ return network.Disconnect(ic.ClientCtx, networkname, opts.Container, options)
}
// NetworkConnect removes a container from a given network
-func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
- return network.Connect(ic.ClientCxt, networkname, options)
+func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, opts entities.NetworkConnectOptions) error {
+ options := new(network.ConnectOptions).WithAliases(opts.Aliases)
+ return network.Connect(ic.ClientCtx, networkname, opts.Container, options)
}
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index 26f23093b..2318b9caa 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -3,10 +3,21 @@ package tunnel
import (
"context"
+ "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/bindings/play"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
- return play.Kube(ic.ClientCxt, path, options)
+func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+ options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
+ options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
+ options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot)
+
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ options.WithSkipTLSVerify(s == types.OptionalBoolTrue)
+ }
+ if start := opts.Start; start != types.OptionalBoolUndefined {
+ options.WithStart(start == types.OptionalBoolTrue)
+ }
+ return play.Kube(ic.ClientCtx, path, options)
}
diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go
index ee4978787..aa7b92fa7 100644
--- a/pkg/domain/infra/tunnel/pods.go
+++ b/pkg/domain/infra/tunnel/pods.go
@@ -12,23 +12,24 @@ import (
)
func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
- exists, err := pods.Exists(ic.ClientCxt, nameOrID)
+ exists, err := pods.Exists(ic.ClientCtx, nameOrID)
return &entities.BoolReport{Value: exists}, err
}
-func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, options entities.PodKillOptions) ([]*entities.PodKillReport, error) {
- _, err := util.ParseSignal(options.Signal)
+func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opts entities.PodKillOptions) ([]*entities.PodKillReport, error) {
+ _, err := util.ParseSignal(opts.Signal)
if err != nil {
return nil, err
}
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodKillReport, 0, len(foundPods))
+ options := new(pods.KillOptions).WithSignal(opts.Signal)
for _, p := range foundPods {
- response, err := pods.Kill(ic.ClientCxt, p.Id, &options.Signal)
+ response, err := pods.Kill(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodKillReport{
Errs: []error{err},
@@ -43,13 +44,13 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodPauseReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Pause(ic.ClientCxt, p.Id)
+ response, err := pods.Pause(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodPauseReport{
Errs: []error{err},
@@ -64,13 +65,13 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, options entities.PodunpauseOptions) ([]*entities.PodUnpauseReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodUnpauseReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Unpause(ic.ClientCxt, p.Id)
+ response, err := pods.Unpause(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodUnpauseReport{
Errs: []error{err},
@@ -84,18 +85,19 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
return reports, nil
}
-func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
+func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opts entities.PodStopOptions) ([]*entities.PodStopReport, error) {
timeout := -1
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
+ if err != nil && !(opts.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
- if options.Timeout != -1 {
- timeout = options.Timeout
+ if opts.Timeout != -1 {
+ timeout = opts.Timeout
}
reports := make([]*entities.PodStopReport, 0, len(foundPods))
+ options := new(pods.StopOptions).WithTimeout(timeout)
for _, p := range foundPods {
- response, err := pods.Stop(ic.ClientCxt, p.Id, &timeout)
+ response, err := pods.Stop(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodStopReport{
Errs: []error{err},
@@ -110,13 +112,13 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, options entities.PodRestartOptions) ([]*entities.PodRestartReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodRestartReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Restart(ic.ClientCxt, p.Id)
+ response, err := pods.Restart(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodRestartReport{
Errs: []error{err},
@@ -131,13 +133,13 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, options entities.PodStartOptions) ([]*entities.PodStartReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodStartReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Start(ic.ClientCxt, p.Id)
+ response, err := pods.Start(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodStartReport{
Errs: []error{err},
@@ -151,14 +153,15 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
return reports, nil
}
-func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
+func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, opts entities.PodRmOptions) ([]*entities.PodRmReport, error) {
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
+ if err != nil && !(opts.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
reports := make([]*entities.PodRmReport, 0, len(foundPods))
+ options := new(pods.RemoveOptions).WithForce(opts.Force)
for _, p := range foundPods {
- response, err := pods.Remove(ic.ClientCxt, p.Id, &options.Force)
+ response, err := pods.Remove(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodRmReport{
Err: err,
@@ -173,32 +176,33 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
}
func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneOptions) ([]*entities.PodPruneReport, error) {
- return pods.Prune(ic.ClientCxt)
+ return pods.Prune(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator()
opts.ToPodSpecGen(podSpec)
- return pods.CreatePodFromSpec(ic.ClientCxt, podSpec)
+ return pods.CreatePodFromSpec(ic.ClientCtx, podSpec, nil)
}
-func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOptions) (*entities.StringSliceReport, error) {
+func (ic *ContainerEngine) PodTop(ctx context.Context, opts entities.PodTopOptions) (*entities.StringSliceReport, error) {
switch {
- case options.Latest:
+ case opts.Latest:
return nil, errors.New("latest is not supported")
- case options.NameOrID == "":
+ case opts.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
-
- topOutput, err := pods.Top(ic.ClientCxt, options.NameOrID, options.Descriptors)
+ options := new(pods.TopOptions).WithDescriptors(opts.Descriptors)
+ topOutput, err := pods.Top(ic.ClientCtx, opts.NameOrID, options)
if err != nil {
return nil, err
}
return &entities.StringSliceReport{Value: topOutput}, nil
}
-func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
- return pods.List(ic.ClientCxt, options.Filters)
+func (ic *ContainerEngine) PodPs(ctx context.Context, opts entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
+ options := new(pods.ListOptions).WithFilters(opts.Filters)
+ return pods.List(ic.ClientCtx, options)
}
func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodInspectOptions) (*entities.PodInspectReport, error) {
@@ -208,9 +212,10 @@ func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodI
case options.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
- return pods.Inspect(ic.ClientCxt, options.NameOrID)
+ return pods.Inspect(ic.ClientCtx, options.NameOrID, nil)
}
-func (ic *ContainerEngine) PodStats(ctx context.Context, namesOrIds []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
- return pods.Stats(ic.ClientCxt, namesOrIds, options)
+func (ic *ContainerEngine) PodStats(ctx context.Context, namesOrIds []string, opts entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
+ options := new(pods.StatsOptions).WithAll(opts.All)
+ return pods.Stats(ic.ClientCtx, namesOrIds, options)
}
diff --git a/pkg/domain/infra/tunnel/runtime.go b/pkg/domain/infra/tunnel/runtime.go
index 357e2c390..6542ea5b7 100644
--- a/pkg/domain/infra/tunnel/runtime.go
+++ b/pkg/domain/infra/tunnel/runtime.go
@@ -6,15 +6,15 @@ import (
// Image-related runtime using an ssh-tunnel to utilize Podman service
type ImageEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
// Container-related runtime using an ssh-tunnel to utilize Podman service
type ContainerEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
// Container-related runtime using an ssh-tunnel to utilize Podman service
type SystemEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index f3e8fbcb1..a46b164a5 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -11,7 +11,7 @@ import (
)
func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
- return system.Info(ic.ClientCxt)
+ return system.Info(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
@@ -19,12 +19,13 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
// SystemPrune prunes unused data from the system.
-func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
- return system.Prune(ic.ClientCxt, &options.All, &options.Volume)
+func (ic *ContainerEngine) SystemPrune(ctx context.Context, opts entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
+ options := new(system.PruneOptions).WithAll(opts.All).WithVolumes(opts.Volume).WithFilters(opts.Filters)
+ return system.Prune(ic.ClientCtx, options)
}
func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) {
- return system.DiskUsage(ic.ClientCxt)
+ return system.DiskUsage(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
@@ -32,5 +33,5 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
}
func (ic ContainerEngine) Version(ctx context.Context) (*entities.SystemVersionReport, error) {
- return system.Version(ic.ClientCxt)
+ return system.Version(ic.ClientCtx, nil)
}
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index c0df2bb7b..10e8d7da8 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -5,11 +5,12 @@ import (
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
- response, err := volumes.Create(ic.ClientCxt, opts)
+ response, err := volumes.Create(ic.ClientCtx, opts, nil)
if err != nil {
return nil, err
}
@@ -18,7 +19,7 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
if opts.All {
- vols, err := volumes.List(ic.ClientCxt, nil)
+ vols, err := volumes.List(ic.ClientCtx, nil)
if err != nil {
return nil, err
}
@@ -28,8 +29,9 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
}
reports := make([]*entities.VolumeRmReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
+ options := new(volumes.RemoveOptions).WithForce(opts.Force)
reports = append(reports, &entities.VolumeRmReport{
- Err: volumes.Remove(ic.ClientCxt, id, &opts.Force),
+ Err: volumes.Remove(ic.ClientCtx, id, options),
Id: id,
})
}
@@ -42,7 +44,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
errs = []error{}
)
if opts.All {
- vols, err := volumes.List(ic.ClientCxt, nil)
+ vols, err := volumes.List(ic.ClientCtx, nil)
if err != nil {
return nil, nil, err
}
@@ -51,7 +53,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
}
for _, id := range namesOrIds {
- data, err := volumes.Inspect(ic.ClientCxt, id)
+ data, err := volumes.Inspect(ic.ClientCtx, id, nil)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -68,10 +70,12 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return volumes.Prune(ic.ClientCxt)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
+ options := new(volumes.PruneOptions).WithFilters(opts.Filters)
+ return volumes.Prune(ic.ClientCtx, options)
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
- return volumes.List(ic.ClientCxt, opts.Filter)
+ options := new(volumes.ListOptions).WithFilters(opts.Filter)
+ return volumes.List(ic.ClientCtx, options)
}
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
index ca6b60bc5..21df261fb 100644
--- a/pkg/errorhandling/errorhandling.go
+++ b/pkg/errorhandling/errorhandling.go
@@ -19,7 +19,12 @@ func JoinErrors(errs []error) error {
// blank lines when printing the error.
var multiE *multierror.Error
multiE = multierror.Append(multiE, errs...)
- return errors.New(strings.TrimSpace(multiE.ErrorOrNil().Error()))
+
+ finalErr := multiE.ErrorOrNil()
+ if finalErr == nil {
+ return finalErr
+ }
+ return errors.New(strings.TrimSpace(finalErr.Error()))
}
// ErrorsToString converts the slice of errors into a slice of corresponding
diff --git a/pkg/hooks/README.md b/pkg/hooks/README.md
index 61fbbcac6..f6a03a775 100644
--- a/pkg/hooks/README.md
+++ b/pkg/hooks/README.md
@@ -9,7 +9,7 @@ This can cause some performance issues.
Also a lot of hooks just check if certain configuration is set and then exit early, without doing anything.
For example the [oci-systemd-hook][] only executes if the command is `init` or `systemd`, otherwise it just exits.
This means if we automatically enabled all hooks, every container would have to execute `oci-systemd-hook`, even if they don't run systemd inside of the container.
-Performance would also suffer if we exectuted each hook at each stage ([pre-start][], [post-start][], and [post-stop][]).
+Performance would also suffer if we executed each hook at each stage ([pre-start][], [post-start][], and [post-stop][]).
The hooks configuration is documented in [`oci-hooks.5`](docs/oci-hooks.5.md).
diff --git a/pkg/hooks/exec/exec.go b/pkg/hooks/exec/exec.go
index 77b350573..f6b6636ad 100644
--- a/pkg/hooks/exec/exec.go
+++ b/pkg/hooks/exec/exec.go
@@ -1,4 +1,4 @@
-// Package exec provides utilities for executing Open Container Initative runtime hooks.
+// Package exec provides utilities for executing Open Container Initiative runtime hooks.
package exec
import (
diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go
index 6257529ab..6cb81e573 100644
--- a/pkg/hooks/hooks.go
+++ b/pkg/hooks/hooks.go
@@ -46,7 +46,7 @@ type namedHook struct {
//
// extensionStages allows callers to add additional stages beyond
// those specified in the OCI Runtime Specification and to control
-// OCI-defined stages instead of delagating to the OCI runtime. See
+// OCI-defined stages instead of delegating to the OCI runtime. See
// Hooks() for more information.
func New(ctx context.Context, directories []string, extensionStages []string) (manager *Manager, err error) {
manager = &Manager{
diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go
index ff5691203..ed5241632 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -162,7 +162,7 @@ func NewNS() (ns.NetNS, error) {
// bind mount the netns from the current thread (from /proc) onto the
// mount point. This causes the namespace to persist, even when there
// are no threads in the ns. Make this a shared mount; it needs to be
- // back-propogated to the host
+ // back-propagated to the host
err = unix.Mount(threadNsPath, nsPath, "none", unix.MS_BIND|unix.MS_SHARED|unix.MS_REC, "")
if err != nil {
err = fmt.Errorf("failed to bind mount ns at %s: %v", nsPath, err)
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index cfdf3ee49..9e0dcb728 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -11,8 +11,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/filters"
psdefine "github.com/containers/podman/v2/pkg/ps/define"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -27,7 +27,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
all := options.All || options.Last > 0
if len(options.Filters) > 0 {
for k, v := range options.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime)
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
all = true
}
if !all {
- runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
+ runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
if err != nil {
return nil, err
}
@@ -179,24 +179,25 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
}
ps := entities.ListContainer{
- Command: conConfig.Command,
- Created: conConfig.CreatedTime,
- Exited: exited,
- ExitCode: exitCode,
- ExitedAt: exitedTime.Unix(),
- ID: conConfig.ID,
- Image: conConfig.RootfsImageName,
- ImageID: conConfig.RootfsImageID,
- IsInfra: conConfig.IsInfra,
- Labels: conConfig.Labels,
- Mounts: ctr.UserVolumes(),
- Names: []string{conConfig.Name},
- Pid: pid,
- Pod: conConfig.Pod,
- Ports: portMappings,
- Size: size,
- StartedAt: startedTime.Unix(),
- State: conState.String(),
+ AutoRemove: ctr.AutoRemove(),
+ Command: conConfig.Command,
+ Created: conConfig.CreatedTime,
+ Exited: exited,
+ ExitCode: exitCode,
+ ExitedAt: exitedTime.Unix(),
+ ID: conConfig.ID,
+ Image: conConfig.RootfsImageName,
+ ImageID: conConfig.RootfsImageID,
+ IsInfra: conConfig.IsInfra,
+ Labels: conConfig.Labels,
+ Mounts: ctr.UserVolumes(),
+ Names: []string{conConfig.Name},
+ Pid: pid,
+ Pod: conConfig.Pod,
+ Ports: portMappings,
+ Size: size,
+ StartedAt: startedTime.Unix(),
+ State: conState.String(),
}
if opts.Pod && len(conConfig.Pod) > 0 {
podName, err := rt.GetName(conConfig.Pod)
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index f029f24cb..d4b1a0dfd 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -257,7 +257,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
uidsMapped = err == nil
}
if !uidsMapped {
- logrus.Warnf("using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding subids")
+ logrus.Warnf("using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids")
setgroups := fmt.Sprintf("/proc/%d/setgroups", pid)
err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666)
if err != nil {
diff --git a/pkg/seccomp/seccomp.go b/pkg/seccomp/seccomp.go
index eeba46a72..4502c608f 100644
--- a/pkg/seccomp/seccomp.go
+++ b/pkg/seccomp/seccomp.go
@@ -30,7 +30,7 @@ var supportedPolicies = map[string]Policy{
"image": PolicyImage,
}
-// LookupPolicy looksup the corresponding Policy for the specified
+// LookupPolicy looks up the corresponding Policy for the specified
// string. If none is found, an errors is returned including the list of
// supported policies.
//
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 72ab1b97b..305b9d21f 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -1,4 +1,5 @@
// +build linux
+// +build !mips,!mipsle,!mips64,!mips64le
// Signal handling for Linux only.
package signal
diff --git a/pkg/signal/signal_linux_mipsx.go b/pkg/signal/signal_linux_mipsx.go
new file mode 100644
index 000000000..67638e30a
--- /dev/null
+++ b/pkg/signal/signal_linux_mipsx.go
@@ -0,0 +1,106 @@
+// +build linux
+// +build mips mipsle mips64 mips64le
+
+// Special signal handling for mips architecture
+package signal
+
+// Copyright 2013-2018 Docker, Inc.
+
+// NOTE: this package has originally been copied from github.com/docker/docker.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 127
+)
+
+// signalMap is a map of Linux signals.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": unix.SIGABRT,
+ "ALRM": unix.SIGALRM,
+ "BUS": unix.SIGBUS,
+ "CHLD": unix.SIGCHLD,
+ "CLD": unix.SIGCLD,
+ "CONT": unix.SIGCONT,
+ "FPE": unix.SIGFPE,
+ "HUP": unix.SIGHUP,
+ "ILL": unix.SIGILL,
+ "INT": unix.SIGINT,
+ "IO": unix.SIGIO,
+ "IOT": unix.SIGIOT,
+ "KILL": unix.SIGKILL,
+ "PIPE": unix.SIGPIPE,
+ "POLL": unix.SIGPOLL,
+ "PROF": unix.SIGPROF,
+ "PWR": unix.SIGPWR,
+ "QUIT": unix.SIGQUIT,
+ "SEGV": unix.SIGSEGV,
+ "EMT": unix.SIGEMT,
+ "STOP": unix.SIGSTOP,
+ "SYS": unix.SIGSYS,
+ "TERM": unix.SIGTERM,
+ "TRAP": unix.SIGTRAP,
+ "TSTP": unix.SIGTSTP,
+ "TTIN": unix.SIGTTIN,
+ "TTOU": unix.SIGTTOU,
+ "URG": unix.SIGURG,
+ "USR1": unix.SIGUSR1,
+ "USR2": unix.SIGUSR2,
+ "VTALRM": unix.SIGVTALRM,
+ "WINCH": unix.SIGWINCH,
+ "XCPU": unix.SIGXCPU,
+ "XFSZ": unix.SIGXFSZ,
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ handledSigs := make([]os.Signal, 0, len(signalMap))
+ for _, s := range signalMap {
+ handledSigs = append(handledSigs, s)
+ }
+ signal.Notify(sigc, handledSigs...)
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ signal.Stop(sigc)
+ close(sigc)
+}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index c7e62d185..42fea0277 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -163,7 +163,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
return nil, err
}
- // labels from the image that dont exist already
+ // labels from the image that don't exist already
if len(labels) > 0 && s.Labels == nil {
s.Labels = make(map[string]string)
}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 5cc7891ac..e5b09dcd8 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -30,7 +30,7 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
p.Hostname = podName
}
if podYAML.Spec.HostNetwork {
- p.NetNS.Value = "host"
+ p.NetNS.NSMode = specgen.Host
}
if podYAML.Spec.HostAliases != nil {
hosts := make([]string, 0, len(podYAML.Spec.HostAliases))
@@ -47,30 +47,53 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
return p, nil
}
-func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]*KubeVolume, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) {
- s := specgen.NewSpecGenerator(iid, false)
+type CtrSpecGenOptions struct {
+ // Container as read from the pod yaml
+ Container v1.Container
+ // Image available to use (pulled or found local)
+ Image *image.Image
+ // Volumes for all containers
+ Volumes map[string]*KubeVolume
+ // PodID of the parent pod
+ PodID string
+ // PodName of the parent pod
+ PodName string
+ // PodInfraID as the infrastructure container id
+ PodInfraID string
+ // ConfigMaps the configuration maps for environment variables
+ ConfigMaps []v1.ConfigMap
+ // SeccompPaths for finding the seccomp profile path
+ SeccompPaths *KubeSeccompPaths
+ // RestartPolicy defines the restart policy of the container
+ RestartPolicy string
+ // NetNSIsHost tells the container to use the host netns
+ NetNSIsHost bool
+}
+
+func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) {
+ s := specgen.NewSpecGenerator(opts.Container.Image, false)
- // podName should be non-empty for Deployment objects to be able to create
+ // pod name should be non-empty for Deployment objects to be able to create
// multiple pods having containers with unique names
- if len(podName) < 1 {
- return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName")
+ if len(opts.PodName) < 1 {
+ return nil, errors.Errorf("got empty pod name on container creation when playing kube")
}
- s.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name)
+ s.Name = fmt.Sprintf("%s-%s", opts.PodName, opts.Container.Name)
- s.Terminal = containerYAML.TTY
+ s.Terminal = opts.Container.TTY
- s.Pod = podID
+ s.Pod = opts.PodID
- setupSecurityContext(s, containerYAML)
+ setupSecurityContext(s, opts.Container)
// Since we prefix the container name with pod name to work-around the uniqueness requirement,
// the seccomp profile should reference the actual container name from the YAML
// but apply to the containers with the prefixed name
- s.SeccompProfilePath = seccompPaths.FindForContainer(containerYAML.Name)
+ s.SeccompProfilePath = opts.SeccompPaths.FindForContainer(opts.Container.Name)
s.ResourceLimits = &spec.LinuxResources{}
- milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu())
+ milliCPU, err := quantityToInt64(opts.Container.Resources.Limits.Cpu())
if err != nil {
return nil, errors.Wrap(err, "Failed to set CPU quota")
}
@@ -82,12 +105,12 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
}
- limit, err := quantityToInt64(containerYAML.Resources.Limits.Memory())
+ limit, err := quantityToInt64(opts.Container.Resources.Limits.Memory())
if err != nil {
return nil, errors.Wrap(err, "Failed to set memory limit")
}
- memoryRes, err := quantityToInt64(containerYAML.Resources.Requests.Memory())
+ memoryRes, err := quantityToInt64(opts.Container.Resources.Requests.Memory())
if err != nil {
return nil, errors.Wrap(err, "Failed to set memory reservation")
}
@@ -104,19 +127,26 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.ResourceLimits.Memory.Reservation = &memoryRes
}
- // TODO: We dont understand why specgen does not take of this, but
+ // TODO: We don't understand why specgen does not take of this, but
// integration tests clearly pointed out that it was required.
s.Command = []string{}
- imageData, err := newImage.Inspect(ctx)
+ imageData, err := opts.Image.Inspect(ctx)
if err != nil {
return nil, err
}
s.WorkDir = "/"
+ // We will use "Docker field name" internally here to avoid confusion
+ // and reference the "Kubernetes field name" when referencing the YAML
+ // ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
+ entrypoint := []string{}
+ cmd := []string{}
if imageData != nil && imageData.Config != nil {
if imageData.Config.WorkingDir != "" {
s.WorkDir = imageData.Config.WorkingDir
}
- s.Command = imageData.Config.Entrypoint
+ // Pull entrypoint and cmd from image
+ entrypoint = imageData.Config.Entrypoint
+ cmd = imageData.Config.Cmd
s.Labels = imageData.Config.Labels
if len(imageData.Config.StopSignal) > 0 {
stopSignal, err := util.ParseSignal(imageData.Config.StopSignal)
@@ -126,22 +156,27 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.StopSignal = &stopSignal
}
}
- if len(containerYAML.Command) != 0 {
- s.Command = containerYAML.Command
+ // If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd
+ if len(opts.Container.Command) != 0 {
+ entrypoint = opts.Container.Command
+ cmd = []string{}
}
- // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
- if len(containerYAML.Args) != 0 {
- s.Command = append(s.Command, containerYAML.Args...)
+ // Only override the cmd field if yaml.Args is specified
+ // Keep the image entrypoint, or the yaml.command if specified
+ if len(opts.Container.Args) != 0 {
+ cmd = opts.Container.Args
}
+
+ s.Command = append(entrypoint, cmd...)
// FIXME,
// we are currently ignoring imageData.Config.ExposedPorts
- if containerYAML.WorkingDir != "" {
- s.WorkDir = containerYAML.WorkingDir
+ if opts.Container.WorkingDir != "" {
+ s.WorkDir = opts.Container.WorkingDir
}
annotations := make(map[string]string)
- if infraID != "" {
- annotations[ann.SandboxID] = infraID
+ if opts.PodInfraID != "" {
+ annotations[ann.SandboxID] = opts.PodInfraID
annotations[ann.ContainerType] = ann.ContainerTypeContainer
}
s.Annotations = annotations
@@ -153,13 +188,13 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
envs[keyval[0]] = keyval[1]
}
- for _, env := range containerYAML.Env {
- value := envVarValue(env, configMaps)
+ for _, env := range opts.Container.Env {
+ value := envVarValue(env, opts.ConfigMaps)
envs[env.Name] = value
}
- for _, envFrom := range containerYAML.EnvFrom {
- cmEnvs := envVarsFromConfigMap(envFrom, configMaps)
+ for _, envFrom := range opts.Container.EnvFrom {
+ cmEnvs := envVarsFromConfigMap(envFrom, opts.ConfigMaps)
for k, v := range cmEnvs {
envs[k] = v
@@ -167,8 +202,8 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
s.Env = envs
- for _, volume := range containerYAML.VolumeMounts {
- volumeSource, exists := volumes[volume.Name]
+ for _, volume := range opts.Container.VolumeMounts {
+ volumeSource, exists := opts.Volumes[volume.Name]
if !exists {
return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
}
@@ -200,7 +235,11 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
}
- s.RestartPolicy = restartPolicy
+ s.RestartPolicy = opts.RestartPolicy
+
+ if opts.NetNSIsHost {
+ s.NetNS.NSMode = specgen.Host
+ }
return s, nil
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index c24dcf4c0..ba68de6fd 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -319,7 +319,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// BIND MOUNTS
- configSpec.Mounts = SupercedeUserMounts(mounts, configSpec.Mounts)
+ configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
// Process mounts to ensure correct options
if err := InitFSMounts(configSpec.Mounts); err != nil {
return nil, err
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index b69bd9091..9fceec7b3 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -115,7 +115,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
if err != nil {
return errors.Wrapf(err, "capabilities requested by user or image are not valid: %q", strings.Join(capsRequired, ","))
} else {
- // Verify all capRequiered are in the capList
+ // Verify all capRequired are in the capList
for _, cap := range capsRequired {
if !util.StringInSlice(cap, caplist) {
privCapsRequired = append(privCapsRequired, cap)
@@ -141,7 +141,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
} else {
- userCaps, err := capabilities.NormalizeCapabilities(s.CapAdd)
+ userCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
if err != nil {
return errors.Wrapf(err, "capabilities requested by user are not valid: %q", strings.Join(s.CapAdd, ","))
}
@@ -172,7 +172,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
// Clear default Seccomp profile from Generator for unconfined containers
// and privileged containers which do not specify a seccomp profile.
- if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
+ if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == "" || s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
configSpec.Linux.Seccomp = nil
}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 331a5c5bf..f523ac5bf 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -366,7 +366,7 @@ func addContainerInitBinary(s *specgen.SpecGenerator, path string) (spec.Mount,
// TODO: Should we unmount subtree mounts? E.g., if /tmp/ is mounted by
// one mount, and we already have /tmp/a and /tmp/b, should we remove
// the /tmp/a and /tmp/b mounts in favor of the more general /tmp?
-func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount {
+func SupersedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount {
if len(mounts) > 0 {
// If we have overlappings mounts, remove them from the spec in favor of
// the user-added volume mounts
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index a6c61a203..7c81f3f9f 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -48,7 +48,7 @@ func (p *PodSpecGenerator) Validate() error {
}
if p.NoInfra {
if p.NetNS.NSMode != Default && p.NetNS.NSMode != "" {
- return errors.New("NoInfra and network modes cannot be used toegther")
+ return errors.New("NoInfra and network modes cannot be used together")
}
if p.StaticIP != nil {
return exclusivePodOptions("NoInfra", "StaticIP")
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 964b89fa4..a6cc0a730 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -19,7 +19,7 @@ type LogConfig struct {
// Only available if LogDriver is set to "json-file" or "k8s-file".
// Optional.
Path string `json:"path,omitempty"`
- // Size is the maximimup size of the log file
+ // Size is the maximum size of the log file
// Optional.
Size int64 `json:"size,omitempty"`
// A set of options to accompany the log driver.
@@ -302,7 +302,7 @@ type ContainerSecurityConfig struct {
IDMappings *storage.IDMappingOptions `json:"idmappings,omitempty"`
// ReadOnlyFilesystem indicates that everything will be mounted
// as read-only
- ReadOnlyFilesystem bool `json:"read_only_filesystem,omittempty"`
+ ReadOnlyFilesystem bool `json:"read_only_filesystem,omitempty"`
// Umask is the umask the init process of the container will be run with.
Umask string `json:"umask,omitempty"`
// ProcOpts are the options used for the proc mount.
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index 52a214883..fb921cd72 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -11,6 +11,11 @@ import (
// is set to the unit's (unique) name.
const EnvVariable = "PODMAN_SYSTEMD_UNIT"
+// minTimeoutStopSec is the minimal stop timeout for generated systemd units.
+// Once exceeded, processes of the services are killed and the cgroup(s) are
+// cleaned up.
+const minTimeoutStopSec = 60
+
// RestartPolicies includes all valid restart policies to be used in a unit
// file.
var RestartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index 8090bcd3d..cfa02dc9d 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -55,6 +55,8 @@ type containerInfo struct {
ExecStartPre string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -74,6 +76,7 @@ After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $v
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre}}
ExecStartPre={{.ExecStartPre}}
{{- end}}
@@ -81,7 +84,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -191,7 +193,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand)
}
// We're hard-coding the first five arguments and append the
- // CreateCommand with a stripped command and subcomand.
+ // CreateCommand with a stripped command and subcommand.
startCommand := []string{
info.Executable,
"run",
@@ -241,7 +243,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}
if hasNameParam && !hasReplaceParam {
// Enforce --replace for named containers. This will
- // make systemd units more robuts as it allows them to
+ // make systemd units more robust as it allows them to
// start after system crashes (see
// github.com/containers/podman/issues/5485).
startCommand = append(startCommand, "--replace")
@@ -255,6 +257,8 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.ExecStopPost = "{{.Executable}} rm --ignore -f --cidfile {{.ContainerIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index d27062ef3..b9fb8fee6 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyContainer(t *testing.T) {
@@ -48,11 +49,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=82
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStopPost=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStop=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStopPost=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -71,11 +72,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -96,11 +97,11 @@ After=a.service b.service c.service pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -119,12 +120,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -143,12 +144,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -167,12 +168,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --pod-id-file /tmp/pod-foobar.pod-id-file --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -191,12 +192,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -215,12 +216,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id --cgroups=no-conmon -d awesome-image:latest
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
PIDFile=%t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
-KillMode=none
Type=forking
[Install]
@@ -242,7 +243,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ StopTimeout: 22,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
},
@@ -302,7 +303,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
EnvVariable: EnvVariable,
@@ -318,7 +319,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -334,7 +335,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -353,7 +354,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -390,9 +391,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreateContainerSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 234a60380..fc582e42a 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -60,6 +60,8 @@ type podInfo struct {
ExecStartPre2 string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -72,6 +74,7 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre1}}
ExecStartPre={{.ExecStartPre1}}
{{- end}}
@@ -82,7 +85,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -266,7 +268,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
}
// We're hard-coding the first five arguments and append the
- // CreateCommand with a stripped command and subcomand.
+ // CreateCommand with a stripped command and subcommand.
startCommand := []string{info.Executable}
startCommand = append(startCommand, podRootArgs...)
startCommand = append(startCommand,
@@ -298,6 +300,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.ExecStop = "{{.Executable}} pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
info.ExecStopPost = "{{.Executable}} pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index 7f1f63b7e..6d925ecd2 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyPod(t *testing.T) {
@@ -50,11 +51,11 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=102
ExecStart=/usr/bin/podman start jadda-jadda-infra
-ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
-ExecStopPost=/usr/bin/podman stop -t 10 jadda-jadda-infra
+ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
+ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -75,13 +76,13 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
PIDFile=%t/pod-123abc.pid
-KillMode=none
Type=forking
[Install]
@@ -102,7 +103,7 @@ WantedBy=multi-user.target default.target
InfraNameOrID: "jadda-jadda-infra",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ StopTimeout: 42,
PodmanVersion: "CI",
RequiredServices: []string{"container-1", "container-2"},
},
@@ -139,9 +140,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreatePodSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreatePodSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}
diff --git a/pkg/terminal/util.go b/pkg/terminal/util.go
index 169bec2af..231b47974 100644
--- a/pkg/terminal/util.go
+++ b/pkg/terminal/util.go
@@ -61,7 +61,7 @@ func ReadPassword(prompt string) (pw []byte, err error) {
}
}
-func PublicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
+func PublicKey(path string, passphrase []byte) (ssh.Signer, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
@@ -75,12 +75,9 @@ func PublicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
if len(passphrase) == 0 {
passphrase = ReadPassphrase()
}
- signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
- if err != nil {
- return nil, err
- }
+ return ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
}
- return ssh.PublicKeys(signer), nil
+ return signer, nil
}
func ReadPassphrase() []byte {
diff --git a/pkg/util/utils_linux.go b/pkg/util/utils_linux.go
index e4957f442..288137ca5 100644
--- a/pkg/util/utils_linux.go
+++ b/pkg/util/utils_linux.go
@@ -6,7 +6,6 @@ import (
"path/filepath"
"syscall"
- "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/psgo"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -53,19 +52,3 @@ func FindDeviceNodes() (map[string]string, error) {
return nodes, nil
}
-
-// CheckRootlessUIDRange checks the uid within the rootless container is in the range from /etc/subuid
-func CheckRootlessUIDRange(uid int) error {
- uids, _, err := rootless.GetConfiguredMappings()
- if err != nil {
- return err
- }
- total := 0
- for _, u := range uids {
- total += u.Size
- }
- if uid > total {
- return errors.Errorf("requested user's UID %d is too large for the rootless user namespace", uid)
- }
- return nil
-}
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index a63c76415..21022eb7c 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -114,7 +114,7 @@ func GetRootlessPauseProcessPidPath() (string, error) {
// files.
func GetRootlessPauseProcessPidPathGivenDir(libpodTmpDir string) (string, error) {
if libpodTmpDir == "" {
- return "", errors.Errorf("must provide non-empty tmporary directory")
+ return "", errors.Errorf("must provide non-empty temporary directory")
}
return filepath.Join(libpodTmpDir, "pause.pid"), nil
}
diff --git a/pkg/util/utils_unsupported.go b/pkg/util/utils_unsupported.go
index f8d5a37c1..62805d7c8 100644
--- a/pkg/util/utils_unsupported.go
+++ b/pkg/util/utils_unsupported.go
@@ -10,8 +10,3 @@ import (
func FindDeviceNodes() (map[string]string, error) {
return nil, errors.Errorf("not supported on non-Linux OSes")
}
-
-// CheckRootlessUIDRange is not implemented anywhere except Linux.
-func CheckRootlessUIDRange(uid int) error {
- return nil
-}
diff --git a/rootless.md b/rootless.md
index 22b03e340..9edd5a437 100644
--- a/rootless.md
+++ b/rootless.md
@@ -18,7 +18,7 @@ can easily fail
* Some system unit configuration options do not work in the rootless container
* systemd fails to apply several options and failures are silently ignored (e.g. CPUShares, MemoryLimit). Should work on cgroup V2.
* Use of certain options will cause service startup failures (e.g. PrivateNetwork). The systemd services requiring `PrivateNetwork` can be made to work by passing `--cap-add SYS_ADMIN`, but the security implications should be carefully evaluated. In most cases, it's better to create an override.conf drop-in that sets `PrivateNetwork=no`. This also applies to containers run by root.
-* Can not share container images with CRI-O or other rootfull users
+* Can not share container images with CRI-O or other rootful users
* Difficult to use additional stores for sharing content
* Does not work on NFS or parallel filesystem homedirs (e.g. [GPFS](https://www.ibm.com/support/knowledgecenter/en/SSFKCN/gpfs_welcome.html))
* NFS and parallel filesystems enforce file creation on different UIDs on the server side and does not understand User Namespace.
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index c105a9278..7b500bf57 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -12,6 +12,8 @@ iid=$(jq -r '.[0].Id' <<<"$output")
t GET libpod/images/$iid/exists 204
t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/exists 204
+t GET libpod/images/${iid}abcdef/exists 404 \
+ .cause="failed to find image ${iid}abcdef"
# FIXME: compare to actual podman info
t GET libpod/images/json 200 \
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 5c35edf2b..decdc4754 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -5,8 +5,10 @@
# WORKDIR=/data
ENV_WORKDIR_IMG=quay.io/libpod/testimage:20200929
+MultiTagName=localhost/test/testformultitag:tag
podman pull $IMAGE &>/dev/null
+podman tag $IMAGE $MultiTagName
podman pull $ENV_WORKDIR_IMG &>/dev/null
# Unimplemented
#t POST libpod/containers/create '' 201 'sdf'
@@ -201,6 +203,15 @@ t GET 'containers/json?limit=0&all=1' 200 \
.[0].Id~[0-9a-f]\\{64\\} \
.[1].Id~[0-9a-f]\\{64\\}
+t GET containers/json?limit=2 200 length=2
+
+# Filter with two ids should return both container
+t GET "containers/json?filters=%7B%22id%22%3A%5B%22${cid}%22%2C%22${cid_top}%22%5D%7D&all=1" 200 length=2
+# Filter with two ids and status running should return only 1 container
+t GET "containers/json?filters=%7B%22id%22%3A%5B%22${cid}%22%2C%22${cid_top}%22%5D%2C%22status%22%3A%5B%22running%22%5D%7D&all=1" 200 \
+ length=1 \
+ .[0].Id=${cid_top}
+
t POST containers/${cid_top}/stop "" 204
t DELETE containers/$cid 204
@@ -216,4 +227,13 @@ t GET containers/$cid/json 200 \
t DELETE containers/$cid 204
+# when the image had multi tags, the container's Image should be correct
+# Fixes https://github.com/containers/podman/issues/8547
+t POST containers/create Image=${MultiTagName} 201 \
+ .Id~[0-9a-f]\\{64\\}
+cid=$(jq -r '.Id' <<<"$output")
+t GET containers/$cid/json 200 \
+ .Image=${MultiTagName}
+t DELETE containers/$cid 204
+t DELETE images/${MultiTagName}?force=true 200
# vim: filetype=sh
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index aa167a97a..33f4ea37f 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -20,6 +20,18 @@ t POST libpod/volumes/create \
.Labels.testlabel=testonly \
.Options.type=tmpfs \
.Options.o=nodev,noexec
+t POST libpod/volumes/create \
+ '"Name":"foo3","Label":{"testlabel":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo3 \
+ .Labels.testlabel="" \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
+t POST libpod/volumes/create \
+ '"Name":"foo4","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo4 \
+ .Labels.testlabel1=testonly \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
# Negative test
# We have created a volume named "foo1"
@@ -37,15 +49,21 @@ t GET libpod/volumes/json 200 \
t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22foo1%22%5D%7D 200 length=1 .[0].Name=foo1
# -G --data-urlencode 'filters={"name":["foo1","foo2"]}'
t GET libpod/volumes/json?filters=%7B%22name%22%3A%20%5B%22foo1%22%2C%20%22foo2%22%5D%7D 200 length=2 .[0].Name=foo1 .[1].Name=foo2
-# -G --data-urlencode 'filters={"name":["notexist"]}'
-t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22notexists%22%5D%7D 200 length=0
+# -G --data-urlencode 'filters={"name":["nonexistent"]}'
+t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22nonexistent%22%5D%7D 200 length=0
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D 200 length=2
+# -G --data-urlencode 'filters={"label":["testlabel=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel=testonly%22%5D%7D 200 length=1
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D 200 length=1
## inspect volume
t GET libpod/volumes/foo1/json 200 \
.Name=foo1 \
.Mountpoint=$volumepath/foo1/_data \
.CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.*
-t GET libpod/volumes/notexist/json 404 \
+t GET libpod/volumes/nonexistent/json 404 \
.cause="no such volume" \
.message~.* \
.response=404
@@ -60,6 +78,18 @@ t DELETE libpod/volumes/foo1 404 \
.message~.* \
.response=404
+## Prune volumes with label matching 'testlabel1=testonly'
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t POST libpod/volumes/prune?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D "" 200
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D 200 length=0
+
+## Prune volumes with label matching 'testlabel'
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t POST libpod/volumes/prune?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D "" 200
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D 200 length=0
+
## Prune volumes
t POST libpod/volumes/prune "" 200
#After prune volumes, there should be no volume existing
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index 0ce56ee3c..5327bd076 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -50,7 +50,13 @@ t GET networks?filters=%7B%22dangling%22%3A%5B%221%22%5D%7D 500 \
# network inspect docker
t GET networks/a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 200 \
.Name=network1 \
-.Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1
+.Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 \
+.Scope=local
+
+# network create docker
+t POST networks/create '"Name":"net3","IPAM":{"Config":[]}' 201
+# network delete docker
+t DELETE networks/net3 204
# clean the network
t DELETE libpod/networks/network1 200 \
diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at
new file mode 100644
index 000000000..44cd05a13
--- /dev/null
+++ b/test/apiv2/45-system.at
@@ -0,0 +1,67 @@
+# -*- sh -*-
+#
+# system related tests
+#
+
+## ensure system is clean
+t POST 'libpod/system/prune?volumes=true&all=true' params='' 200
+
+## podman system df
+t GET system/df 200 '{"LayersSize":0,"Images":[],"Containers":[],"Volumes":[],"BuildCache":[],"BuilderSize":0}'
+t GET libpod/system/df 200 '{"Images":[],"Containers":[],"Volumes":[]}'
+
+# Create volume. We expect df to report this volume next invocation of system/df
+t GET libpod/info 200
+volumepath=$(jq -r ".store.volumePath" <<<"$output")
+t POST libpod/volumes/create name=foo1 201 \
+ .Name=foo1 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo1/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels={} \
+ .Options=null
+
+t GET system/df 200 '.Volumes[0].Name=foo1'
+
+t GET libpod/system/df 200 '.Volumes[0].VolumeName=foo1'
+
+# Create two more volumes to test pruneing
+t POST libpod/volumes/create \
+ '"Name":"foo2","Label":{"testlabel1":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo2 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo2/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1="" \
+ .Options.o=nodev,noexec
+
+t POST libpod/volumes/create \
+ '"Name":"foo3","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo3 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo3/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1=testonly \
+ .Options.o=nodev,noexec
+
+t GET system/df 200 '.Volumes | length=3'
+t GET libpod/system/df 200 '.Volumes | length=3'
+
+# Prune volumes
+
+# -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=idontmatch"]}'
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=idontmatch%22%5D%7D' params='' 200
+
+# nothing should have been pruned
+t GET system/df 200 '.Volumes | length=3'
+t GET libpod/system/df 200 '.Volumes | length=3'
+
+# -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=testonly"]}'
+# only foo3 should be pruned because of filter
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo3
+# only foo2 should be pruned because of filter
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo2
+# foo1, the last remaining volume should be pruned without any filters applied
+t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReports[0].Id=foo1
+
+# TODO add other system prune tests for pods / images
diff --git a/test/compose/README.md b/test/compose/README.md
new file mode 100644
index 000000000..863decf2c
--- /dev/null
+++ b/test/compose/README.md
@@ -0,0 +1,47 @@
+Tests for docker-compose
+========================
+
+This directory contains tests for docker-compose under podman.
+
+Each subdirectory must contain one docker-compose.yml file along with
+all necessary infrastructure for it (e.g. Containerfile, any files
+to be copied into the container, and so on.
+
+The `test-compose` script will, for each test subdirectory:
+
+* set up a fresh podman root under an empty working directory;
+* run a podman server rooted therein;
+* cd to the test subdirectory, and run `docker-compose up -d`;
+* source `tests.sh`;
+* run `docker-compose down`.
+
+As a special case, `setup.sh` and `teardown.sh` in the test directory
+will contain commands to be executed prior to `docker-compose up` and
+after `docker-compose down` respectively.
+
+tests.sh will probably contain commands of the form
+
+ test_port 12345 = 'hello there'
+
+Where 12345 is the port to curl to; '=' checks equality, '~' uses `expr`
+to check substrings; and 'hello there' is a string to look for in
+the curl results.
+
+Usage:
+
+ $ sudo test/compose/test-compose [pattern]
+
+By default, all subdirs will be run. If given a pattern, only those
+subdirectories matching 'pattern' will be run.
+
+If `$COMPOSE_WAIT` is set, `test-compose` will pause before running
+`docker-compose down`. This can be helpful for you to debug failing tests:
+
+ $ env COMPOSE_WAIT=1 sudo --preserve-env=COMPOSE_WAIT test/compose/test-compose
+
+Then, in another window,
+
+ # ls -lt /var/tmp/
+ # X=/var/tmp/test-compose.tmp.XXXXXX <--- most recent results of above
+ # podman --root $X/root --runroot $X/runroot ps -a
+ # podman --root $X/root --runroot $X/runroot logs -l
diff --git a/test/compose/env_and_volume/README.md b/test/compose/env_and_volume/README.md
new file mode 100644
index 000000000..e7d74976b
--- /dev/null
+++ b/test/compose/env_and_volume/README.md
@@ -0,0 +1,12 @@
+environment variable and volume
+===============
+
+This test creates two containers both of which are running flask. The first container has
+an environment variable called PODMAN_MSG. That container pipes the contents of PODMAN_MSG
+to a file on a shared volume between the containers. The second container then reads the
+file are returns the PODMAN_MSG value via flask (http).
+
+Validation
+------------
+* curl http://localhost:5000 and verify message
+* curl http://localhost:5001 and verify message
diff --git a/test/compose/env_and_volume/docker-compose.yml b/test/compose/env_and_volume/docker-compose.yml
new file mode 100644
index 000000000..df906e170
--- /dev/null
+++ b/test/compose/env_and_volume/docker-compose.yml
@@ -0,0 +1,18 @@
+version: '3'
+services:
+ writer:
+ environment:
+ - PODMAN_MSG=podman_rulez
+ build: write
+ ports:
+ - '5000:5000'
+ volumes:
+ - data:/data
+ reader:
+ build: read
+ ports:
+ - '5001:5000'
+ volumes:
+ - data:/data
+volumes:
+ data:
diff --git a/test/compose/env_and_volume/read/Dockerfile b/test/compose/env_and_volume/read/Dockerfile
new file mode 100644
index 000000000..8d5c45401
--- /dev/null
+++ b/test/compose/env_and_volume/read/Dockerfile
@@ -0,0 +1,5 @@
+FROM quay.io/libpod/podman_python
+WORKDIR /app
+COPY . /app
+ENTRYPOINT ["python3"]
+CMD ["app.py"]
diff --git a/test/compose/env_and_volume/read/app.py b/test/compose/env_and_volume/read/app.py
new file mode 100644
index 000000000..71fbbb26a
--- /dev/null
+++ b/test/compose/env_and_volume/read/app.py
@@ -0,0 +1,10 @@
+from flask import Flask
+app = Flask(__name__)
+
+@app.route('/')
+def hello():
+ f = open("/data/message", "r")
+ return f.read()
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0')
diff --git a/test/compose/env_and_volume/tests.sh b/test/compose/env_and_volume/tests.sh
new file mode 100644
index 000000000..a4c8bed30
--- /dev/null
+++ b/test/compose/env_and_volume/tests.sh
@@ -0,0 +1,4 @@
+# -*- bash -*-
+
+test_port 5000 = "done"
+test_port 5001 = "podman_rulez"
diff --git a/test/compose/env_and_volume/write/Dockerfile b/test/compose/env_and_volume/write/Dockerfile
new file mode 100644
index 000000000..8d5c45401
--- /dev/null
+++ b/test/compose/env_and_volume/write/Dockerfile
@@ -0,0 +1,5 @@
+FROM quay.io/libpod/podman_python
+WORKDIR /app
+COPY . /app
+ENTRYPOINT ["python3"]
+CMD ["app.py"]
diff --git a/test/compose/env_and_volume/write/app.py b/test/compose/env_and_volume/write/app.py
new file mode 100644
index 000000000..b6ad6fe63
--- /dev/null
+++ b/test/compose/env_and_volume/write/app.py
@@ -0,0 +1,13 @@
+from flask import Flask
+import os
+app = Flask(__name__)
+
+@app.route('/')
+def hello():
+ f = open("/data/message", "w")
+ f.write(os.getenv("PODMAN_MSG"))
+ f.close()
+ return "done"
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0')
diff --git a/test/compose/images/README.md b/test/compose/images/README.md
new file mode 100644
index 000000000..f25fbdc24
--- /dev/null
+++ b/test/compose/images/README.md
@@ -0,0 +1,5 @@
+images
+======
+
+Use these directories for images that are needed for the compose testing. These
+images should be then pushed to `quay.io/libpod` for consumption.
diff --git a/test/compose/images/podman-python/Containerfile b/test/compose/images/podman-python/Containerfile
new file mode 100644
index 000000000..47f90afaa
--- /dev/null
+++ b/test/compose/images/podman-python/Containerfile
@@ -0,0 +1,3 @@
+FROM alpine
+WORKDIR /app
+RUN apk update && apk add py3-pip && pip3 install flask && rm -fr /var/cache/apk/*
diff --git a/test/compose/mount_and_label/README.md b/test/compose/mount_and_label/README.md
new file mode 100644
index 000000000..623b38cac
--- /dev/null
+++ b/test/compose/mount_and_label/README.md
@@ -0,0 +1,9 @@
+mount and label
+===============
+
+This test creates a container with a mount (not volume) and also adds a label to the container.
+
+Validation
+------------
+* curl http://localhost:5000 and verify message
+* inspect the container to make the label exists on it
diff --git a/test/compose/mount_and_label/docker-compose.yml b/test/compose/mount_and_label/docker-compose.yml
new file mode 100644
index 000000000..112d7e134
--- /dev/null
+++ b/test/compose/mount_and_label/docker-compose.yml
@@ -0,0 +1,10 @@
+version: '3'
+services:
+ web:
+ build: frontend
+ ports:
+ - '5000:5000'
+ volumes:
+ - /tmp/data:/data:ro
+ labels:
+ - "io.podman=the_best"
diff --git a/test/compose/mount_and_label/frontend/Dockerfile b/test/compose/mount_and_label/frontend/Dockerfile
new file mode 100644
index 000000000..8d5c45401
--- /dev/null
+++ b/test/compose/mount_and_label/frontend/Dockerfile
@@ -0,0 +1,5 @@
+FROM quay.io/libpod/podman_python
+WORKDIR /app
+COPY . /app
+ENTRYPOINT ["python3"]
+CMD ["app.py"]
diff --git a/test/compose/mount_and_label/frontend/app.py b/test/compose/mount_and_label/frontend/app.py
new file mode 100644
index 000000000..bd2794d94
--- /dev/null
+++ b/test/compose/mount_and_label/frontend/app.py
@@ -0,0 +1,10 @@
+from flask import Flask
+app = Flask(__name__)
+
+@app.route('/')
+def hello():
+ f = open("/data/message")
+ return f.read()
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0')
diff --git a/test/compose/mount_and_label/setup.sh b/test/compose/mount_and_label/setup.sh
new file mode 100644
index 000000000..8633d65d5
--- /dev/null
+++ b/test/compose/mount_and_label/setup.sh
@@ -0,0 +1,2 @@
+mkdir -p /tmp/data
+echo "Podman rulez!" > /tmp/data/message
diff --git a/test/compose/mount_and_label/teardown.sh b/test/compose/mount_and_label/teardown.sh
new file mode 100644
index 000000000..57867c28a
--- /dev/null
+++ b/test/compose/mount_and_label/teardown.sh
@@ -0,0 +1 @@
+rm /tmp/data/message
diff --git a/test/compose/mount_and_label/tests.sh b/test/compose/mount_and_label/tests.sh
new file mode 100644
index 000000000..07ff089b5
--- /dev/null
+++ b/test/compose/mount_and_label/tests.sh
@@ -0,0 +1,4 @@
+# -*- bash -*-
+
+test_port 5000 = "Podman rulez!"
+podman container inspect -l --format '{{.Config.Labels}}' | grep "the_best"
diff --git a/test/compose/port_map_diff_port/README.md b/test/compose/port_map_diff_port/README.md
new file mode 100644
index 000000000..13ece72ad
--- /dev/null
+++ b/test/compose/port_map_diff_port/README.md
@@ -0,0 +1,9 @@
+port map on different port
+===============
+
+This test creates a container that runs flask on different ports for the container
+and the host
+
+Validation
+------------
+* curl http://localhost:5001 and verify message
diff --git a/test/compose/port_map_diff_port/docker-compose.yml b/test/compose/port_map_diff_port/docker-compose.yml
new file mode 100644
index 000000000..3003c52f4
--- /dev/null
+++ b/test/compose/port_map_diff_port/docker-compose.yml
@@ -0,0 +1,6 @@
+version: '3'
+services:
+ web:
+ build: frontend
+ ports:
+ - '5001:5000'
diff --git a/test/compose/port_map_diff_port/frontend/Dockerfile b/test/compose/port_map_diff_port/frontend/Dockerfile
new file mode 100644
index 000000000..8d5c45401
--- /dev/null
+++ b/test/compose/port_map_diff_port/frontend/Dockerfile
@@ -0,0 +1,5 @@
+FROM quay.io/libpod/podman_python
+WORKDIR /app
+COPY . /app
+ENTRYPOINT ["python3"]
+CMD ["app.py"]
diff --git a/test/compose/port_map_diff_port/frontend/app.py b/test/compose/port_map_diff_port/frontend/app.py
new file mode 100644
index 000000000..895556a89
--- /dev/null
+++ b/test/compose/port_map_diff_port/frontend/app.py
@@ -0,0 +1,9 @@
+from flask import Flask
+app = Flask(__name__)
+
+@app.route('/')
+def hello():
+ return "Podman rulez!"
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0')
diff --git a/test/compose/port_map_diff_port/tests.sh b/test/compose/port_map_diff_port/tests.sh
new file mode 100644
index 000000000..5a468aadc
--- /dev/null
+++ b/test/compose/port_map_diff_port/tests.sh
@@ -0,0 +1,3 @@
+# -*- bash -*-
+
+test_port 5001 = "Podman rulez!"
diff --git a/test/compose/setup.sh.example b/test/compose/setup.sh.example
new file mode 100644
index 000000000..9004b1e76
--- /dev/null
+++ b/test/compose/setup.sh.example
@@ -0,0 +1,3 @@
+# -*- bash -*-
+
+export ENV_PASSTHRU=$(random_string 20)
diff --git a/test/compose/simple_port_map/README.md b/test/compose/simple_port_map/README.md
new file mode 100644
index 000000000..f28d71c3e
--- /dev/null
+++ b/test/compose/simple_port_map/README.md
@@ -0,0 +1,9 @@
+simple port map to host
+===============
+
+This test creates a container that runs flask on and maps to the same
+host port
+
+Validation
+------------
+* curl http://localhost:5000 and verify message
diff --git a/test/compose/simple_port_map/docker-compose.yml b/test/compose/simple_port_map/docker-compose.yml
new file mode 100644
index 000000000..e7eab1047
--- /dev/null
+++ b/test/compose/simple_port_map/docker-compose.yml
@@ -0,0 +1,6 @@
+version: '3'
+services:
+ web:
+ build: frontend
+ ports:
+ - '5000:5000'
diff --git a/test/compose/simple_port_map/frontend/Dockerfile b/test/compose/simple_port_map/frontend/Dockerfile
new file mode 100644
index 000000000..2595828ff
--- /dev/null
+++ b/test/compose/simple_port_map/frontend/Dockerfile
@@ -0,0 +1,6 @@
+FROM alpine
+WORKDIR /app
+RUN apk update && apk add py3-pip && pip3 install flask
+COPY . /app
+ENTRYPOINT ["python3"]
+CMD ["app.py"]
diff --git a/test/compose/simple_port_map/frontend/app.py b/test/compose/simple_port_map/frontend/app.py
new file mode 100644
index 000000000..e4f84068c
--- /dev/null
+++ b/test/compose/simple_port_map/frontend/app.py
@@ -0,0 +1,10 @@
+from flask import Flask
+import os
+app = Flask(__name__)
+
+@app.route('/')
+def hello():
+ return "Podman rulez!"
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0')
diff --git a/test/compose/simple_port_map/tests.sh b/test/compose/simple_port_map/tests.sh
new file mode 100644
index 000000000..ccb2b6a3d
--- /dev/null
+++ b/test/compose/simple_port_map/tests.sh
@@ -0,0 +1,3 @@
+# -*- bash -*-
+
+test_port 5000 = "Podman rulez!"
diff --git a/test/compose/teardown.sh.example b/test/compose/teardown.sh.example
new file mode 100644
index 000000000..3f8153fa0
--- /dev/null
+++ b/test/compose/teardown.sh.example
@@ -0,0 +1,4 @@
+# -*- bash -*-
+
+# FIXME: this is completely unnecessary; it's just an example of a teardown
+unset ENV_PASSTHRU
diff --git a/test/compose/test-compose b/test/compose/test-compose
new file mode 100755
index 000000000..9558fbf58
--- /dev/null
+++ b/test/compose/test-compose
@@ -0,0 +1,345 @@
+#!/usr/bin/env bash
+#
+# Usage: test-compose [testname]
+#
+ME=$(basename $0)
+
+###############################################################################
+# BEGIN stuff you can but probably shouldn't customize
+
+# Directory where this script and all subtests live
+TEST_ROOTDIR=$(realpath $(dirname $0))
+
+# Podman executable
+PODMAN_BIN=$(realpath $TEST_ROOTDIR/../../bin)/podman
+
+# Local path to docker socket (we will add the unix:/ prefix when we need it)
+DOCKER_SOCK=/var/run/docker.sock
+
+# END stuff you can but probably shouldn't customize
+###############################################################################
+# BEGIN setup
+
+export TMPDIR=${TMPDIR:-/var/tmp}
+WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX)
+
+# Log of all HTTP requests and responses; always make '.log' point to latest
+LOGBASE=${TMPDIR}/$ME.log
+LOG=${LOGBASE}.$(date +'%Y%m%dT%H%M%S')
+ln -sf $LOG $LOGBASE
+
+# Keep track of test count and failures in files, not variables, because
+# variables don't carry back up from subshells.
+testcounter_file=$WORKDIR/.testcounter
+failures_file=$WORKDIR/.failures
+
+echo 0 >$testcounter_file
+echo 0 >$failures_file
+
+# END setup
+###############################################################################
+# BEGIN infrastructure code - the helper functions used in tests themselves
+
+#########
+# die # Exit error with a message to stderr
+#########
+function die() {
+ echo "$ME: $*" >&2
+ exit 1
+}
+
+########
+# is # Simple comparison
+########
+function is() {
+ local actual=$1
+ local expect=$2
+ local testname=$3
+
+ if [[ $actual = $expect ]]; then
+ # On success, include expected value; this helps readers understand
+ _show_ok 1 "$testname=$expect"
+ return
+ fi
+ _show_ok 0 "$testname" "$expect" "$actual"
+}
+
+##########
+# like # Compare, but allowing patterns
+##########
+function like() {
+ local actual=$1
+ local expect=$2
+ local testname=$3
+
+ # "is" (equality) is a subset of "like", but one that expr fails on if
+ # the expected result has shell-special characters like '['. Treat it
+ # as a special case.
+
+ if [[ "$actual" = "$expect" ]]; then
+ _show_ok 1 "$testname=$expect"
+ return
+ fi
+
+ if expr "$actual" : ".*$expect" &>/dev/null; then
+ # On success, include expected value; this helps readers understand
+ _show_ok 1 "$testname ('$actual') ~ $expect"
+ return
+ fi
+ _show_ok 0 "$testname" "~ $expect" "$actual"
+}
+
+##############
+# _show_ok # Helper for is() and like(): displays 'ok' or 'not ok'
+##############
+function _show_ok() {
+ local ok=$1
+ local testname=$2
+
+ # If output is a tty, colorize pass/fail
+ local red=
+ local green=
+ local reset=
+ local bold=
+ if [ -t 1 ]; then
+ red='\e[31m'
+ green='\e[32m'
+ reset='\e[0m'
+ bold='\e[1m'
+ fi
+
+ _bump $testcounter_file
+ count=$(<$testcounter_file)
+
+ # "skip" is a special case of "ok". Assume that our caller has included
+ # the magical '# skip - reason" comment string.
+ if [[ $ok == "skip" ]]; then
+ # colon-plus: replace green with yellow, but only if green is non-null
+ green="${green:+\e[33m}"
+ ok=1
+ fi
+ if [ $ok -eq 1 ]; then
+ echo -e "${green}ok $count $testname${reset}"
+ echo "ok $count $testname" >>$LOG
+ return
+ fi
+
+ # Failed
+ local expect=$3
+ local actual=$4
+ printf "${red}not ok $count $testname${reset}\n"
+ printf "${red}# expected: %s${reset}\n" "$expect"
+ printf "${red}# actual: ${bold}%s${reset}\n" "$actual"
+
+ echo "not ok $count $testname" >>$LOG
+ echo " expected: $expect" >>$LOG
+
+ _bump $failures_file
+}
+
+###########
+# _bump # Increment a counter in a file
+###########
+function _bump() {
+ local file=$1
+
+ count=$(<$file)
+ echo $(( $count + 1 )) >| $file
+}
+
+###############
+# test_port # Run curl against a port, check results against expectation
+###############
+function test_port() {
+ local port="$1" # e.g. 5000
+ local op="$2" # '=' or '~'
+ local expect="$3" # what to expect from curl output
+
+ local actual=$(curl --retry 5 --retry-connrefused -s http://127.0.0.1:$port/)
+ local curl_rc=$?
+ if [ $curl_rc -ne 0 ]; then
+ _show_ok 0 "$testname - curl failed with status $curl_rc"
+### docker-compose down >>$logfile 2>&1
+### exit 1
+ fi
+
+ case "$op" in
+ '=') is "$actual" "$expect" "$testname : port $port" ;;
+ '~') like "$actual" "$expect" "$testname : port $port" ;;
+ *) die "Invalid operator '$op'" ;;
+ esac
+}
+
+
+###################
+# start_service # Run the socket listener
+###################
+service_pid=
+function start_service() {
+ test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN"
+
+ # FIXME: use ${testname} subdir but we can't: 50-char limit in runroot
+ rm -rf $WORKDIR/{root,runroot,cni}
+ mkdir --mode 0755 $WORKDIR/{root,runroot,cni}
+ chcon --reference=/var/lib/containers $WORKDIR/root
+ cp /etc/cni/net.d/*podman*conflist $WORKDIR/cni/
+
+ $PODMAN_BIN \
+ --root $WORKDIR/root \
+ --runroot $WORKDIR/runroot \
+ --cgroup-manager=systemd \
+ --cni-config-dir $WORKDIR/cni \
+ system service \
+ --time 0 unix:/$DOCKER_SOCK \
+ &> $WORKDIR/server.log &
+ service_pid=$!
+
+ # Wait (FIXME: how do we test the socket?)
+ local _timeout=5
+ while [ $_timeout -gt 0 ]; do
+ # FIXME: should we actually try a read or write?
+ test -S $DOCKER_SOCK && return
+ sleep 1
+ _timeout=$(( $_timeout - 1 ))
+ done
+ cat $WORKDIR/server.log
+ die "Timed out waiting for service"
+}
+
+############
+# podman # Needed by some test scripts to invoke the actual podman binary
+############
+function podman() {
+ echo "\$ podman $*" >>$WORKDIR/output.log
+ $PODMAN_BIN \
+ --root $WORKDIR/root \
+ --runroot $WORKDIR/runroot \
+ "$@" >>$WORKDIR/output.log 2>&1
+}
+
+###################
+# random_string # Returns a pseudorandom human-readable string
+###################
+function random_string() {
+ # Numeric argument, if present, is desired length of string
+ local length=${1:-10}
+
+ head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
+}
+
+# END infrastructure code
+###############################################################################
+# BEGIN sanity checks
+
+for tool in curl docker-compose; do
+ type $tool &>/dev/null || die "$ME: Required tool '$tool' not found"
+done
+
+# END sanity checks
+###############################################################################
+# BEGIN entry handler (subtest invoker)
+
+# Identify the tests to run. If called with args, use those as globs.
+tests_to_run=()
+if [ -n "$*" ]; then
+ shopt -s nullglob
+ for i; do
+ match=(${TEST_ROOTDIR}/*${i}*/docker-compose.yml)
+ if [ ${#match} -eq 0 ]; then
+ die "No match for $TEST_ROOTDIR/*$i*.curl"
+ fi
+ tests_to_run+=("${match[@]}")
+ done
+ shopt -u nullglob
+else
+ tests_to_run=(${TEST_ROOTDIR}/*/docker-compose.yml)
+fi
+
+# Too hard to precompute the number of tests; just spit it out at the end.
+n_tests=0
+for t in ${tests_to_run[@]}; do
+ testdir="$(dirname $t)"
+ testname="$(basename $testdir)"
+
+ if [ -e $test_dir/SKIP ]; then
+ local reason="$(<$test_dir/SKIP)"
+ if [ -n "$reason" ]; then
+ reason=" - $reason"
+ fi
+ _show_ok skip "$testname # skip$reason"
+ continue
+ fi
+
+ start_service
+
+ logfile=$WORKDIR/$testname.log
+ (
+ cd $testdir || die "Cannot cd $testdir"
+
+ # setup file may be used for creating temporary directories/files.
+ # We source it so that envariables defined in it will get back to us.
+ if [ -e setup.sh ]; then
+ . setup.sh
+ fi
+ if [ -e teardown.sh ]; then
+ trap '. teardown.sh' 0
+ fi
+
+ docker-compose up -d &> $logfile
+ docker_compose_rc=$?
+ if [[ $docker_compose_rc -ne 0 ]]; then
+ _show_ok 0 "$testname - up" "[ok]" "status=$docker_compose_rc"
+ sed -e 's/^/# /' <$logfile
+ docker-compose down >>$logfile 2>&1 # No status check here
+ exit 1
+ fi
+ _show_ok 1 "$testname - up"
+
+ # Run tests. This is likely to be a series of 'test_port' checks
+ # but may also include podman commands to inspect labels, state
+ if [ -e tests.sh ]; then
+ . tests.sh
+ fi
+ # FIXME: if any tests fail, try 'podman logs' on container?
+
+ if [ -n "$COMPOSE_WAIT" ]; then
+ echo -n "Pausing due to \$COMPOSE_WAIT. Press ENTER to continue: "
+ read keepgoing
+ fi
+
+ # Done. Clean up.
+ docker-compose down &> $logfile
+ rc=$?
+ if [[ $rc -eq 0 ]]; then
+ _show_ok 1 "$testname - down"
+ else
+ _show_ok 0 "$testname - down" "[ok]" "rc=$rc"
+ # FIXME: show error
+ fi
+ )
+
+ kill $service_pid
+ wait $service_pid
+
+ # FIXME: otherwise we get EBUSY
+ umount $WORKDIR/root/overlay &>/dev/null
+
+ # FIXME: run 'podman ps'?
+# rm -rf $WORKDIR/${testname}
+done
+
+# END entry handler
+###############################################################################
+
+# Clean up
+
+test_count=$(<$testcounter_file)
+failure_count=$(<$failures_file)
+
+#if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then
+# rm -rf $WORKDIR
+#fi
+
+echo "1..${test_count}"
+
+exit $failure_count
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index d7bbdc633..a076ada6b 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -62,7 +62,7 @@ type PodmanTestIntegration struct {
var LockTmpDir string
-// PodmanSessionIntegration sturct for command line session
+// PodmanSessionIntegration struct for command line session
type PodmanSessionIntegration struct {
*PodmanSession
}
@@ -121,7 +121,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
}
}
- // Pull cirros but dont put it into the cache
+ // Pull cirros but don't put it into the cache
pullImages := []string{cirros, fedoraToolbox}
pullImages = append(pullImages, CACHE_IMAGES...)
for _, image := range pullImages {
diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go
index 28672cfc6..719ac9fac 100644
--- a/test/e2e/containers_conf_test.go
+++ b/test/e2e/containers_conf_test.go
@@ -82,6 +82,7 @@ var _ = Describe("Podman run", func() {
})
It("podman Capabilities in containers.conf", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
cap := podmanTest.Podman([]string{"run", ALPINE, "grep", "CapEff", "/proc/self/status"})
cap.WaitWithDefaultTimeout()
Expect(cap.ExitCode()).To(Equal(0))
@@ -121,6 +122,7 @@ var _ = Describe("Podman run", func() {
})
verifyNSHandling := func(nspath, option string) {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
os.Setenv("CONTAINERS_CONF", "config/containers-ns.conf")
if IsRemote() {
podmanTest.RestartRemoteService()
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index 33908b60e..f81323847 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -24,7 +24,6 @@ var _ = Describe("Podman cp", func() {
)
BeforeEach(func() {
- SkipIfRemote("FIXME: Podman-remote cp needs to work")
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -61,7 +60,7 @@ var _ = Describe("Podman cp", func() {
// Copy TO the container.
- // Cannot copy to a non-existent path (note the trailing "/").
+ // Cannot copy to a nonexistent path (note the trailing "/").
session = podmanTest.Podman([]string{"cp", srcFile.Name(), name + ":foo/"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index aaf089d97..a4931ff2d 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -233,7 +233,7 @@ var _ = Describe("Podman create", func() {
Expect(err).To(BeNil())
defer os.RemoveAll(tmpDir)
- podName := "rudoplh"
+ podName := "rudolph"
ctrName := "prancer"
podIDFile := tmpDir + "pod-id-file"
@@ -337,8 +337,8 @@ var _ = Describe("Podman create", func() {
Expect(string(session.Out.Contents())).To(ContainSubstring(ALPINEARM64DIGEST))
})
- It("podman create --authfile with nonexist authfile", func() {
- session := podmanTest.Podman([]string{"create", "--authfile", "/tmp/nonexist", "--name=foo", ALPINE})
+ It("podman create --authfile with nonexistent authfile", func() {
+ session := podmanTest.Podman([]string{"create", "--authfile", "/tmp/nonexistent", "--name=foo", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(Not(Equal(0)))
})
@@ -655,7 +655,7 @@ var _ = Describe("Podman create", func() {
session = podmanTest.Podman([]string{"create", "--platform=linux/arm64", "--override-os", "windows", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
- expectedError = "--platform option can not be specified with --overide-arch or --override-os"
+ expectedError = "--platform option can not be specified with --override-arch or --override-os"
Expect(session.ErrorToString()).To(ContainSubstring(expectedError))
session = podmanTest.Podman([]string{"create", "-q", "--platform=linux/arm64", ALPINE})
diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go
index b37bd584e..0c7a1bd66 100644
--- a/test/e2e/events_test.go
+++ b/test/e2e/events_test.go
@@ -5,9 +5,11 @@ import (
"fmt"
"os"
"strings"
+ "sync"
"time"
. "github.com/containers/podman/v2/test/utils"
+ "github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -115,10 +117,7 @@ var _ = Describe("Podman events", func() {
SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
- test := podmanTest.Podman([]string{"events", "--help"})
- test.WaitWithDefaultTimeout()
- fmt.Println(test.OutputToStringArray())
- result := podmanTest.Podman([]string{"events", "--stream=false", "--since", "1h"})
+ result := podmanTest.Podman([]string{"events", "--stream=false", "--until", "1h"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(BeZero())
})
@@ -154,4 +153,40 @@ var _ = Describe("Podman events", func() {
Expect(eventsMap).To(HaveKey("Status"))
})
+
+ It("podman events --until future", func() {
+ name1 := stringid.GenerateNonCryptoID()
+ name2 := stringid.GenerateNonCryptoID()
+ name3 := stringid.GenerateNonCryptoID()
+ session := podmanTest.Podman([]string{"create", "--name", name1, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer GinkgoRecover()
+ defer wg.Done()
+
+ // wait 2 seconds to be sure events is running
+ time.Sleep(time.Second * 2)
+ session = podmanTest.Podman([]string{"create", "--name", name2, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"create", "--name", name3, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ }()
+
+ // unix timestamp in 10 seconds
+ until := time.Now().Add(time.Second * 10).Unix()
+ result := podmanTest.Podman([]string{"events", "--since", "30s", "--until", fmt.Sprint(until)})
+ result.Wait(11)
+ Expect(result.ExitCode()).To(BeZero())
+ Expect(result.OutputToString()).To(ContainSubstring(name1))
+ Expect(result.OutputToString()).To(ContainSubstring(name2))
+ Expect(result.OutputToString()).To(ContainSubstring(name3))
+
+ wg.Wait()
+ })
})
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index f61f52589..18737105e 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -119,6 +119,21 @@ var _ = Describe("Podman exec", func() {
Expect(session.ExitCode()).To(Equal(100))
})
+ It("podman exec --privileged", func() {
+ hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
+ Expect(hostCap.ExitCode()).To(Equal(0))
+
+ setup := podmanTest.RunTopContainer("test-privileged")
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
+ })
+
It("podman exec terminal doesn't hang", func() {
setup := podmanTest.Podman([]string{"run", "-dti", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
setup.WaitWithDefaultTimeout()
diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go
index 7ff5d4207..480bfe5fc 100644
--- a/test/e2e/exists_test.go
+++ b/test/e2e/exists_test.go
@@ -38,7 +38,6 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session).Should(Exit(0))
})
It("podman image exists in local storage by short name", func() {
- Skip("FIXME-8165: shortnames don't seem to work with quay (#8176)")
session := podmanTest.Podman([]string{"image", "exists", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 0950a9321..239817e6c 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -471,6 +471,7 @@ var _ = Describe("Podman generate kube", func() {
})
It("podman generate kube multiple pods should fail", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", ALPINE, "top"})
pod1.WaitWithDefaultTimeout()
Expect(pod1.ExitCode()).To(Equal(0))
diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go
index 765844265..3f059300b 100644
--- a/test/e2e/generate_systemd_test.go
+++ b/test/e2e/generate_systemd_test.go
@@ -74,6 +74,9 @@ var _ = Describe("Podman generate systemd", func() {
found, _ := session.GrepString(" stop -t 1234 ")
Expect(found).To(BeTrue())
+
+ found, _ = session.GrepString("TimeoutStopSec=1294")
+ Expect(found).To(BeTrue())
})
It("podman generate systemd", func() {
diff --git a/test/e2e/image_sign_test.go b/test/e2e/image_sign_test.go
index c9041eaba..57739419c 100644
--- a/test/e2e/image_sign_test.go
+++ b/test/e2e/image_sign_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -58,4 +59,19 @@ var _ = Describe("Podman image sign", func() {
_, err = os.Stat(filepath.Join(sigDir, "library"))
Expect(err).To(BeNil())
})
+
+ It("podman sign --all multi-arch image", func() {
+ cmd := exec.Command("gpg", "--import", "sign/secret-key.asc")
+ err := cmd.Run()
+ Expect(err).To(BeNil())
+ sigDir := filepath.Join(podmanTest.TempDir, "test-sign-multi")
+ err = os.MkdirAll(sigDir, os.ModePerm)
+ Expect(err).To(BeNil())
+ session := podmanTest.Podman([]string{"image", "sign", "--all", "--directory", sigDir, "--sign-by", "foo@bar.com", "docker://library/alpine"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ fInfos, err := ioutil.ReadDir(filepath.Join(sigDir, "library"))
+ Expect(err).To(BeNil())
+ Expect(len(fInfos) > 1).To(BeTrue())
+ })
})
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index 281b2c313..2dab4858e 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -146,17 +146,17 @@ var _ = Describe("Podman images", func() {
Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(Equal(8))
- retapline := podmanTest.Podman([]string{"images", "-f", "reference=a*pine"})
- retapline.WaitWithDefaultTimeout()
- Expect(retapline).Should(Exit(0))
- Expect(len(retapline.OutputToStringArray())).To(Equal(6))
- Expect(retapline.LineInOutputContains("alpine")).To(BeTrue())
-
- retapline = podmanTest.Podman([]string{"images", "-f", "reference=alpine"})
- retapline.WaitWithDefaultTimeout()
- Expect(retapline).Should(Exit(0))
- Expect(len(retapline.OutputToStringArray())).To(Equal(6))
- Expect(retapline.LineInOutputContains("alpine")).To(BeTrue())
+ retalpine := podmanTest.Podman([]string{"images", "-f", "reference=a*pine"})
+ retalpine.WaitWithDefaultTimeout()
+ Expect(retalpine).Should(Exit(0))
+ Expect(len(retalpine.OutputToStringArray())).To(Equal(6))
+ Expect(retalpine.LineInOutputContains("alpine")).To(BeTrue())
+
+ retalpine = podmanTest.Podman([]string{"images", "-f", "reference=alpine"})
+ retalpine.WaitWithDefaultTimeout()
+ Expect(retalpine).Should(Exit(0))
+ Expect(len(retalpine.OutputToStringArray())).To(Equal(6))
+ Expect(retalpine.LineInOutputContains("alpine")).To(BeTrue())
retnone := podmanTest.Podman([]string{"images", "-q", "-f", "reference=bogus"})
retnone.WaitWithDefaultTimeout()
diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go
index 8a4828583..8b31cae72 100644
--- a/test/e2e/kill_test.go
+++ b/test/e2e/kill_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "io/ioutil"
"os"
. "github.com/containers/podman/v2/test/utils"
@@ -112,4 +113,58 @@ var _ = Describe("Podman kill", func() {
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
+
+ It("podman kill --cidfile", func() {
+ tmpDir, err := ioutil.TempDir("", "")
+ Expect(err).To(BeNil())
+ tmpFile := tmpDir + "cid"
+ defer os.RemoveAll(tmpDir)
+
+ session := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile, ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToStringArray()[0]
+
+ kill := podmanTest.Podman([]string{"kill", "--cidfile", tmpFile})
+ kill.WaitWithDefaultTimeout()
+ Expect(kill.ExitCode()).To(BeZero())
+
+ wait := podmanTest.Podman([]string{"wait", "--condition", "exited", cid})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait.ExitCode()).To(BeZero())
+ })
+
+ It("podman kill multiple --cidfile", func() {
+ tmpDir1, err := ioutil.TempDir("", "")
+ Expect(err).To(BeNil())
+ tmpFile1 := tmpDir1 + "cid"
+ defer os.RemoveAll(tmpDir1)
+
+ tmpDir2, err := ioutil.TempDir("", "")
+ Expect(err).To(BeNil())
+ tmpFile2 := tmpDir2 + "cid"
+ defer os.RemoveAll(tmpDir2)
+
+ session := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile1, ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid1 := session.OutputToStringArray()[0]
+
+ session2 := podmanTest.Podman([]string{"run", "-dt", "--cidfile", tmpFile2, ALPINE, "top"})
+ session2.WaitWithDefaultTimeout()
+ Expect(session2.ExitCode()).To(Equal(0))
+ cid2 := session2.OutputToStringArray()[0]
+
+ kill := podmanTest.Podman([]string{"kill", "--cidfile", tmpFile1, "--cidfile", tmpFile2})
+ kill.WaitWithDefaultTimeout()
+ Expect(kill.ExitCode()).To(BeZero())
+
+ wait := podmanTest.Podman([]string{"wait", "--condition", "exited", cid1})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait.ExitCode()).To(BeZero())
+ wait = podmanTest.Podman([]string{"wait", "--condition", "exited", cid2})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait.ExitCode()).To(BeZero())
+ })
+
})
diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go
index 5de77f158..a2e88ecd2 100644
--- a/test/e2e/login_logout_test.go
+++ b/test/e2e/login_logout_test.go
@@ -66,7 +66,7 @@ var _ = Describe("Podman login and logout", func() {
registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server))
- testImg = strings.Join([]string{server, "test-apline"}, "/")
+ testImg = strings.Join([]string{server, "test-alpine"}, "/")
certDirPath = filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", server)
os.MkdirAll(certDirPath, os.ModePerm)
@@ -155,8 +155,8 @@ var _ = Describe("Podman login and logout", func() {
json.Unmarshal(authInfo, &info)
fmt.Println(info)
- // push should fail with nonexist authfile
- session = podmanTest.Podman([]string{"push", "--authfile", "/tmp/nonexist", ALPINE, testImg})
+ // push should fail with nonexistent authfile
+ session = podmanTest.Podman([]string{"push", "--authfile", "/tmp/nonexistent", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
@@ -168,8 +168,8 @@ var _ = Describe("Podman login and logout", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- // logout should fail with nonexist authfile
- session = podmanTest.Podman([]string{"logout", "--authfile", "/tmp/nonexist", server})
+ // logout should fail with nonexistent authfile
+ session = podmanTest.Podman([]string{"logout", "--authfile", "/tmp/nonexistent", server})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index a749a86ff..b370aeec1 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -332,6 +332,11 @@ var _ = Describe("Podman logs", func() {
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
+ inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).To(Exit(0))
+ Expect(inspect.OutputToString()).To(Equal("10kB"))
+
results := podmanTest.Podman([]string{"logs", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
@@ -355,4 +360,21 @@ var _ = Describe("Podman logs", func() {
Expect(outlines[0]).To(Equal("1\r"))
Expect(outlines[1]).To(Equal("2\r"))
})
+
+ It("podman logs test stdout and stderr", func() {
+ cname := "log-test"
+ logc := podmanTest.Podman([]string{"run", "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"})
+ logc.WaitWithDefaultTimeout()
+ Expect(logc).To(Exit(0))
+
+ wait := podmanTest.Podman([]string{"wait", cname})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait).To(Exit(0))
+
+ results := podmanTest.Podman([]string{"logs", cname})
+ results.WaitWithDefaultTimeout()
+ Expect(results).To(Exit(0))
+ Expect(results.OutputToString()).To(Equal("stdout"))
+ Expect(results.ErrorToString()).To(Equal("stderr"))
+ })
})
diff --git a/test/e2e/mount_rootless_test.go b/test/e2e/mount_rootless_test.go
index 1e4152709..c410a2507 100644
--- a/test/e2e/mount_rootless_test.go
+++ b/test/e2e/mount_rootless_test.go
@@ -16,7 +16,7 @@ var _ = Describe("Podman mount", func() {
)
BeforeEach(func() {
- SkipIfNotRootless("This function is not enabled for rootfull podman")
+ SkipIfNotRootless("This function is not enabled for rootful podman")
SkipIfRemote("Podman mount not supported for remote connections")
tempdir, err = CreateTempDirInTempDir()
if err != nil {
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index 7cdad9bf2..dd94bd7ca 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -33,7 +33,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("bad network name in disconnect should result in error", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
dis := podmanTest.Podman([]string{"network", "disconnect", "foobar", "test"})
dis.WaitWithDefaultTimeout()
Expect(dis.ExitCode()).ToNot(BeZero())
@@ -41,7 +41,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("bad container name in network disconnect should result in error", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -55,7 +55,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("podman network disconnect", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -80,7 +80,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("bad network name in connect should result in error", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
dis := podmanTest.Podman([]string{"network", "connect", "foobar", "test"})
dis.WaitWithDefaultTimeout()
Expect(dis.ExitCode()).ToNot(BeZero())
@@ -88,7 +88,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("bad container name in network connect should result in error", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -102,7 +102,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("podman connect on a container that already is connected to the network should error", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -120,7 +120,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
It("podman network connect", func() {
SkipIfRemote("This requires a pending PR to be merged before it will work")
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -152,7 +152,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("podman network connect when not running", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -181,7 +181,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
})
It("podman network disconnect when not running", func() {
- SkipIfRootless("network connect and disconnect are only rootfull")
+ SkipIfRootless("network connect and disconnect are only rootful")
netName1 := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName1})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go
index 21b3074fc..7e9a18ab2 100644
--- a/test/e2e/network_create_test.go
+++ b/test/e2e/network_create_test.go
@@ -106,6 +106,7 @@ var _ = Describe("Podman network create", func() {
Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("0.0.0.0/0"))
Expect(bridgePlugin.IsGW).To(BeTrue())
Expect(bridgePlugin.IPMasq).To(BeTrue())
+ Expect(bridgePlugin.IPAM.Ranges[0][0].Gateway).ToNot(BeEmpty())
Expect(portMapPlugin.Capabilities["portMappings"]).To(BeTrue())
})
@@ -153,6 +154,8 @@ var _ = Describe("Podman network create", func() {
// JSON the bridge info
bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge")
Expect(err).To(BeNil())
+ // check that gateway is added to config
+ Expect(bridgePlugin.IPAM.Ranges[0][0].Gateway).To(Equal("10.11.12.1"))
// Once a container executes a new network, the nic will be created. We should clean those up
// best we can
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 5ecfdd6b5..f009e333e 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -16,7 +16,7 @@ import (
)
var unknownKindYaml = `
-apiVerson: v1
+apiVersion: v1
kind: UnknownKind
metadata:
labels:
@@ -62,6 +62,7 @@ metadata:
spec:
restartPolicy: {{ .RestartPolicy }}
hostname: {{ .Hostname }}
+ hostNetwork: {{ .HostNetwork }}
hostAliases:
{{ range .HostAliases }}
- hostnames:
@@ -220,6 +221,7 @@ spec:
spec:
restartPolicy: {{ .RestartPolicy }}
hostname: {{ .Hostname }}
+ hostNetwork: {{ .HostNetwork }}
containers:
{{ with .Ctrs }}
{{ range . }}
@@ -376,6 +378,7 @@ type Pod struct {
Name string
RestartPolicy string
Hostname string
+ HostNetwork bool
HostAliases []HostAlias
Ctrs []*Ctr
Volumes []*Volume
@@ -396,6 +399,7 @@ func getPod(options ...podOption) *Pod {
Name: defaultPodName,
RestartPolicy: "Never",
Hostname: "",
+ HostNetwork: false,
HostAliases: nil,
Ctrs: make([]*Ctr, 0),
Volumes: make([]*Volume, 0),
@@ -464,6 +468,12 @@ func withVolume(v *Volume) podOption {
}
}
+func withHostNetwork() podOption {
+ return func(pod *Pod) {
+ pod.HostNetwork = true
+ }
+}
+
// Deployment describes the options a kube yaml can be configured at deployment level
type Deployment struct {
Name string
@@ -793,11 +803,11 @@ var _ = Describe("Podman play kube", func() {
})
- It("podman play kube fail with nonexist authfile", func() {
+ It("podman play kube fail with nonexistent authfile", func() {
err := generateKubeYaml("pod", getPod(), kubeYaml)
Expect(err).To(BeNil())
- kube := podmanTest.Podman([]string{"play", "kube", "--authfile", "/tmp/nonexist", kubeYaml})
+ kube := podmanTest.Podman([]string{"play", "kube", "--authfile", "/tmp/nonexistent", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube.ExitCode()).To(Not(Equal(0)))
@@ -820,8 +830,28 @@ var _ = Describe("Podman play kube", func() {
Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd))
})
+ // If you do not supply command or args for a Container, the defaults defined in the Docker image are used.
+ It("podman play kube test correct args and cmd when not specified", func() {
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil))))
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+
+ // this image's ENTRYPOINT is `/entrypoint.sh` and it's COMMAND is `/etc/docker/registry/config.yml`
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[/entrypoint.sh /etc/docker/registry/config.yml]`))
+ })
+
+ // If you supply a command but no args for a Container, only the supplied command is used.
+ // The default EntryPoint and the default Cmd defined in the Docker image are ignored.
It("podman play kube test correct command with only set command in yaml file", func() {
- pod := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg(nil))))
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo", "hello"}), withArg(nil))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -837,8 +867,29 @@ var _ = Describe("Podman play kube", func() {
Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello]`))
})
+ // If you supply only args for a Container, the default Entrypoint defined in the Docker image is run with the args that you supplied.
It("podman play kube test correct command with only set args in yaml file", func() {
- pod := getPod(withCtr(getCtr(withImage(redis), withCmd(nil), withArg([]string{"echo", "hello"}))))
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg([]string{"echo", "hello"}))))
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ // this image's ENTRYPOINT is `/entrypoint.sh`
+ // so result should be `/entrypoint.sh + withArg(...)`
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[/entrypoint.sh echo hello]`))
+ })
+
+ // If you supply a command and args,
+ // the default Entrypoint and the default Cmd defined in the Docker image are ignored.
+ // Your command is run with your args.
+ It("podman play kube test correct command with both set args and cmd in yaml file", func() {
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo"}), withArg([]string{"hello"}))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -849,9 +900,7 @@ var _ = Describe("Podman play kube", func() {
inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
- // this image's ENTRYPOINT is called `docker-entrypoint.sh`
- // so result should be `docker-entrypoint.sh + withArg(...)`
- Expect(inspect.OutputToString()).To(ContainSubstring(`[docker-entrypoint.sh echo hello]`))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello]`))
})
It("podman play kube test correct output", func() {
@@ -1072,7 +1121,7 @@ var _ = Describe("Podman play kube", func() {
logs := podmanTest.Podman([]string{"logs", getCtrNameInPod(pod)})
logs.WaitWithDefaultTimeout()
Expect(logs.ExitCode()).To(Equal(0))
- Expect(logs.OutputToString()).To(ContainSubstring("Operation not permitted"))
+ Expect(logs.ErrorToString()).To(ContainSubstring("Operation not permitted"))
})
It("podman play kube seccomp pod level", func() {
@@ -1099,7 +1148,7 @@ var _ = Describe("Podman play kube", func() {
logs := podmanTest.Podman([]string{"logs", getCtrNameInPod(pod)})
logs.WaitWithDefaultTimeout()
Expect(logs.ExitCode()).To(Equal(0))
- Expect(logs.OutputToString()).To(ContainSubstring("Operation not permitted"))
+ Expect(logs.ErrorToString()).To(ContainSubstring("Operation not permitted"))
})
It("podman play kube with pull policy of never should be 125", func() {
@@ -1240,7 +1289,7 @@ spec:
inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[0]), "--format", "'{{ .Config.Cmd }}'"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
- // yaml's command shuold override the image's Entrypoint
+ // yaml's command should override the image's Entrypoint
correctCmd := "[" + strings.Join(defaultCtrCmd, " ") + " " + strings.Join(defaultCtrArg, " ")
Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd))
})
@@ -1285,7 +1334,7 @@ spec:
Expect(inspect.OutputToString()).To(Equal("5000/tcp -> 127.0.0.100:5000"))
})
- It("podman play kube test with non-existent empty HostPath type volume", func() {
+ It("podman play kube test with nonexistent empty HostPath type volume", func() {
hostPathLocation := filepath.Join(tempdir, "file")
pod := getPod(withVolume(getHostPathVolume(`""`, hostPathLocation)))
@@ -1312,7 +1361,7 @@ spec:
Expect(kube.ExitCode()).To(Equal(0))
})
- It("podman play kube test with non-existent File HostPath type volume", func() {
+ It("podman play kube test with nonexistent File HostPath type volume", func() {
hostPathLocation := filepath.Join(tempdir, "file")
pod := getPod(withVolume(getHostPathVolume("File", hostPathLocation)))
@@ -1548,4 +1597,23 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`})
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.OutputToString()).To(Equal("false"))
})
+
+ It("podman play kube test with HostNetwork", func() {
+ if !strings.Contains(podmanTest.OCIRuntime, "crun") {
+ Skip("Test only works on crun")
+ }
+
+ pod := getPod(withHostNetwork())
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", pod.Name, "--format", "{{ .InfraConfig.HostNetwork }}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(Equal("true"))
+ })
})
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index 7ec36b2f8..452a3de21 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -225,6 +225,7 @@ var _ = Describe("Podman pod create", func() {
})
It("podman pod container can override pod pid NS", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
session := podmanTest.Podman([]string{"pod", "create", "--share", "pid"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go
index f968f73a6..710147893 100644
--- a/test/e2e/pod_kill_test.go
+++ b/test/e2e/pod_kill_test.go
@@ -127,6 +127,7 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill all", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index ea8d10e78..225da785c 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -157,6 +157,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps --ctr-names", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go
index 41fc59267..a034ec2d1 100644
--- a/test/e2e/pod_stats_test.go
+++ b/test/e2e/pod_stats_test.go
@@ -17,8 +17,9 @@ var _ = Describe("Podman pod stats", func() {
)
BeforeEach(func() {
- if os.Geteuid() != 0 {
- SkipIfCgroupV2("--cgroup-manager=cgroupfs which doesn't work in rootless mode")
+ SkipIfRootless("Tests fail with both CGv1/2 + required --cgroup-manager=cgroupfs")
+ if isContainerized() {
+ SkipIfCgroupV1("All tests fail Error: unable to load cgroup at ...: cgroup deleted")
}
tempdir, err = CreateTempDirInTempDir()
@@ -176,7 +177,8 @@ var _ = Describe("Podman pod stats", func() {
It("podman stats on net=host post", func() {
// --net=host not supported for rootless pods at present
- SkipIfRootlessCgroupsV1("Pause stats not supported in cgroups v1")
+ // problem with sysctls being passed to containers of the pod.
+ SkipIfCgroupV1("Bug: Error: sysctl net.ipv4.ping_group_range is not allowed in the hosts network namespace: OCI runtime error")
podName := "testPod"
podCreate := podmanTest.Podman([]string{"pod", "create", "--net=host", "--name", podName})
podCreate.WaitWithDefaultTimeout()
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index c02ed5a50..3bc1012df 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -349,4 +349,64 @@ var _ = Describe("Podman prune", func() {
// all images are unused, so they all should be deleted!
Expect(len(images.OutputToStringArray())).To(Equal(len(CACHE_IMAGES)))
})
+
+ It("podman system prune --volumes --filter", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv1", "myvol2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv2", "myvol3"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1", "myvol4"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol5:/myvol5", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol6:/myvol6", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(7))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=label1=value1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(6))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1=slv1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(5))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(3))
+
+ podmanTest.Cleanup()
+ })
})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 05571157c..0c5d817ba 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -673,4 +673,55 @@ var _ = Describe("Podman ps", func() {
Expect(session.LineInOutputContains("test3")).To(BeTrue())
Expect(session.LineInOutputContains("test4")).To(BeTrue())
})
+ It("podman ps filter pod", func() {
+ pod1 := podmanTest.Podman([]string{"pod", "create", "--name", "pod1"})
+ pod1.WaitWithDefaultTimeout()
+ Expect(pod1.ExitCode()).To(BeZero())
+ con1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "pod1", ALPINE, "top"})
+ con1.WaitWithDefaultTimeout()
+ Expect(con1.ExitCode()).To(BeZero())
+
+ pod2 := podmanTest.Podman([]string{"pod", "create", "--name", "pod2"})
+ pod2.WaitWithDefaultTimeout()
+ Expect(pod2.ExitCode()).To(BeZero())
+ con2 := podmanTest.Podman([]string{"run", "-dt", "--pod", "pod2", ALPINE, "top"})
+ con2.WaitWithDefaultTimeout()
+ Expect(con2.ExitCode()).To(BeZero())
+
+ // bogus pod name or id should not result in error
+ session := podmanTest.Podman([]string{"ps", "--filter", "pod=1234"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(BeZero())
+
+ // filter by pod name
+ session = podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "--filter", "pod=pod1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(BeZero())
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+ Expect(StringInSlice(pod1.OutputToString(), session.OutputToStringArray()))
+
+ // filter by full pod id
+ session = podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "--filter", "pod=" + pod1.OutputToString()})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(BeZero())
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+ Expect(StringInSlice(pod1.OutputToString(), session.OutputToStringArray()))
+
+ // filter by partial pod id
+ session = podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "--filter", "pod=" + pod1.OutputToString()[0:12]})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(BeZero())
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+ Expect(StringInSlice(pod1.OutputToString(), session.OutputToStringArray()))
+
+ // filter by multiple pods is inclusive
+ session = podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "--filter", "pod=pod1", "--filter", "pod=pod2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(BeZero())
+ Expect(len(session.OutputToStringArray())).To(Equal(4))
+ Expect(StringInSlice(pod1.OutputToString(), session.OutputToStringArray()))
+ Expect(StringInSlice(pod2.OutputToString(), session.OutputToStringArray()))
+
+ })
+
})
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index 446e2bd38..7099a2904 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -393,8 +393,8 @@ var _ = Describe("Podman pull", func() {
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 4))
})
- It("podman pull from docker with nonexist --authfile", func() {
- session := podmanTest.Podman([]string{"pull", "--authfile", "/tmp/nonexist", ALPINE})
+ It("podman pull from docker with nonexistent --authfile", func() {
+ session := podmanTest.Podman([]string{"pull", "--authfile", "/tmp/nonexistent", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
@@ -506,7 +506,7 @@ var _ = Describe("Podman pull", func() {
session = podmanTest.Podman([]string{"pull", "--platform=linux/arm64", "--override-os", "windows", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
- expectedError = "--platform option can not be specified with --overide-arch or --override-os"
+ expectedError = "--platform option can not be specified with --override-arch or --override-os"
Expect(session.ErrorToString()).To(ContainSubstring(expectedError))
session = podmanTest.Podman([]string{"pull", "-q", "--platform=linux/arm64", ALPINE})
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index c8d77b7c6..1f40e4928 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -113,7 +113,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi image that is a parent of another image", func() {
- Skip("I need help with this one. i dont understand what is going on")
+ Skip("I need help with this one. i don't understand what is going on")
podmanTest.AddImageToRWStore(cirros)
session := podmanTest.Podman([]string{"run", "--name", "c_test", cirros, "true"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go
index 5242e04d2..51657cb1e 100644
--- a/test/e2e/run_ns_test.go
+++ b/test/e2e/run_ns_test.go
@@ -35,6 +35,7 @@ var _ = Describe("Podman run ns", func() {
})
It("podman run pidns test", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
session := podmanTest.Podman([]string{"run", fedoraMinimal, "bash", "-c", "echo $$"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -105,6 +106,7 @@ var _ = Describe("Podman run ns", func() {
})
It("podman run --ipc=host --pid=host", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
cmd := exec.Command("ls", "-l", "/proc/self/ns/pid")
res, err := cmd.Output()
Expect(err).To(BeNil())
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index ab11128ba..48f9ea76e 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -16,22 +16,22 @@ import (
// know about at compile time. That is: the kernel may have more caps
// available than we are aware of, leading to host=FFF... and ctr=3FF...
// because the latter is all we request. Accept that.
-func containerCapMatchesHost(ctr_cap string, host_cap string) {
+func containerCapMatchesHost(ctrCap string, hostCap string) {
if isRootless() {
return
}
- ctr_cap_n, err := strconv.ParseUint(ctr_cap, 16, 64)
- Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctr_cap)
+ ctrCap_n, err := strconv.ParseUint(ctrCap, 16, 64)
+ Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctrCap)
- host_cap_n, err := strconv.ParseUint(host_cap, 16, 64)
- Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", host_cap)
+ hostCap_n, err := strconv.ParseUint(hostCap, 16, 64)
+ Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", hostCap)
// host caps can never be zero (except rootless).
// and host caps must always be a superset (inclusive) of container
- Expect(host_cap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", host_cap)
- Expect(host_cap_n).To(BeNumerically(">=", ctr_cap_n), "host cap %q should never be less than container cap %q", host_cap, ctr_cap)
- host_cap_masked := host_cap_n & (1<<len(capability.List()) - 1)
- Expect(ctr_cap_n).To(Equal(host_cap_masked), "container cap %q is not a subset of host cap %q", ctr_cap, host_cap)
+ Expect(hostCap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", hostCap)
+ Expect(hostCap_n).To(BeNumerically(">=", ctrCap_n), "host cap %q should never be less than container cap %q", hostCap, ctrCap)
+ hostCap_masked := hostCap_n & (1<<len(capability.List()) - 1)
+ Expect(ctrCap_n).To(Equal(hostCap_masked), "container cap %q is not a subset of host cap %q", ctrCap, hostCap)
}
var _ = Describe("Podman privileged container tests", func() {
@@ -68,26 +68,38 @@ var _ = Describe("Podman privileged container tests", func() {
})
It("podman privileged CapEff", func() {
- host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
- Expect(host_cap.ExitCode()).To(Equal(0))
+ hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
+ Expect(hostCap.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", "--privileged", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString())
+ containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})
It("podman cap-add CapEff", func() {
// Get caps of current process
- host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
- Expect(host_cap.ExitCode()).To(Equal(0))
+ hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
+ Expect(hostCap.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString())
+ containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
+ })
+
+ It("podman cap-add CapEff with --user", func() {
+ // Get caps of current process
+ hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
+ Expect(hostCap.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"run", "--user=bin", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})
It("podman cap-drop CapEff", func() {
@@ -98,6 +110,15 @@ var _ = Describe("Podman privileged container tests", func() {
Expect("0000000000000000").To(Equal(capEff[1]))
})
+ It("podman privileged should disable seccomp by default", func() {
+ hostSeccomp := SystemExec("grep", []string{"-Ei", "^Seccomp:\\s+0$", "/proc/self/status"})
+ Expect(hostSeccomp.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "grep", "-Ei", "^Seccomp:\\s+0$", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman non-privileged should have very few devices", func() {
session := podmanTest.Podman([]string{"run", "-t", "busybox", "ls", "-l", "/dev"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go
index 3294f6d3b..2e9d38e2d 100644
--- a/test/e2e/run_selinux_test.go
+++ b/test/e2e/run_selinux_test.go
@@ -274,6 +274,7 @@ var _ = Describe("Podman run", func() {
})
It("podman test --pid=host", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
session := podmanTest.Podman([]string{"run", "--pid=host", ALPINE, "cat", "/proc/self/attr/current"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index dbdd6a072..4888a676b 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -493,7 +493,9 @@ USER bin`
Skip("Kernel does not support blkio.weight")
}
}
-
+ if podmanTest.Host.Distribution == "ubuntu" {
+ Skip("Ubuntu <= 20.10 lacks BFQ scheduler")
+ }
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"})
@@ -1228,8 +1230,8 @@ USER mail`
Expect(session).To(ExitWithError())
})
- It("podman run should fail with nonexist authfile", func() {
- session := podmanTest.Podman([]string{"run", "--authfile", "/tmp/nonexist", ALPINE, "ls"})
+ It("podman run should fail with nonexistent authfile", func() {
+ session := podmanTest.Podman([]string{"run", "--authfile", "/tmp/nonexistent", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go
index 7c0b8bc9b..10e16ea23 100644
--- a/test/e2e/runlabel_test.go
+++ b/test/e2e/runlabel_test.go
@@ -114,12 +114,12 @@ var _ = Describe("podman container runlabel", func() {
Expect(result.ExitCode()).To(Equal(0))
})
- It("runlabel should fail with nonexist authfile", func() {
+ It("runlabel should fail with nonexistent authfile", func() {
image := "podman-runlabel-test:podman"
podmanTest.BuildImage(PodmanDockerfile, image, "false")
- // runlabel should fail with nonexist authfile
- result := podmanTest.Podman([]string{"container", "runlabel", "--authfile", "/tmp/nonexist", "RUN", image})
+ // runlabel should fail with nonexistent authfile
+ result := podmanTest.Podman([]string{"container", "runlabel", "--authfile", "/tmp/nonexistent", "RUN", image})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Not(Equal(0)))
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index 5c3c69fd4..f809c5afe 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -430,9 +430,9 @@ registries = ['{{.Host}}:{{.Port}}']`
resetRegistriesConfigEnv()
})
- // search should fail with nonexist authfile
- It("podman search fail with nonexist --authfile", func() {
- search := podmanTest.Podman([]string{"search", "--authfile", "/tmp/nonexist", ALPINE})
+ // search should fail with nonexistent authfile
+ It("podman search fail with nonexistent --authfile", func() {
+ search := podmanTest.Podman([]string{"search", "--authfile", "/tmp/nonexistent", ALPINE})
search.WaitWithDefaultTimeout()
Expect(search.ExitCode()).To(Not(Equal(0)))
})
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index 942e00123..a6f22e007 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -49,6 +49,29 @@ var _ = Describe("Podman start", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman start --rm removed on failure", func() {
+ session := podmanTest.Podman([]string{"create", "--name=test", "--rm", ALPINE, "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"start", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ session = podmanTest.Podman([]string{"container", "exists", "test"})
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
+ It("podman start --rm --attach removed on failure", func() {
+ session := podmanTest.Podman([]string{"create", "--rm", ALPINE, "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+ session = podmanTest.Podman([]string{"start", "--attach", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ session = podmanTest.Podman([]string{"container", "exists", cid})
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
It("podman container start single container by id", func() {
session := podmanTest.Podman([]string{"container", "create", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go
index ab117a2a0..53aa230e9 100644
--- a/test/e2e/stats_test.go
+++ b/test/e2e/stats_test.go
@@ -140,7 +140,7 @@ var _ = Describe("Podman stats", func() {
// Regression test for #8265
It("podman stats with custom memory limits", func() {
- // Run thre containers. One with a memory limit. Make sure
+ // Run three containers. One with a memory limit. Make sure
// that the limits are different and the limited one has a
// lower limit.
ctrNoLimit0 := "no-limit-0"
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index 48294943b..49ab3b8ed 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -13,10 +13,10 @@ import (
var _ = Describe("Podman systemd", func() {
var (
- tempdir string
- err error
- podmanTest *PodmanTestIntegration
- systemd_unit_file string
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ systemdUnitFile string
)
BeforeEach(func() {
@@ -27,7 +27,7 @@ var _ = Describe("Podman systemd", func() {
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
podmanTest.SeedImages()
- systemd_unit_file = `[Unit]
+ systemdUnitFile = `[Unit]
Description=redis container
[Service]
Restart=always
@@ -50,7 +50,7 @@ WantedBy=multi-user.target
SkipIfRootless("rootless can not write to /etc")
SkipIfContainerized("test does not have systemd as pid 1")
- sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemd_unit_file), 0644)
+ sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemdUnitFile), 0644)
Expect(sys_file).To(BeNil())
defer func() {
stop := SystemExec("bash", []string{"-c", "systemctl stop redis"})
@@ -131,6 +131,21 @@ WantedBy=multi-user.target
Expect(conData[0].Config.SystemdMode).To(BeTrue())
})
+ It("podman create container with --uidmap and conmon PidFile accessible", func() {
+ ctrName := "testCtrUidMap"
+ run := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:1:1000", "--name", ctrName, ALPINE, "top"})
+ run.WaitWithDefaultTimeout()
+ Expect(run.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"inspect", "--format", "{{.ConmonPidFile}}", ctrName})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ pidFile := strings.TrimSuffix(session.OutputToString(), "\n")
+ _, err := ioutil.ReadFile(pidFile)
+ Expect(err).To(BeNil())
+ })
+
It("podman create container with systemd=always triggers systemd mode", func() {
ctrName := "testCtr"
run := podmanTest.Podman([]string{"create", "--name", ctrName, "--systemd", "always", ALPINE})
diff --git a/test/e2e/toolbox_test.go b/test/e2e/toolbox_test.go
index 7393b13cb..6de775983 100644
--- a/test/e2e/toolbox_test.go
+++ b/test/e2e/toolbox_test.go
@@ -121,6 +121,7 @@ var _ = Describe("Toolbox-specific testing", func() {
if podmanTest.RemoteTest {
Skip("Shm size check does not work with a remote client")
}
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
var session *PodmanSessionIntegration
var cmd *exec.Cmd
var hostShmSize, containerShmSize int
@@ -239,7 +240,7 @@ var _ = Describe("Toolbox-specific testing", func() {
session = podmanTest.Podman([]string{"logs", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(ContainSubstring(expectedOutput))
+ Expect(session.ErrorToString()).To(ContainSubstring(expectedOutput))
})
It("podman create --userns=keep-id + podman exec - adding group with groupadd", func() {
diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go
index 2a7feaacb..9bdc3af9d 100644
--- a/test/e2e/tree_test.go
+++ b/test/e2e/tree_test.go
@@ -35,7 +35,7 @@ var _ = Describe("Podman image tree", func() {
It("podman image tree", func() {
SkipIfRemote("Does not work on remote client")
- Skip("dont understand why this fails")
+ Skip("don't understand why this fails")
podmanTest.AddImageToRWStore(cirros)
dockerfile := `FROM quay.io/libpod/cirros:latest
RUN mkdir hello
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 8c44e57e4..544532ee0 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -82,5 +82,13 @@ var _ = Describe("Podman volume create", func() {
inspectGID.WaitWithDefaultTimeout()
Expect(inspectGID.ExitCode()).To(Equal(0))
Expect(inspectGID.OutputToString()).To(Equal(gid))
+
+ // options should containt `uid=3000,gid=4000:3000:4000`
+ optionFormat := `{{ .Options.o }}:{{ .Options.UID }}:{{ .Options.GID }}`
+ optionStrFormatExpect := fmt.Sprintf(`uid=%s,gid=%s:%s:%s`, uid, gid, uid, gid)
+ inspectOpts := podmanTest.Podman([]string{"volume", "inspect", "--format", optionFormat, volName})
+ inspectOpts.WaitWithDefaultTimeout()
+ Expect(inspectOpts.ExitCode()).To(Equal(0))
+ Expect(inspectOpts.OutputToString()).To(Equal(optionStrFormatExpect))
})
})
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index c8521ebe7..a910c47a7 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -62,6 +62,66 @@ var _ = Describe("Podman volume prune", func() {
podmanTest.Cleanup()
})
+ It("podman prune volume --filter", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv1", "myvol2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv2", "myvol3"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1", "myvol4"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol5:/myvol5", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol6:/myvol6", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(7))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=label1=value1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(6))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=sharedlabel1=slv1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(5))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=sharedlabel1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(3))
+
+ podmanTest.Cleanup()
+ })
+
It("podman system prune --volume", func() {
session := podmanTest.Podman([]string{"volume", "create"})
session.WaitWithDefaultTimeout()
diff --git a/test/framework/framework.go b/test/framework/framework.go
index 52401faf8..57c6bda2a 100644
--- a/test/framework/framework.go
+++ b/test/framework/framework.go
@@ -7,7 +7,7 @@ import (
"github.com/onsi/gomega"
)
-// TestFramework is used to support commonnly used test features
+// TestFramework is used to support commonly used test features
type TestFramework struct {
setup func(*TestFramework) error
teardown func(*TestFramework) error
diff --git a/test/python/docker/test_containers.py b/test/python/docker/test_containers.py
index 20d8417c3..5a9f761a6 100644
--- a/test/python/docker/test_containers.py
+++ b/test/python/docker/test_containers.py
@@ -143,7 +143,7 @@ class TestContainers(unittest.TestCase):
top = self.client.containers.get(TestContainers.topContainerId)
top.stop()
- # Pause exited container should trow error
+ # Pause exited container should throw error
with self.assertRaises(errors.APIError) as error:
top.pause()
self.assertEqual(error.exception.response.status_code, 500)
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 3ee141f5f..29dc95dc3 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -401,7 +401,7 @@ json-file | f
is "$output" "$driver" "podman inspect: driver"
# If LogPath is non-null, check that it exists and has a valid log
- run_podman inspect --format '{{.LogPath}}' myctr
+ run_podman inspect --format '{{.HostConfig.LogConfig.Path}}' myctr
if [[ $do_check != '-' ]]; then
is "$output" "/.*" "LogPath (driver=$driver)"
if ! test -e "$output"; then
@@ -415,13 +415,18 @@ json-file | f
fi
if [[ $driver != 'none' ]]; then
- run_podman logs myctr
- is "$output" "$msg" "check that podman logs works as expected"
+ if [[ $driver = 'journald' ]] && journald_unavailable; then
+ # Cannot perform check
+ :
+ else
+ run_podman logs myctr
+ is "$output" "$msg" "podman logs, with driver '$driver'"
+ fi
else
run_podman 125 logs myctr
if ! is_remote; then
is "$output" ".*this container is using the 'none' log driver, cannot read logs.*" \
- "podman logs does not work with none log driver"
+ "podman logs, with driver 'none', should fail with error"
fi
fi
run_podman rm myctr
@@ -437,14 +442,7 @@ json-file | f
skip_if_remote "We cannot read journalctl over remote."
# We can't use journald on RHEL as rootless, either: rhbz#1895105
- if is_rootless; then
- run journalctl -n 1
- if [[ $status -ne 0 ]]; then
- if [[ $output =~ permission ]]; then
- skip "Cannot use rootless journald on this system"
- fi
- fi
- fi
+ skip_if_journald_unavailable
msg=$(random_string 20)
pidfile="${PODMAN_TMPDIR}/$(random_string 20)"
@@ -550,27 +548,33 @@ json-file | f
}
@test "Verify /run/.containerenv exist" {
- run_podman run --rm $IMAGE ls -1 /run/.containerenv
- is "$output" "/run/.containerenv"
-
- run_podman run --privileged --rm $IMAGE sh -c '. /run/.containerenv; echo $engine'
- is "$output" ".*podman.*" "failed to identify engine"
-
- run_podman run --privileged --name "testcontainerenv" --rm $IMAGE sh -c '. /run/.containerenv; echo $name'
- is "$output" ".*testcontainerenv.*"
-
- run_podman run --privileged --rm $IMAGE sh -c '. /run/.containerenv; echo $image'
- is "$output" ".*$IMAGE.*" "failed to idenitfy image"
-
- run_podman run --privileged --rm $IMAGE sh -c '. /run/.containerenv; echo $rootless'
- # FIXME: on some CI systems, 'run --privileged' emits a spurious
- # warning line about dup devices. Ignore it.
- remove_same_dev_warning
- if is_rootless; then
- is "$output" "1"
- else
- is "$output" "0"
- fi
+ # Nonprivileged container: file exists, but must be empty
+ run_podman run --rm $IMAGE stat -c '%s' /run/.containerenv
+ is "$output" "0" "file size of /run/.containerenv, nonprivileged"
+
+ # Prep work: get ID of image; make a cont. name; determine if we're rootless
+ run_podman inspect --format '{{.ID}}' $IMAGE
+ local iid="$output"
+
+ random_cname=c$(random_string 15 | tr A-Z a-z)
+ local rootless=0
+ if is_rootless; then
+ rootless=1
+ fi
+
+ run_podman run --privileged --rm --name $random_cname $IMAGE \
+ sh -c '. /run/.containerenv; echo $engine; echo $name; echo $image; echo $id; echo $imageid; echo $rootless'
+
+ # FIXME: on some CI systems, 'run --privileged' emits a spurious
+ # warning line about dup devices. Ignore it.
+ remove_same_dev_warning
+
+ is "${lines[0]}" "podman-.*" 'containerenv : $engine'
+ is "${lines[1]}" "$random_cname" 'containerenv : $name'
+ is "${lines[2]}" "$IMAGE" 'containerenv : $image'
+ is "${lines[3]}" "[0-9a-f]\{64\}" 'containerenv : $id'
+ is "${lines[4]}" "$iid" 'containerenv : $imageid'
+ is "${lines[5]}" "$rootless" 'containerenv : $rootless'
}
@test "podman run with --net=host and --port prints warning" {
diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats
index a081a7ce1..bac153b8e 100644
--- a/test/system/035-logs.bats
+++ b/test/system/035-logs.bats
@@ -55,14 +55,7 @@ ${cid[0]} d" "Sequential output from logs"
@test "podman logs over journald" {
# We can't use journald on RHEL as rootless: rhbz#1895105
- if is_rootless; then
- run journalctl -n 1
- if [[ $status -ne 0 ]]; then
- if [[ $output =~ permission ]]; then
- skip "Cannot use rootless journald on this system"
- fi
- fi
- fi
+ skip_if_journald_unavailable
msg=$(random_string 20)
diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats
index 1ed2779b2..0447122b1 100644
--- a/test/system/040-ps.bats
+++ b/test/system/040-ps.bats
@@ -82,4 +82,43 @@ load helpers
run_podman rm -a
}
+@test "podman ps -a --storage" {
+ skip_if_remote "ps --storage does not work over remote"
+
+ # Setup: ensure that we have no hidden storage containers
+ run_podman ps --storage -a
+ is "${#lines[@]}" "1" "setup check: no storage containers at start of test"
+
+ # Force a buildah timeout; this leaves a buildah container behind
+ PODMAN_TIMEOUT=5 run_podman 124 build -t thiswillneverexist - <<EOF
+FROM $IMAGE
+RUN sleep 30
+EOF
+
+ run_podman ps -a
+ is "${#lines[@]}" "1" "podman ps -a does not see buildah container"
+
+ run_podman ps --storage -a
+ is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container"
+ is "${lines[1]}" \
+ "[0-9a-f]\{12\} \+$IMAGE *buildah .* seconds ago .* storage .* ${PODMAN_TEST_IMAGE_NAME}-working-container" \
+ "podman ps --storage"
+
+ cid="${lines[1]:0:12}"
+
+ # 'rm -a' should be a NOP
+ run_podman rm -a
+ run_podman ps --storage -a
+ is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container"
+
+ # This is what deletes the container
+ # FIXME: why doesn't "podman rm --storage $cid" do anything?
+ run_podman rm -f "$cid"
+
+ run_podman ps --storage -a
+ is "${#lines[@]}" "1" "storage container has been removed"
+}
+
+
+
# vim: filetype=sh
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index 43bdf217d..d3cf1c274 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -8,8 +8,6 @@
load helpers
@test "podman cp file from host to container" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-file-host-to-ctr
mkdir -p $srcdir
local -a randomcontent=(
@@ -57,60 +55,16 @@ load helpers
is "$output" 'Error: ".*/IdoNotExist" could not be found on the host' \
"copy nonexistent host path"
- # Container path does not exist. Notice that the error message shows how
- # the specified container is resolved.
+ # Container (parent) path does not exist.
run_podman 125 cp $srcdir/hostfile0 cpcontainer:/IdoNotExist/
- is "$output" 'Error: "/IdoNotExist/" could not be found on container.*(resolved to .*/IdoNotExist.*' \
+ is "$output" 'Error: "/IdoNotExist/" could not be found on container cpcontainer: No such file or directory' \
"copy into nonexistent path in container"
run_podman rm -f cpcontainer
}
-@test "podman cp --extract=true tar archive to container" {
- skip_if_remote "podman-remote does not yet handle cp"
-
- # Create tempfile with random name and content
- dirname=cp-test-extract
- srcdir=$PODMAN_TMPDIR/$dirname
- mkdir -p $srcdir
- rand_filename=$(random_string 20)
- rand_content=$(random_string 50)
- echo $rand_content > $srcdir/$rand_filename
- chmod 644 $srcdir/$rand_filename
-
- # Now tar it up!
- tar_file=$PODMAN_TMPDIR/archive.tar.gz
- tar -C $PODMAN_TMPDIR -zvcf $tar_file $dirname
-
- run_podman run -d --name cpcontainer $IMAGE sleep infinity
-
- # First just copy without extracting the archive.
- run_podman cp $tar_file cpcontainer:/tmp
- # Now remove the archive which will also test if it exists and is a file.
- # To save expensive exec'ing, create a file for the next tests.
- run_podman exec cpcontainer sh -c "rm /tmp/archive.tar.gz; touch /tmp/file.txt"
-
- # Now copy with extracting the archive. NOTE that Podman should
- # auto-decompress the file if needed.
- run_podman cp --extract=true $tar_file cpcontainer:/tmp
- run_podman exec cpcontainer cat /tmp/$dirname/$rand_filename
- is "$output" "$rand_content"
-
- # Test extract on non archive.
- run_podman cp --extract=true $srcdir/$rand_filename cpcontainer:/foo.txt
-
- # Cannot extract an archive to a file!
- run_podman 125 cp --extract=true $tar_file cpcontainer:/tmp/file.txt
- is "$output" 'Error: cannot extract archive .* to file "/tmp/file.txt"'
-
- run_podman rm -f cpcontainer
-}
-
-
@test "podman cp file from container to host" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-file-ctr-to-host
mkdir -p $srcdir
@@ -153,8 +107,6 @@ load helpers
@test "podman cp dir from host to container" {
- skip_if_remote "podman-remote does not yet handle cp"
-
dirname=dir-test
srcdir=$PODMAN_TMPDIR/$dirname
mkdir -p $srcdir
@@ -195,8 +147,6 @@ load helpers
@test "podman cp dir from container to host" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/dir-test
mkdir -p $srcdir
@@ -230,8 +180,6 @@ load helpers
@test "podman cp file from host to container volume" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-volume
mkdir -p $srcdir
echo "This file should be in volume2" > $srcdir/hostfile
@@ -268,8 +216,6 @@ load helpers
@test "podman cp file from host to container mount" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-mount-src
mountdir=$PODMAN_TMPDIR/cp-test-mount
mkdir -p $srcdir $mountdir
@@ -296,8 +242,6 @@ load helpers
# perform wildcard expansion in the container. We should get both
# files copied into the host.
@test "podman cp * - wildcard copy multiple files from container to host" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
mkdir -p $srcdir $dstdir
@@ -321,8 +265,6 @@ load helpers
# Create a file on the host; make a symlink in the container pointing
# into host-only space. Try to podman-cp that symlink. It should fail.
@test "podman cp - will not recognize symlink pointing into host space" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
mkdir -p $srcdir $dstdir
@@ -350,8 +292,6 @@ load helpers
# in the container pointing to 'file*' (file star). Try to podman-cp
# this invalid double symlink. It must fail.
@test "podman cp - will not expand globs in host space (#3829)" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
mkdir -p $srcdir $dstdir
@@ -372,8 +312,6 @@ load helpers
# Another symlink into host space, this one named '*' (star). cp should fail.
@test "podman cp - will not expand wildcard" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
mkdir -p $srcdir $dstdir
@@ -394,8 +332,6 @@ load helpers
# THIS IS EXTREMELY WEIRD. Podman expands symlinks in weird ways.
@test "podman cp into container: weird symlink expansion" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
mkdir -p $srcdir $dstdir
@@ -427,7 +363,7 @@ load helpers
is "$output" "" "output from podman cp 1"
run_podman 125 cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/
- is "$output" 'Error: "/tmp/d2/x/" could not be found on container.*' "cp will not create nonexistent destination directory"
+ is "$output" 'Error: "/tmp/d2/x/" could not be found on container cpcontainer: No such file or directory' "cp will not create nonexistent destination directory"
run_podman cp --pause=false $srcdir/$rand_filename3 cpcontainer:/tmp/d3/x
is "$output" "" "output from podman cp 3"
@@ -454,8 +390,6 @@ load helpers
# rhbz1741718 : file copied into container:/var/lib/foo appears as /foo
# (docker only, never seems to have affected podman. Make sure it never does).
@test "podman cp into a subdirectory matching GraphRoot" {
- skip_if_remote "podman-remote does not yet handle cp"
-
# Create tempfile with random name and content
srcdir=$PODMAN_TMPDIR/cp-test-in
mkdir -p $srcdir
@@ -491,8 +425,6 @@ load helpers
@test "podman cp from stdin to container" {
- skip_if_remote "podman-remote does not yet handle cp"
-
# Create tempfile with random name and content
srcdir=$PODMAN_TMPDIR/cp-test-stdin
mkdir -p $srcdir
@@ -525,24 +457,22 @@ load helpers
# Input stream must be a (compressed) tar archive.
run_podman 125 cp - cpcontainer:/tmp < $srcdir/$rand_filename
- is "$output" "Error:.*: error reading tar stream.*" "input stream must be a (compressed) tar archive"
+ is "$output" "Error: source must be a (compressed) tar archive when copying from stdin"
# Destination must be a directory (on an existing file).
run_podman exec cpcontainer touch /tmp/file.txt
run_podman 125 cp /dev/stdin cpcontainer:/tmp/file.txt < $tar_file
- is "$output" 'Error: destination must be a directory or stream when copying from a stream'
+ is "$output" 'Error: destination must be a directory when copying from stdin'
# Destination must be a directory (on an absent path).
run_podman 125 cp /dev/stdin cpcontainer:/tmp/IdoNotExist < $tar_file
- is "$output" 'Error: destination must be a directory or stream when copying from a stream'
+ is "$output" 'Error: destination must be a directory when copying from stdin'
run_podman rm -f cpcontainer
}
@test "podman cp from container to stdout" {
- skip_if_remote "podman-remote does not yet handle cp"
-
srcdir=$PODMAN_TMPDIR/cp-test-stdout
mkdir -p $srcdir
rand_content=$(random_string 50)
@@ -569,7 +499,7 @@ load helpers
tar xvf $srcdir/stdout.tar -C $srcdir
run cat $srcdir/file.txt
is "$output" "$rand_content"
- run 1 ls $srcfir/empty.txt
+ run 1 ls $srcdir/empty.txt
rm -f $srcdir/*
# Copy directory.
@@ -579,9 +509,9 @@ load helpers
fi
tar xvf $srcdir/stdout.tar -C $srcdir
- run cat $srcdir/file.txt
+ run cat $srcdir/tmp/file.txt
is "$output" "$rand_content"
- run cat $srcdir/empty.txt
+ run cat $srcdir/tmp/empty.txt
is "$output" ""
run_podman rm -f cpcontainer
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 8e9a2d613..0e83a184b 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -345,7 +345,7 @@ EOF
# all commands after 'podman build' would silently be ignored.
# In the test below, prior to #8092, the 'sed' would not get
# any input, and we would never see $random3 in the output.
- # And, we use 'sed' to massage $random3 juuuuust on the remote
+ # And, we use 'sed' to massage $random3 just on the remote
# chance that podman itself could pass stdin through.
results=$(echo $random3 | (
echo $random1
@@ -424,6 +424,23 @@ EOF
run_podman rmi -a --force
}
+@test "podman build --logfile test" {
+ tmpdir=$PODMAN_TMPDIR/build-test
+ mkdir -p $tmpdir
+ tmpbuilddir=$tmpdir/build
+ mkdir -p $tmpbuilddir
+ dockerfile=$tmpbuilddir/Dockerfile
+ cat >$dockerfile <<EOF
+FROM $IMAGE
+EOF
+
+ run_podman build -t build_test --format=docker --logfile=$tmpdir/logfile $tmpbuilddir
+ run cat $tmpdir/logfile
+ is "$output" ".*STEP 2: COMMIT" "COMMIT seen in log"
+
+ run_podman rmi -f build_test
+}
+
function teardown() {
# A timeout or other error in 'build' can leave behind stale images
# that podman can't even see and which will cascade into subsequent
diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats
index c99ba4fa6..a5fa0f4e6 100644
--- a/test/system/260-sdnotify.bats
+++ b/test/system/260-sdnotify.bats
@@ -100,8 +100,17 @@ function _assert_mainpid_is_conmon() {
run_podman logs sdnotify_conmon_c
is "$output" "READY" "\$NOTIFY_SOCKET in container"
+ # The 'echo's help us debug failed runs
run cat $_SOCAT_LOG
- is "${lines[-1]}" "READY=1" "final output from sdnotify"
+ echo "socat log:"
+ echo "$output"
+
+ # ARGH! 'READY=1' should always be the last output line. But sometimes,
+ # for reasons unknown, we get an extra MAINPID=xxx after READY=1 (#8718).
+ # Who knows if this is a systemd bug, or conmon, or what. I don't
+ # even know where to begin asking. So, to eliminate the test flakes,
+ # we look for READY=1 _anywhere_ in the output, not just the last line.
+ is "$output" ".*READY=1.*" "sdnotify sent READY=1"
_assert_mainpid_is_conmon "${lines[0]}"
diff --git a/test/system/600-completion.bats b/test/system/600-completion.bats
index 1e43cdc41..8cac2c9aa 100644
--- a/test/system/600-completion.bats
+++ b/test/system/600-completion.bats
@@ -8,6 +8,17 @@
load helpers
+# Returns true if we are able to podman-pause
+function _can_pause() {
+ # Even though we're just trying completion, not an actual unpause,
+ # podman barfs with:
+ # Error: unpause is not supported for cgroupv1 rootless containers
+ if is_rootless && is_cgroupsv1; then
+ return 1
+ fi
+ return 0
+}
+
function check_shell_completion() {
local count=0
@@ -61,8 +72,9 @@ function check_shell_completion() {
if ! is_remote; then
run_completion "$@" $cmd "--"
# If this fails there is most likely a problem with the cobra library
- is "${lines[0]}" "--.*" "Found flag in suggestions"
- [ ${#lines[@]} -gt 2 ] || die "No flag suggestions"
+ is "${lines[0]}" "--.*" \
+ "$* $cmd: flag(s) listed in suggestions"
+ [ ${#lines[@]} -gt 2 ] || die "$* $cmd: No flag suggestions"
_check_completion_end NoFileComp
fi
# continue the outer for args loop
@@ -70,8 +82,14 @@ function check_shell_completion() {
;;
*CONTAINER*)
+ # podman unpause fails early on rootless cgroupsv1
+ if [[ $cmd = "unpause" ]] && ! _can_pause; then
+ continue 2
+ fi
+
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*-$random_container_name${nl}" "Found expected container in suggestions"
+ is "$output" ".*-$random_container_name${nl}" \
+ "$* $cmd: actual container listed in suggestions"
match=true
# resume
@@ -79,7 +97,8 @@ function check_shell_completion() {
*POD*)
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*-$random_pod_name${nl}" "Found expected pod in suggestions"
+ is "$output" ".*-$random_pod_name${nl}" \
+ "$* $cmd: actual pod listed in suggestions"
_check_completion_end NoFileComp
match=true
@@ -88,16 +107,20 @@ function check_shell_completion() {
*IMAGE*)
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*localhost/$random_image_name:$random_image_tag${nl}" "Found expected image in suggestions"
+ is "$output" ".*localhost/$random_image_name:$random_image_tag${nl}" \
+ "$* $cmd: actual image listed in suggestions"
# check that we complete the image with and without tag after at least one char is typed
run_completion "$@" $cmd "${extra_args[@]}" "${random_image_name:0:1}"
- is "$output" ".*$random_image_name:$random_image_tag${nl}" "Found expected image with tag in suggestions"
- is "$output" ".*$random_image_name${nl}" "Found expected image without tag in suggestions"
+ is "$output" ".*$random_image_name:$random_image_tag${nl}" \
+ "$* $cmd: image name:tag included in suggestions"
+ is "$output" ".*$random_image_name${nl}" \
+ "$* $cmd: image name(w/o tag) included in suggestions"
# check that we complete the image id after at least two chars are typed
run_completion "$@" $cmd "${extra_args[@]}" "${random_image_id:0:2}"
- is "$output" ".*$random_image_id${nl}" "Found expected image id in suggestions"
+ is "$output" ".*$random_image_id${nl}" \
+ "$* $cmd: image id included in suggestions when two leading characters present in command line"
match=true
# resume
@@ -105,7 +128,8 @@ function check_shell_completion() {
*NETWORK*)
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*$random_network_name${nl}" "Found network in suggestions"
+ is "$output" ".*$random_network_name${nl}" \
+ "$* $cmd: actual network listed in suggestions"
_check_completion_end NoFileComp
match=true
@@ -114,7 +138,8 @@ function check_shell_completion() {
*VOLUME*)
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*$random_volume_name${nl}" "Found volume in suggestions"
+ is "$output" ".*$random_volume_name${nl}" \
+ "$* $cmd: actual volume listed in suggestions"
_check_completion_end NoFileComp
match=true
@@ -126,14 +151,14 @@ function check_shell_completion() {
### FIXME how can we get the configured registries?
_check_completion_end NoFileComp
### FIXME this fails if no registries are configured
- [[ ${#lines[@]} -gt 2 ]] || die "No registries found in suggestions"
+ [[ ${#lines[@]} -gt 2 ]] || die "$* $cmd: No REGISTRIES found in suggestions"
match=true
# resume
;;&
*PATH* | *CONTEXT* | *KUBEFILE* | *COMMAND* | *ARG...* | *URI*)
- # default shell completion should be done for everthing which accepts a path
+ # default shell completion should be done for everything which accepts a path
run_completion "$@" $cmd "${extra_args[@]}" ""
# cp is a special case it returns ShellCompDirectiveNoSpace
@@ -141,7 +166,7 @@ function check_shell_completion() {
_check_completion_end NoSpace
else
_check_completion_end Default
- [[ ${#lines[@]} -eq 2 ]] || die "Suggestions are in the output"
+ [[ ${#lines[@]} -eq 2 ]] || die "$* $cmd: Suggestions are in the output"
fi
;;
@@ -172,7 +197,7 @@ function check_shell_completion() {
run_completion "$@" $cmd "${extra_args[@]}" ""
_check_completion_end NoFileComp
if [ ${#lines[@]} -gt 2 ]; then
- # checking for line count is not enough since we may inlcude additional debug output
+ # checking for line count is not enough since we may include additional debug output
# lines starting with [Debug] are allowed
i=0
length=$(( ${#lines[@]} - 2 ))
@@ -212,7 +237,9 @@ function _check_completion_end() {
run_podman create --name created-$random_container_name $IMAGE
run_podman run --name running-$random_container_name -d $IMAGE top
run_podman run --name pause-$random_container_name -d $IMAGE top
- run_podman pause pause-$random_container_name
+ if _can_pause; then
+ run_podman pause pause-$random_container_name
+ fi
run_podman run --name exited-$random_container_name -d $IMAGE echo exited
# create pods for each state
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 6a7c6cc42..0572c6866 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -14,7 +14,7 @@ PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODM
IMAGE=$PODMAN_TEST_IMAGE_FQN
# Default timeout for a podman command.
-PODMAN_TIMEOUT=${PODMAN_TIMEOUT:-60}
+PODMAN_TIMEOUT=${PODMAN_TIMEOUT:-120}
# Prompt to display when logging podman commands; distinguish root/rootless
_LOG_PROMPT='$'
@@ -168,8 +168,11 @@ function run_podman() {
if [ "$status" -eq 124 ]; then
if expr "$output" : ".*timeout: sending" >/dev/null; then
- echo "*** TIMED OUT ***"
- false
+ # It's possible for a subtest to _want_ a timeout
+ if [[ "$expected_rc" != "124" ]]; then
+ echo "*** TIMED OUT ***"
+ false
+ fi
fi
fi
@@ -259,6 +262,31 @@ function is_cgroupsv2() {
test "$cgroup_type" = "cgroup2fs"
}
+# rhbz#1895105: rootless journald is unavailable except to users in
+# certain magic groups; which our testuser account does not belong to
+# (intentional: that is the RHEL default, so that's the setup we test).
+function journald_unavailable() {
+ if ! is_rootless; then
+ # root must always have access to journal
+ return 1
+ fi
+
+ run journalctl -n 1
+ if [[ $status -eq 0 ]]; then
+ return 1
+ fi
+
+ if [[ $output =~ permission ]]; then
+ return 0
+ fi
+
+ # This should never happen; if it does, it's likely that a subsequent
+ # test will fail. This output may help track that down.
+ echo "WEIRD: 'journalctl -n 1' failed with a non-permission error:"
+ echo "$output"
+ return 1
+}
+
###########################
# _add_label_if_missing # make sure skip messages include rootless/remote
###########################
@@ -315,6 +343,15 @@ function skip_if_cgroupsv1() {
fi
}
+##################################
+# skip_if_journald_unavailable # rhbz#1895105: rootless journald permissions
+##################################
+function skip_if_journald_unavailable {
+ if journald_unavailable; then
+ skip "Cannot use rootless journald on this system"
+ fi
+}
+
#########
# die # Abort with helpful message
#########
diff --git a/test/utils/common_function_test.go b/test/utils/common_function_test.go
index 0bbc31d5b..2f9e6f2c7 100644
--- a/test/utils/common_function_test.go
+++ b/test/utils/common_function_test.go
@@ -64,7 +64,7 @@ var _ = Describe("Common functions test", func() {
Expect(host.Version).To(Equal(strings.Trim(ver, "\"")))
}
},
- Entry("Configure file is not exist.", "/tmp/notexist", "", "", true),
+ Entry("Configure file is not exist.", "/tmp/nonexistent", "", "", true),
Entry("Item value with and without \"", "/tmp/os-release.test", "fedora", "\"28\"", false),
Entry("Item empty with and without \"", "/tmp/os-release.test", "", "\"\"", false),
)
@@ -142,7 +142,7 @@ var _ = Describe("Common functions test", func() {
Expect(Containerized()).To(Equal(expect))
},
Entry("Set container in env", "", true, false, true),
- Entry("Can not read from file", "/tmp/notexist", false, false, false),
+ Entry("Can not read from file", "/tmp/nonexistent", false, false, false),
Entry("Docker in cgroup file", "/tmp/cgroup.test", false, true, true),
Entry("Docker not in cgroup file", "/tmp/cgroup.test", false, true, false),
)
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 027e96427..f21584537 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -432,7 +432,7 @@ func IsKernelNewerThan(version string) (bool, error) {
}
-// IsCommandAvaible check if command exist
+// IsCommandAvailable check if command exist
func IsCommandAvailable(command string) bool {
check := exec.Command("bash", "-c", strings.Join([]string{"command -v", command}, " "))
err := check.Run()
diff --git a/vendor/github.com/Microsoft/go-winio/go.mod b/vendor/github.com/Microsoft/go-winio/go.mod
index 50b9d6e2e..a2eb6496c 100644
--- a/vendor/github.com/Microsoft/go-winio/go.mod
+++ b/vendor/github.com/Microsoft/go-winio/go.mod
@@ -3,7 +3,7 @@ module github.com/Microsoft/go-winio
go 1.12
require (
- github.com/pkg/errors v0.8.1
+ github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.4.1
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
)
diff --git a/vendor/github.com/Microsoft/go-winio/go.sum b/vendor/github.com/Microsoft/go-winio/go.sum
index 209aa8cf4..6da76a492 100644
--- a/vendor/github.com/Microsoft/go-winio/go.sum
+++ b/vendor/github.com/Microsoft/go-winio/go.sum
@@ -2,8 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
@@ -12,7 +12,5 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go
index ff96dff1c..96700a73d 100644
--- a/vendor/github.com/Microsoft/go-winio/pipe.go
+++ b/vendor/github.com/Microsoft/go-winio/pipe.go
@@ -429,10 +429,10 @@ type PipeConfig struct {
// when the pipe is in message mode.
MessageMode bool
- // InputBufferSize specifies the size the input buffer, in bytes.
+ // InputBufferSize specifies the size of the input buffer, in bytes.
InputBufferSize int32
- // OutputBufferSize specifies the size the input buffer, in bytes.
+ // OutputBufferSize specifies the size of the output buffer, in bytes.
OutputBufferSize int32
}
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go b/vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
new file mode 100644
index 000000000..2df31b660
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
@@ -0,0 +1,159 @@
+package security
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/pkg/errors"
+)
+
+type (
+ accessMask uint32
+ accessMode uint32
+ desiredAccess uint32
+ inheritMode uint32
+ objectType uint32
+ shareMode uint32
+ securityInformation uint32
+ trusteeForm uint32
+ trusteeType uint32
+
+ explicitAccess struct {
+ accessPermissions accessMask
+ accessMode accessMode
+ inheritance inheritMode
+ trustee trustee
+ }
+
+ trustee struct {
+ multipleTrustee *trustee
+ multipleTrusteeOperation int32
+ trusteeForm trusteeForm
+ trusteeType trusteeType
+ name uintptr
+ }
+)
+
+const (
+ accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
+
+ accessModeGrant accessMode = 1
+
+ desiredAccessReadControl desiredAccess = 0x20000
+ desiredAccessWriteDac desiredAccess = 0x40000
+
+ gvmga = "GrantVmGroupAccess:"
+
+ inheritModeNoInheritance inheritMode = 0x0
+ inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
+
+ objectTypeFileObject objectType = 0x1
+
+ securityInformationDACL securityInformation = 0x4
+
+ shareModeRead shareMode = 0x1
+ shareModeWrite shareMode = 0x2
+
+ sidVmGroup = "S-1-5-83-0"
+
+ trusteeFormIsSid trusteeForm = 0
+
+ trusteeTypeWellKnownGroup trusteeType = 5
+)
+
+// GrantVMGroupAccess sets the DACL for a specified file or directory to
+// include Grant ACE entries for the VM Group SID. This is a golang re-
+// implementation of the same function in vmcompute, just not exported in
+// RS5. Which kind of sucks. Sucks a lot :/
+func GrantVmGroupAccess(name string) error {
+ // Stat (to determine if `name` is a directory).
+ s, err := os.Stat(name)
+ if err != nil {
+ return errors.Wrapf(err, "%s os.Stat %s", gvmga, name)
+ }
+
+ // Get a handle to the file/directory. Must defer Close on success.
+ fd, err := createFile(name, s.IsDir())
+ if err != nil {
+ return err // Already wrapped
+ }
+ defer syscall.CloseHandle(fd)
+
+ // Get the current DACL and Security Descriptor. Must defer LocalFree on success.
+ ot := objectTypeFileObject
+ si := securityInformationDACL
+ sd := uintptr(0)
+ origDACL := uintptr(0)
+ if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
+ return errors.Wrapf(err, "%s GetSecurityInfo %s", gvmga, name)
+ }
+ defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
+
+ // Generate a new DACL which is the current DACL with the required ACEs added.
+ // Must defer LocalFree on success.
+ newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), origDACL)
+ if err != nil {
+ return err // Already wrapped
+ }
+ defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
+
+ // And finally use SetSecurityInfo to apply the updated DACL.
+ if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
+ return errors.Wrapf(err, "%s SetSecurityInfo %s", gvmga, name)
+ }
+
+ return nil
+}
+
+// createFile is a helper function to call [Nt]CreateFile to get a handle to
+// the file or directory.
+func createFile(name string, isDir bool) (syscall.Handle, error) {
+ namep := syscall.StringToUTF16(name)
+ da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
+ sm := uint32(shareModeRead | shareModeWrite)
+ fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
+ if isDir {
+ fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
+ }
+ fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
+ if err != nil {
+ return 0, errors.Wrapf(err, "%s syscall.CreateFile %s", gvmga, name)
+ }
+ return fd, nil
+}
+
+// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
+// The caller is responsible for LocalFree of the returned DACL on success.
+func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
+ // Generate pointers to the SIDs based on the string SIDs
+ sid, err := syscall.StringToSid(sidVmGroup)
+ if err != nil {
+ return 0, errors.Wrapf(err, "%s syscall.StringToSid %s %s", gvmga, name, sidVmGroup)
+ }
+
+ inheritance := inheritModeNoInheritance
+ if isDir {
+ inheritance = inheritModeSubContainersAndObjectsInherit
+ }
+
+ eaArray := []explicitAccess{
+ explicitAccess{
+ accessPermissions: accessMaskDesiredPermission,
+ accessMode: accessModeGrant,
+ inheritance: inheritance,
+ trustee: trustee{
+ trusteeForm: trusteeFormIsSid,
+ trusteeType: trusteeTypeWellKnownGroup,
+ name: uintptr(unsafe.Pointer(sid)),
+ },
+ },
+ }
+
+ modifiedDACL := uintptr(0)
+ if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
+ return 0, errors.Wrapf(err, "%s SetEntriesInAcl %s", gvmga, name)
+ }
+
+ return modifiedDACL, nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
new file mode 100644
index 000000000..c40c2739b
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
@@ -0,0 +1,7 @@
+package security
+
+//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
+
+//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
+//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) [failretval!=0] = advapi32.SetSecurityInfo
+//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) [failretval!=0] = advapi32.SetEntriesInAclW
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
new file mode 100644
index 000000000..0f0c0deff
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
@@ -0,0 +1,81 @@
+// Code generated mksyscall_windows.exe DO NOT EDIT
+
+package security
+
+import (
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
+var (
+ modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
+
+ procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
+ procSetSecurityInfo = modadvapi32.NewProc("SetSecurityInfo")
+ procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
+)
+
+func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/Microsoft/go-winio/vhd/vhd.go b/vendor/github.com/Microsoft/go-winio/vhd/vhd.go
index 229ac2556..91083a388 100644
--- a/vendor/github.com/Microsoft/go-winio/vhd/vhd.go
+++ b/vendor/github.com/Microsoft/go-winio/vhd/vhd.go
@@ -2,150 +2,323 @@
package vhd
-import "syscall"
+import (
+ "fmt"
+ "syscall"
+
+ "github.com/Microsoft/go-winio/pkg/guid"
+ "github.com/pkg/errors"
+ "golang.org/x/sys/windows"
+)
//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go
-//sys createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.CreateVirtualDisk
-//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.OpenVirtualDisk
-//sys detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = VirtDisk.DetachVirtualDisk
-
-type virtualStorageType struct {
- DeviceID uint32
- VendorID [16]byte
-}
+//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk
+//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
+//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
+//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk
+//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath
type (
- createVirtualDiskFlag uint32
- VirtualDiskAccessMask uint32
+ CreateVirtualDiskFlag uint32
VirtualDiskFlag uint32
+ AttachVirtualDiskFlag uint32
+ DetachVirtualDiskFlag uint32
+ VirtualDiskAccessMask uint32
)
-const (
- // Flags for creating a VHD (not exported)
- createVirtualDiskFlagNone createVirtualDiskFlag = 0
- createVirtualDiskFlagFullPhysicalAllocation createVirtualDiskFlag = 1
- createVirtualDiskFlagPreventWritesToSourceDisk createVirtualDiskFlag = 2
- createVirtualDiskFlagDoNotCopyMetadataFromParent createVirtualDiskFlag = 4
-
- // Access Mask for opening a VHD
- VirtualDiskAccessNone VirtualDiskAccessMask = 0
- VirtualDiskAccessAttachRO VirtualDiskAccessMask = 65536
- VirtualDiskAccessAttachRW VirtualDiskAccessMask = 131072
- VirtualDiskAccessDetach VirtualDiskAccessMask = 262144
- VirtualDiskAccessGetInfo VirtualDiskAccessMask = 524288
- VirtualDiskAccessCreate VirtualDiskAccessMask = 1048576
- VirtualDiskAccessMetaOps VirtualDiskAccessMask = 2097152
- VirtualDiskAccessRead VirtualDiskAccessMask = 851968
- VirtualDiskAccessAll VirtualDiskAccessMask = 4128768
- VirtualDiskAccessWritable VirtualDiskAccessMask = 3276800
-
- // Flags for opening a VHD
- OpenVirtualDiskFlagNone VirtualDiskFlag = 0
- OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x1
- OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x2
- OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x4
- OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x8
- OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x10
- OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x20
- OpenVirtualDiskFlagVhdSetFileOnly VirtualDiskFlag = 0x40
- OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x80
- OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x100
-)
+type VirtualStorageType struct {
+ DeviceID uint32
+ VendorID guid.GUID
+}
-type createVersion2 struct {
- UniqueID [16]byte // GUID
+type CreateVersion2 struct {
+ UniqueID guid.GUID
MaximumSize uint64
BlockSizeInBytes uint32
SectorSizeInBytes uint32
+ PhysicalSectorSizeInByte uint32
ParentPath *uint16 // string
SourcePath *uint16 // string
OpenFlags uint32
- ParentVirtualStorageType virtualStorageType
- SourceVirtualStorageType virtualStorageType
- ResiliencyGUID [16]byte // GUID
+ ParentVirtualStorageType VirtualStorageType
+ SourceVirtualStorageType VirtualStorageType
+ ResiliencyGUID guid.GUID
}
-type createVirtualDiskParameters struct {
+type CreateVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
- Version2 createVersion2
+ Version2 CreateVersion2
}
-type openVersion2 struct {
- GetInfoOnly int32 // bool but 4-byte aligned
- ReadOnly int32 // bool but 4-byte aligned
- ResiliencyGUID [16]byte // GUID
+type OpenVersion2 struct {
+ GetInfoOnly bool
+ ReadOnly bool
+ ResiliencyGUID guid.GUID
}
-type openVirtualDiskParameters struct {
+type OpenVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
- Version2 openVersion2
+ Version2 OpenVersion2
}
-// CreateVhdx will create a simple vhdx file at the given path using default values.
-func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
- var (
- defaultType virtualStorageType
- handle syscall.Handle
- )
+type AttachVersion2 struct {
+ RestrictedOffset uint64
+ RestrictedLength uint64
+}
+
+type AttachVirtualDiskParameters struct {
+ Version uint32 // Must always be set to 2
+ Version2 AttachVersion2
+}
+
+const (
+ VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
+
+ // Access Mask for opening a VHD
+ VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
+ VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
+ VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
+ VirtualDiskAccessDetach VirtualDiskAccessMask = 0x00040000
+ VirtualDiskAccessGetInfo VirtualDiskAccessMask = 0x00080000
+ VirtualDiskAccessCreate VirtualDiskAccessMask = 0x00100000
+ VirtualDiskAccessMetaOps VirtualDiskAccessMask = 0x00200000
+ VirtualDiskAccessRead VirtualDiskAccessMask = 0x000d0000
+ VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
+ VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
- parameters := createVirtualDiskParameters{
+ // Flags for creating a VHD
+ CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
+ CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
+ CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
+ CreateVirtualDiskFlagDoNotCopyMetadataFromParent CreateVirtualDiskFlag = 0x4
+ CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
+ CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
+ CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
+ CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40
+ CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
+ CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100
+ CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
+
+ // Flags for opening a VHD
+ OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
+ OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
+ OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
+ OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x00000004
+ OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x00000008
+ OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x00000010
+ OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x00000020
+ OpenVirtualDiskFlagVhdsetFileOnly VirtualDiskFlag = 0x00000040
+ OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
+ OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
+ OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
+
+ // Flags for attaching a VHD
+ AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
+ AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
+ AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
+ AttachVirtualDiskFlagPermanentLifetime AttachVirtualDiskFlag = 0x00000004
+ AttachVirtualDiskFlagNoLocalHost AttachVirtualDiskFlag = 0x00000008
+ AttachVirtualDiskFlagNoSecurityDescriptor AttachVirtualDiskFlag = 0x00000010
+ AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
+ AttachVirtualDiskFlagNonPnp AttachVirtualDiskFlag = 0x00000040
+ AttachVirtualDiskFlagRestrictedRange AttachVirtualDiskFlag = 0x00000080
+ AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
+ AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
+
+ // Flags for detaching a VHD
+ DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
+)
+
+// CreateVhdx is a helper function to create a simple vhdx file at the given path using
+// default values.
+func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
+ params := CreateVirtualDiskParameters{
Version: 2,
- Version2: createVersion2{
+ Version2: CreateVersion2{
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
},
}
- if err := createVirtualDisk(
- &defaultType,
- path,
- uint32(VirtualDiskAccessNone),
- nil,
- uint32(createVirtualDiskFlagNone),
- 0,
- &parameters,
- nil,
- &handle); err != nil {
+ handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, &params)
+ if err != nil {
return err
}
if err := syscall.CloseHandle(handle); err != nil {
return err
}
+ return nil
+}
+// DetachVirtualDisk detaches a virtual hard disk by handle.
+func DetachVirtualDisk(handle syscall.Handle) (err error) {
+ if err := detachVirtualDisk(handle, 0, 0); err != nil {
+ return errors.Wrap(err, "failed to detach virtual disk")
+ }
return nil
}
-// DetachVhd detaches a mounted container layer vhd found at `path`.
+// DetachVhd detaches a vhd found at `path`.
func DetachVhd(path string) error {
handle, err := OpenVirtualDisk(
path,
VirtualDiskAccessNone,
- OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator)
+ OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
+ )
+ if err != nil {
+ return err
+ }
+ defer syscall.CloseHandle(handle)
+ return DetachVirtualDisk(handle)
+}
+
+// AttachVirtualDisk attaches a virtual hard disk for use.
+func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
+ if parameters.Version != 2 {
+ return fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
+ }
+ if err := attachVirtualDisk(
+ handle,
+ nil,
+ uint32(attachVirtualDiskFlag),
+ 0,
+ parameters,
+ nil,
+ ); err != nil {
+ return errors.Wrap(err, "failed to attach virtual disk")
+ }
+ return nil
+}
+// AttachVhd attaches a virtual hard disk at `path` for use.
+func AttachVhd(path string) (err error) {
+ handle, err := OpenVirtualDisk(
+ path,
+ VirtualDiskAccessNone,
+ OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
+ )
if err != nil {
return err
}
+
defer syscall.CloseHandle(handle)
- return detachVirtualDisk(handle, 0, 0)
+ params := AttachVirtualDiskParameters{Version: 2}
+ if err := AttachVirtualDisk(
+ handle,
+ AttachVirtualDiskFlagNone,
+ &params,
+ ); err != nil {
+ return errors.Wrap(err, "failed to attach virtual disk")
+ }
+ return nil
}
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
-func OpenVirtualDisk(path string, accessMask VirtualDiskAccessMask, flag VirtualDiskFlag) (syscall.Handle, error) {
+func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
+ parameters := OpenVirtualDiskParameters{Version: 2}
+ handle, err := OpenVirtualDiskWithParameters(
+ vhdPath,
+ virtualDiskAccessMask,
+ openVirtualDiskFlags,
+ &parameters,
+ )
+ if err != nil {
+ return 0, err
+ }
+ return handle, nil
+}
+
+// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
+func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
var (
- defaultType virtualStorageType
handle syscall.Handle
+ defaultType VirtualStorageType
)
- parameters := openVirtualDiskParameters{Version: 2}
+ if parameters.Version != 2 {
+ return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
+ }
if err := openVirtualDisk(
&defaultType,
+ vhdPath,
+ uint32(virtualDiskAccessMask),
+ uint32(openVirtualDiskFlags),
+ parameters,
+ &handle,
+ ); err != nil {
+ return 0, errors.Wrap(err, "failed to open virtual disk")
+ }
+ return handle, nil
+}
+
+// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
+func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
+ var (
+ handle syscall.Handle
+ defaultType VirtualStorageType
+ )
+ if parameters.Version != 2 {
+ return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
+ }
+
+ if err := createVirtualDisk(
+ &defaultType,
path,
- uint32(accessMask),
- uint32(flag),
- &parameters,
- &handle); err != nil {
- return 0, err
+ uint32(virtualDiskAccessMask),
+ nil,
+ uint32(createVirtualDiskFlags),
+ 0,
+ parameters,
+ nil,
+ &handle,
+ ); err != nil {
+ return handle, errors.Wrap(err, "failed to create virtual disk")
}
return handle, nil
}
+
+// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
+// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
+// that represents the particular enumeration of the physical disk on the caller's system.
+func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
+ var (
+ diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
+ diskPhysicalPathBuf [256]uint16
+ )
+ if err := getVirtualDiskPhysicalPath(
+ handle,
+ &diskPathSizeInBytes,
+ &diskPhysicalPathBuf[0],
+ ); err != nil {
+ return "", errors.Wrap(err, "failed to get disk physical path")
+ }
+ return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
+}
+
+// CreateDiffVhd is a helper function to create a differencing virtual disk.
+func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
+ // Setting `ParentPath` is how to signal to create a differencing disk.
+ createParams := &CreateVirtualDiskParameters{
+ Version: 2,
+ Version2: CreateVersion2{
+ ParentPath: windows.StringToUTF16Ptr(baseVhdPath),
+ BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
+ OpenFlags: uint32(OpenVirtualDiskFlagCachedIO),
+ },
+ }
+
+ vhdHandle, err := CreateVirtualDisk(
+ diffVhdPath,
+ VirtualDiskAccessNone,
+ CreateVirtualDiskFlagNone,
+ createParams,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create differencing vhd: %s", err)
+ }
+ if err := syscall.CloseHandle(vhdHandle); err != nil {
+ return fmt.Errorf("failed to close differencing vhd handle: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go b/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go
index 00599ea49..54c94db77 100644
--- a/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go
+++ b/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go
@@ -37,24 +37,26 @@ func errnoErr(e syscall.Errno) error {
}
var (
- modVirtDisk = windows.NewLazySystemDLL("VirtDisk.dll")
+ modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
- procCreateVirtualDisk = modVirtDisk.NewProc("CreateVirtualDisk")
- procOpenVirtualDisk = modVirtDisk.NewProc("OpenVirtualDisk")
- procDetachVirtualDisk = modVirtDisk.NewProc("DetachVirtualDisk")
+ procCreateVirtualDisk = modvirtdisk.NewProc("CreateVirtualDisk")
+ procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk")
+ procAttachVirtualDisk = modvirtdisk.NewProc("AttachVirtualDisk")
+ procDetachVirtualDisk = modvirtdisk.NewProc("DetachVirtualDisk")
+ procGetVirtualDiskPhysicalPath = modvirtdisk.NewProc("GetVirtualDiskPhysicalPath")
)
-func createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
+func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(path)
if err != nil {
return
}
- return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, flags, providerSpecificFlags, parameters, o, handle)
+ return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
}
-func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
- r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(flags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(handle)))
+func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
+ r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
@@ -65,17 +67,17 @@ func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, vi
return
}
-func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
+func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(path)
if err != nil {
return
}
- return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle)
+ return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
}
-func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
- r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
+func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
+ r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
@@ -86,8 +88,32 @@ func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virt
return
}
-func detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) {
- r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(flags), uintptr(providerSpecificFlags))
+func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
+ if r1 != 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
+ if r1 != 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
diff --git a/vendor/github.com/Microsoft/hcsshim/.gitattributes b/vendor/github.com/Microsoft/hcsshim/.gitattributes
new file mode 100644
index 000000000..94f480de9
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf \ No newline at end of file
diff --git a/vendor/github.com/Microsoft/hcsshim/CODEOWNERS b/vendor/github.com/Microsoft/hcsshim/CODEOWNERS
index 1a59c8021..87f49df31 100644
--- a/vendor/github.com/Microsoft/hcsshim/CODEOWNERS
+++ b/vendor/github.com/Microsoft/hcsshim/CODEOWNERS
@@ -1,3 +1,3 @@
-* @microsoft/containerplat
-
+* @microsoft/containerplat
+
/hcn/* @nagiesek \ No newline at end of file
diff --git a/vendor/github.com/Microsoft/hcsshim/appveyor.yml b/vendor/github.com/Microsoft/hcsshim/appveyor.yml
index 6617fade0..bd3f18f07 100644
--- a/vendor/github.com/Microsoft/hcsshim/appveyor.yml
+++ b/vendor/github.com/Microsoft/hcsshim/appveyor.yml
@@ -18,6 +18,7 @@ build_script:
- go build ./cmd/runhcs
- go build ./cmd/tar2ext4
- go build ./cmd/wclayer
+ - go build ./cmd/device-util
- go build ./internal/tools/grantvmgroupaccess
- go build ./internal/tools/uvmboot
- go build ./internal/tools/zapdir
@@ -33,6 +34,7 @@ artifacts:
- path: 'containerd-shim-runhcs-v1.exe'
- path: 'runhcs.exe'
- path: 'tar2ext4.exe'
+ - path: 'device-util.exe'
- path: 'wclayer.exe'
- path: 'grantvmgroupaccess.exe'
- path: 'uvmboot.exe'
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/attach.go b/vendor/github.com/Microsoft/hcsshim/computestorage/attach.go
new file mode 100644
index 000000000..56901d926
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/attach.go
@@ -0,0 +1,38 @@
+package computestorage
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// AttachLayerStorageFilter sets up the layer storage filter on a writable
+// container layer.
+//
+// `layerPath` is a path to a directory the writable layer is mounted. If the
+// path does not end in a `\` the platform will append it automatically.
+//
+// `layerData` is the parent read-only layer data.
+func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
+ title := "hcsshim.AttachLayerStorageFilter"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ )
+
+ bytes, err := json.Marshal(layerData)
+ if err != nil {
+ return err
+ }
+
+ err = hcsAttachLayerStorageFilter(layerPath, string(bytes))
+ if err != nil {
+ return fmt.Errorf("failed to attach layer storage filter: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go b/vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go
new file mode 100644
index 000000000..ecf3b550d
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go
@@ -0,0 +1,26 @@
+package computestorage
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// DestroyLayer deletes a container layer.
+//
+// `layerPath` is a path to a directory containing the layer to export.
+func DestroyLayer(ctx context.Context, layerPath string) (err error) {
+ title := "hcsshim.DestroyLayer"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
+
+ err = hcsDestroyLayer(layerPath)
+ if err != nil {
+ return fmt.Errorf("failed to destroy layer: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/detach.go b/vendor/github.com/Microsoft/hcsshim/computestorage/detach.go
new file mode 100644
index 000000000..2a4df4213
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/detach.go
@@ -0,0 +1,26 @@
+package computestorage
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// DetachLayerStorageFilter detaches the layer storage filter on a writable container layer.
+//
+// `layerPath` is a path to a directory containing the layer to export.
+func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
+ title := "hcsshim.DetachLayerStorageFilter"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
+
+ err = hcsDetachLayerStorageFilter(layerPath)
+ if err != nil {
+ return fmt.Errorf("failed to detach layer storage filter: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/export.go b/vendor/github.com/Microsoft/hcsshim/computestorage/export.go
new file mode 100644
index 000000000..b1721ef25
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/export.go
@@ -0,0 +1,46 @@
+package computestorage
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// ExportLayer exports a container layer.
+//
+// `layerPath` is a path to a directory containing the layer to export.
+//
+// `exportFolderPath` is a pre-existing folder to export the layer to.
+//
+// `layerData` is the parent layer data.
+//
+// `options` are the export options applied to the exported layer.
+func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
+ title := "hcsshim.ExportLayer"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ trace.StringAttribute("exportFolderPath", exportFolderPath),
+ )
+
+ ldbytes, err := json.Marshal(layerData)
+ if err != nil {
+ return err
+ }
+
+ obytes, err := json.Marshal(options)
+ if err != nil {
+ return err
+ }
+
+ err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes))
+ if err != nil {
+ return fmt.Errorf("failed to export layer: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/format.go b/vendor/github.com/Microsoft/hcsshim/computestorage/format.go
new file mode 100644
index 000000000..2952c8a66
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/format.go
@@ -0,0 +1,26 @@
+package computestorage
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+ "golang.org/x/sys/windows"
+)
+
+// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
+//
+// If the VHD is not mounted it will be temporarily mounted.
+func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
+ title := "hcsshim.FormatWritableLayerVhd"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+
+ err = hcsFormatWritableLayerVhd(vhdHandle)
+ if err != nil {
+ return fmt.Errorf("failed to format writable layer vhd: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go b/vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go
new file mode 100644
index 000000000..d31efd660
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go
@@ -0,0 +1,197 @@
+package computestorage
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "syscall"
+
+ "github.com/Microsoft/go-winio/pkg/security"
+ "github.com/Microsoft/go-winio/vhd"
+ "github.com/pkg/errors"
+ "golang.org/x/sys/windows"
+)
+
+const defaultVHDXBlockSizeInMB = 1
+
+// SetupContainerBaseLayer is a helper to setup a containers scratch. It
+// will create and format the vhdx's inside and the size is configurable with the sizeInGB
+// parameter.
+//
+// `layerPath` is the path to the base container layer on disk.
+//
+// `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
+//
+// `diffVhdPath` is the path where the differencing disk for the base layer should be created.
+//
+// `sizeInGB` is the size in gigabytes to make the base vhdx.
+func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
+ var (
+ hivesPath = filepath.Join(layerPath, "Hives")
+ layoutPath = filepath.Join(layerPath, "Layout")
+ )
+
+ // We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
+ // already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
+ // differencing disks if they exist in case we're asking for a different size.
+ if _, err := os.Stat(hivesPath); err == nil {
+ if err := os.RemoveAll(hivesPath); err != nil {
+ return errors.Wrap(err, "failed to remove prexisting hives directory")
+ }
+ }
+ if _, err := os.Stat(layoutPath); err == nil {
+ if err := os.RemoveAll(layoutPath); err != nil {
+ return errors.Wrap(err, "failed to remove prexisting layout file")
+ }
+ }
+
+ if _, err := os.Stat(baseVhdPath); err == nil {
+ if err := os.RemoveAll(baseVhdPath); err != nil {
+ return errors.Wrap(err, "failed to remove base vhdx path")
+ }
+ }
+ if _, err := os.Stat(diffVhdPath); err == nil {
+ if err := os.RemoveAll(diffVhdPath); err != nil {
+ return errors.Wrap(err, "failed to remove differencing vhdx")
+ }
+ }
+
+ createParams := &vhd.CreateVirtualDiskParameters{
+ Version: 2,
+ Version2: vhd.CreateVersion2{
+ MaximumSize: sizeInGB * 1024 * 1024 * 1024,
+ BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
+ },
+ }
+ handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
+ if err != nil {
+ return errors.Wrap(err, "failed to create vhdx")
+ }
+
+ defer func() {
+ if err != nil {
+ syscall.CloseHandle(handle)
+ os.RemoveAll(baseVhdPath)
+ if os.Stat(diffVhdPath); err == nil {
+ os.RemoveAll(diffVhdPath)
+ }
+ }
+ }()
+
+ if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
+ return err
+ }
+ // Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
+ if err = syscall.CloseHandle(handle); err != nil {
+ return errors.Wrap(err, "failed to close vhdx handle")
+ }
+
+ options := OsLayerOptions{
+ Type: OsLayerTypeContainer,
+ }
+
+ // SetupBaseOSLayer expects an empty vhd handle for a container layer and will
+ // error out otherwise.
+ if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
+ return err
+ }
+ // Create the differencing disk that will be what's copied for the final rw layer
+ // for a container.
+ if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
+ return errors.Wrap(err, "failed to create differencing disk")
+ }
+
+ if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
+ return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
+ }
+ if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
+ return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
+ }
+ return nil
+}
+
+// SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
+// the vhdx inside and the size is configurable by the sizeInGB parameter.
+//
+// `uvmPath` is the path to the UtilityVM filesystem.
+//
+// `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
+//
+// `diffVhdPath` is the path where the differencing disk for the UVM should be created.
+//
+// `sizeInGB` specifies the size in gigabytes to make the base vhdx.
+func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
+ // Remove the base and differencing disks if they exist in case we're asking for a different size.
+ if _, err := os.Stat(baseVhdPath); err == nil {
+ if err := os.RemoveAll(baseVhdPath); err != nil {
+ return errors.Wrap(err, "failed to remove base vhdx")
+ }
+ }
+ if _, err := os.Stat(diffVhdPath); err == nil {
+ if err := os.RemoveAll(diffVhdPath); err != nil {
+ return errors.Wrap(err, "failed to remove differencing vhdx")
+ }
+ }
+
+ // Just create the vhdx for utilityVM layer, no need to format it.
+ createParams := &vhd.CreateVirtualDiskParameters{
+ Version: 2,
+ Version2: vhd.CreateVersion2{
+ MaximumSize: sizeInGB * 1024 * 1024 * 1024,
+ BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
+ },
+ }
+ handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
+ if err != nil {
+ return errors.Wrap(err, "failed to create vhdx")
+ }
+
+ defer func() {
+ if err != nil {
+ syscall.CloseHandle(handle)
+ os.RemoveAll(baseVhdPath)
+ if os.Stat(diffVhdPath); err == nil {
+ os.RemoveAll(diffVhdPath)
+ }
+ }
+ }()
+
+ // If it is a UtilityVM layer then the base vhdx must be attached when calling
+ // `SetupBaseOSLayer`
+ attachParams := &vhd.AttachVirtualDiskParameters{
+ Version: 2,
+ }
+ if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
+ return errors.Wrapf(err, "failed to attach virtual disk")
+ }
+
+ options := OsLayerOptions{
+ Type: OsLayerTypeVM,
+ }
+ if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
+ return err
+ }
+
+ // Detach and close the handle after setting up the layer as we don't need the handle
+ // for anything else and we no longer need to be attached either.
+ if err = vhd.DetachVirtualDisk(handle); err != nil {
+ return errors.Wrap(err, "failed to detach vhdx")
+ }
+ if err = syscall.CloseHandle(handle); err != nil {
+ return errors.Wrap(err, "failed to close vhdx handle")
+ }
+
+ // Create the differencing disk that will be what's copied for the final rw layer
+ // for a container.
+ if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
+ return errors.Wrap(err, "failed to create differencing disk")
+ }
+
+ if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
+ return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
+ }
+ if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
+ return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/import.go b/vendor/github.com/Microsoft/hcsshim/computestorage/import.go
new file mode 100644
index 000000000..06e329794
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/import.go
@@ -0,0 +1,41 @@
+package computestorage
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// ImportLayer imports a container layer.
+//
+// `layerPath` is a path to a directory to import the layer to. If the directory
+// does not exist it will be automatically created.
+//
+// `sourceFolderpath` is a pre-existing folder that contains the layer to
+// import.
+//
+// `layerData` is the parent layer data.
+func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
+ title := "hcsshim.ImportLayer"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ trace.StringAttribute("sourceFolderPath", sourceFolderPath),
+ )
+
+ bytes, err := json.Marshal(layerData)
+ if err != nil {
+ return err
+ }
+
+ err = hcsImportLayer(layerPath, sourceFolderPath, string(bytes))
+ if err != nil {
+ return fmt.Errorf("failed to import layer: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go b/vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go
new file mode 100644
index 000000000..2e4810c45
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go
@@ -0,0 +1,38 @@
+package computestorage
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+)
+
+// InitializeWritableLayer initializes a writable layer for a container.
+//
+// `layerPath` is a path to a directory the layer is mounted. If the
+// path does not end in a `\` the platform will append it automatically.
+//
+// `layerData` is the parent read-only layer data.
+func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
+ title := "hcsshim.InitializeWritableLayer"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ )
+
+ bytes, err := json.Marshal(layerData)
+ if err != nil {
+ return err
+ }
+
+ // Options are not used in the platform as of RS5
+ err = hcsInitializeWritableLayer(layerPath, string(bytes), "")
+ if err != nil {
+ return fmt.Errorf("failed to intitialize container layer: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/mount.go b/vendor/github.com/Microsoft/hcsshim/computestorage/mount.go
new file mode 100644
index 000000000..40652b99e
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/mount.go
@@ -0,0 +1,27 @@
+package computestorage
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/interop"
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "go.opencensus.io/trace"
+ "golang.org/x/sys/windows"
+)
+
+// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
+func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
+ title := "hcsshim.GetLayerVhdMountPath"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+
+ var mountPath *uint16
+ err = hcsGetLayerVhdMountPath(vhdHandle, &mountPath)
+ if err != nil {
+ return "", fmt.Errorf("failed to get vhd mount path: %s", err)
+ }
+ path = interop.ConvertAndFreeCoTaskMemString(mountPath)
+ return path, nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/setup.go b/vendor/github.com/Microsoft/hcsshim/computestorage/setup.go
new file mode 100644
index 000000000..13ce0cd60
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/setup.go
@@ -0,0 +1,75 @@
+package computestorage
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ "github.com/Microsoft/hcsshim/internal/oc"
+ "github.com/Microsoft/hcsshim/osversion"
+ "go.opencensus.io/trace"
+ "golang.org/x/sys/windows"
+)
+
+// SetupBaseOSLayer sets up a layer that contains a base OS for a container.
+//
+// `layerPath` is a path to a directory containing the layer.
+//
+// `vhdHandle` is an empty file handle of `options.Type == OsLayerTypeContainer`
+// or else it is a file handle to the 'SystemTemplateBase.vhdx' if `options.Type
+// == OsLayerTypeVm`.
+//
+// `options` are the options applied while processing the layer.
+func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
+ title := "hcsshim.SetupBaseOSLayer"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ )
+
+ bytes, err := json.Marshal(options)
+ if err != nil {
+ return err
+ }
+
+ err = hcsSetupBaseOSLayer(layerPath, vhdHandle, string(bytes))
+ if err != nil {
+ return fmt.Errorf("failed to setup base OS layer: %s", err)
+ }
+ return nil
+}
+
+// SetupBaseOSVolume sets up a volume that contains a base OS for a container.
+//
+// `layerPath` is a path to a directory containing the layer.
+//
+// `volumePath` is the path to the volume to be used for setup.
+//
+// `options` are the options applied while processing the layer.
+func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
+ if osversion.Get().Build < 19645 {
+ return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
+ }
+ title := "hcsshim.SetupBaseOSVolume"
+ ctx, span := trace.StartSpan(ctx, title)
+ defer span.End()
+ defer func() { oc.SetSpanStatus(span, err) }()
+ span.AddAttributes(
+ trace.StringAttribute("layerPath", layerPath),
+ trace.StringAttribute("volumePath", volumePath),
+ )
+
+ bytes, err := json.Marshal(options)
+ if err != nil {
+ return err
+ }
+
+ err = hcsSetupBaseOSVolume(layerPath, volumePath, string(bytes))
+ if err != nil {
+ return fmt.Errorf("failed to setup base OS layer: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/storage.go b/vendor/github.com/Microsoft/hcsshim/computestorage/storage.go
new file mode 100644
index 000000000..9cd283d4b
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/storage.go
@@ -0,0 +1,50 @@
+// Package computestorage is a wrapper around the HCS storage APIs. These are new storage APIs introduced
+// separate from the original graphdriver calls intended to give more freedom around creating
+// and managing container layers and scratch spaces.
+package computestorage
+
+import (
+ hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
+)
+
+//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go
+
+//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
+//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
+//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
+//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
+//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
+//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
+//sys hcsDetachLayerStorageFilter(layerPath string) (hr error) = computestorage.HcsDetachLayerStorageFilter?
+//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
+//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
+//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
+
+// LayerData is the data used to describe parent layer information.
+type LayerData struct {
+ SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"`
+ Layers []hcsschema.Layer `json:"Layers,omitempty"`
+}
+
+// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
+type ExportLayerOptions struct {
+ IsWritableLayer bool `json:"IsWritableLayer,omitempty"`
+}
+
+// OsLayerType is the type of layer being operated on.
+type OsLayerType string
+
+const (
+ // OsLayerTypeContainer is a container layer.
+ OsLayerTypeContainer OsLayerType = "Container"
+ // OsLayerTypeVM is a virtual machine layer.
+ OsLayerTypeVM OsLayerType = "Vm"
+)
+
+// OsLayerOptions are the set of options that are used with the `SetupBaseOSLayer` and
+// `SetupBaseOSVolume` calls.
+type OsLayerOptions struct {
+ Type OsLayerType `json:"Type,omitempty"`
+ DisableCiCacheOptimization bool `json:"DisableCiCacheOptimization,omitempty"`
+ SkipUpdateBcdForBoot bool `json:"SkipUpdateBcdForBoot,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go
new file mode 100644
index 000000000..4f9518067
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go
@@ -0,0 +1,319 @@
+// Code generated mksyscall_windows.exe DO NOT EDIT
+
+package computestorage
+
+import (
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
+var (
+ modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
+
+ procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
+ procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
+ procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
+ procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
+ procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
+ procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
+ procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
+ procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
+ procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
+ procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
+)
+
+func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
+ if hr != nil {
+ return
+ }
+ var _p2 *uint16
+ _p2, hr = syscall.UTF16PtrFromString(layerData)
+ if hr != nil {
+ return
+ }
+ return _hcsImportLayer(_p0, _p1, _p2)
+}
+
+func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
+ if hr = procHcsImportLayer.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(exportFolderPath)
+ if hr != nil {
+ return
+ }
+ var _p2 *uint16
+ _p2, hr = syscall.UTF16PtrFromString(layerData)
+ if hr != nil {
+ return
+ }
+ var _p3 *uint16
+ _p3, hr = syscall.UTF16PtrFromString(options)
+ if hr != nil {
+ return
+ }
+ return _hcsExportLayer(_p0, _p1, _p2, _p3)
+}
+
+func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
+ if hr = procHcsExportLayer.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsDestroyLayer(layerPath string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ return _hcsDestroyLayer(_p0)
+}
+
+func _hcsDestroyLayer(layerPath *uint16) (hr error) {
+ if hr = procHcsDestoryLayer.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(options)
+ if hr != nil {
+ return
+ }
+ return _hcsSetupBaseOSLayer(_p0, handle, _p1)
+}
+
+func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
+ if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(writableLayerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(layerData)
+ if hr != nil {
+ return
+ }
+ var _p2 *uint16
+ _p2, hr = syscall.UTF16PtrFromString(options)
+ if hr != nil {
+ return
+ }
+ return _hcsInitializeWritableLayer(_p0, _p1, _p2)
+}
+
+func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
+ if hr = procHcsInitializeWritableLayer.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(layerData)
+ if hr != nil {
+ return
+ }
+ return _hcsAttachLayerStorageFilter(_p0, _p1)
+}
+
+func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
+ if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ return _hcsDetachLayerStorageFilter(_p0)
+}
+
+func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
+ if hr = procHcsDetachLayerStorageFilter.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
+ if hr = procHcsFormatWritableLayerVhd.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
+ if hr = procHcsGetLayerVhdMountPath.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(layerPath)
+ if hr != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, hr = syscall.UTF16PtrFromString(volumePath)
+ if hr != nil {
+ return
+ }
+ var _p2 *uint16
+ _p2, hr = syscall.UTF16PtrFromString(options)
+ if hr != nil {
+ return
+ }
+ return _hcsSetupBaseOSVolume(_p0, _p1, _p2)
+}
+
+func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
+ if hr = procHcsSetupBaseOSVolume.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/go.mod b/vendor/github.com/Microsoft/hcsshim/go.mod
index 5255b93f1..a2faeb52b 100644
--- a/vendor/github.com/Microsoft/hcsshim/go.mod
+++ b/vendor/github.com/Microsoft/hcsshim/go.mod
@@ -3,8 +3,8 @@ module github.com/Microsoft/hcsshim
go 1.13
require (
- github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5
- github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f
+ github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331
+ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1
github.com/containerd/containerd v1.3.2
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
@@ -17,16 +17,16 @@ require (
github.com/kr/pretty v0.1.0 // indirect
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2 // indirect
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f // indirect
- github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700
- github.com/pkg/errors v0.8.1
+ github.com/opencontainers/runtime-spec v1.0.2
+ github.com/pkg/errors v0.9.1
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/stretchr/testify v1.4.0 // indirect
- github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5
+ github.com/urfave/cli v1.22.2
go.opencensus.io v0.22.0
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
golang.org/x/sync v0.0.0-20190423024810-112230192c58
- golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
+ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 // indirect
google.golang.org/grpc v1.23.1
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
diff --git a/vendor/github.com/Microsoft/hcsshim/go.sum b/vendor/github.com/Microsoft/hcsshim/go.sum
index 8ab4318ed..e71f8979a 100644
--- a/vendor/github.com/Microsoft/hcsshim/go.sum
+++ b/vendor/github.com/Microsoft/hcsshim/go.sum
@@ -1,11 +1,14 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo=
+github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331 h1:3YnB7Hpmh1lPecPE8doMOtYCrMdrpedZOvxfuNES/Vk=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA=
@@ -20,17 +23,16 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de h1:dlfGmNcE3jDAec
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd h1:JNn81o/xG+8NEo3bC/vx9pbi/g2WI8mtP2/nXzu297Y=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
@@ -47,11 +49,12 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -61,14 +64,20 @@ github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2 h1:QhPf3A
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f h1:a969LJ4IQFwRHYqonHtUDMSh9i54WcKggeEkQ3fZMl4=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7 h1:hhvfGDVThBnd4kYisSFmYuHYeUhglxcwag7FhVPH9zM=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@@ -79,8 +88,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -109,14 +118,17 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479 h1:LhLiKguPgZL+Tglay4GhVtfF0kb8cvOJ0dHTCBO8YNI=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/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/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/service.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/service.go
new file mode 100644
index 000000000..3a5f01250
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/service.go
@@ -0,0 +1,49 @@
+package hcs
+
+import (
+ "context"
+ "encoding/json"
+
+ hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
+ "github.com/Microsoft/hcsshim/internal/vmcompute"
+)
+
+// GetServiceProperties returns properties of the host compute service.
+func GetServiceProperties(ctx context.Context, q hcsschema.PropertyQuery) (*hcsschema.ServiceProperties, error) {
+ operation := "hcsshim::GetServiceProperties"
+
+ queryb, err := json.Marshal(q)
+ if err != nil {
+ return nil, err
+ }
+ propertiesJSON, resultJSON, err := vmcompute.HcsGetServiceProperties(ctx, string(queryb))
+ events := processHcsResult(ctx, resultJSON)
+ if err != nil {
+ return nil, &HcsError{Op: operation, Err: err, Events: events}
+ }
+
+ if propertiesJSON == "" {
+ return nil, ErrUnexpectedValue
+ }
+ properties := &hcsschema.ServiceProperties{}
+ if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
+ return nil, err
+ }
+ return properties, nil
+}
+
+// ModifyServiceSettings modifies settings of the host compute service.
+func ModifyServiceSettings(ctx context.Context, settings hcsschema.ModificationRequest) error {
+ operation := "hcsshim::ModifyServiceSettings"
+
+ settingsJSON, err := json.Marshal(settings)
+ if err != nil {
+ return err
+ }
+ resultJSON, err := vmcompute.HcsModifyServiceSettings(ctx, string(settingsJSON))
+ events := processHcsResult(ctx, resultJSON)
+ if err != nil {
+ return &HcsError{Op: operation, Err: err, Events: events}
+ }
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/syscall.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/syscall.go
deleted file mode 100644
index ded2175c5..000000000
--- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/syscall.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package hcs
-
-//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go syscall.go
-
-//sys hcsFormatWritableLayerVhd(handle uintptr) (hr error) = computestorage.HcsFormatWritableLayerVhd
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
index 67a5f7176..6120399c4 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
@@ -28,8 +28,7 @@ type System struct {
waitBlock chan struct{}
waitError error
exitError error
-
- os, typ string
+ os, typ string
}
func newSystem(id string) *System {
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/utils.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/utils.go
index b474604bd..3342e5bb9 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/utils.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/utils.go
@@ -7,6 +7,7 @@ import (
"github.com/Microsoft/go-winio"
diskutil "github.com/Microsoft/go-winio/vhd"
+ "github.com/Microsoft/hcsshim/computestorage"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
@@ -36,7 +37,7 @@ func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
return fs, nil
}
-// creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
+// CreateNTFSVHD creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err error) {
if err := diskutil.CreateVhdx(vhdPath, sizeGB, 1); err != nil {
return errors.Wrap(err, "failed to create VHD")
@@ -53,7 +54,7 @@ func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err erro
}
}()
- if err := hcsFormatWritableLayerVhd(uintptr(vhd)); err != nil {
+ if err := computestorage.FormatWritableLayerVhd(ctx, windows.Handle(vhd)); err != nil {
return errors.Wrap(err, "failed to format VHD")
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go
deleted file mode 100644
index 39396d272..000000000
--- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Code generated mksyscall_windows.exe DO NOT EDIT
-
-package hcs
-
-import (
- "syscall"
- "unsafe"
-
- "golang.org/x/sys/windows"
-)
-
-var _ unsafe.Pointer
-
-// Do the interface allocations only once for common
-// Errno values.
-const (
- errnoERROR_IO_PENDING = 997
-)
-
-var (
- errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
-)
-
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e syscall.Errno) error {
- switch e {
- case 0:
- return nil
- case errnoERROR_IO_PENDING:
- return errERROR_IO_PENDING
- }
- // TODO: add more here, after collecting data on the common
- // error values see on Windows. (perhaps when running
- // all.bat?)
- return e
-}
-
-var (
- modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
-
- procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
-)
-
-func hcsFormatWritableLayerVhd(handle uintptr) (hr error) {
- r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
- if int32(r0) < 0 {
- if r0&0x1fff0000 == 0x00070000 {
- r0 &= 0xffff
- }
- hr = syscall.Errno(r0)
- }
- return
-}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go
index e0e1a4710..b36315a39 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go
@@ -17,12 +17,15 @@ type HNSEndpoint struct {
Policies []json.RawMessage `json:",omitempty"`
MacAddress string `json:",omitempty"`
IPAddress net.IP `json:",omitempty"`
+ IPv6Address net.IP `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
+ GatewayAddressV6 string `json:",omitempty"`
EnableInternalDNS bool `json:",omitempty"`
DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"`
+ IPv6PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
Namespace *Namespace `json:",omitempty"`
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go b/vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go
index 45e2281b0..d3b04eefe 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go
@@ -27,9 +27,10 @@ type namespaceResourceRequest struct {
}
type Namespace struct {
- ID string
- IsDefault bool `json:",omitempty"`
- ResourceList []NamespaceResource `json:",omitempty"`
+ ID string
+ IsDefault bool `json:",omitempty"`
+ ResourceList []NamespaceResource `json:",omitempty"`
+ CompartmentId uint32 `json:",omitempty"`
}
func issueNamespaceRequest(id *string, method, subpath string, request interface{}) (*Namespace, error) {
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go b/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
index f31edfaf8..d484c212c 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
@@ -11,72 +11,11 @@ import (
"unsafe"
"github.com/Microsoft/hcsshim/internal/longpath"
+ "github.com/Microsoft/hcsshim/internal/winapi"
winio "github.com/Microsoft/go-winio"
)
-//go:generate go run $GOROOT\src\syscall\mksyscall_windows.go -output zsyscall_windows.go safeopen.go
-
-//sys ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) = ntdll.NtCreateFile
-//sys ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile
-//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
-//sys localAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc
-//sys localFree(ptr uintptr) = kernel32.LocalFree
-
-type ioStatusBlock struct {
- Status, Information uintptr
-}
-
-type objectAttributes struct {
- Length uintptr
- RootDirectory uintptr
- ObjectName uintptr
- Attributes uintptr
- SecurityDescriptor uintptr
- SecurityQoS uintptr
-}
-
-type unicodeString struct {
- Length uint16
- MaximumLength uint16
- Buffer uintptr
-}
-
-type fileLinkInformation struct {
- ReplaceIfExists bool
- RootDirectory uintptr
- FileNameLength uint32
- FileName [1]uint16
-}
-
-type fileDispositionInformationEx struct {
- Flags uintptr
-}
-
-const (
- _FileLinkInformation = 11
- _FileDispositionInformationEx = 64
-
- FILE_READ_ATTRIBUTES = 0x0080
- FILE_WRITE_ATTRIBUTES = 0x0100
- DELETE = 0x10000
-
- FILE_OPEN = 1
- FILE_CREATE = 2
-
- FILE_DIRECTORY_FILE = 0x00000001
- FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
- FILE_DELETE_ON_CLOSE = 0x00001000
- FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
- FILE_OPEN_REPARSE_POINT = 0x00200000
-
- FILE_DISPOSITION_DELETE = 0x00000001
-
- _OBJ_DONT_REPARSE = 0x1000
-
- _STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
-)
-
func OpenRoot(path string) (*os.File, error) {
longpath, err := longpath.LongAbs(path)
if err != nil {
@@ -85,16 +24,24 @@ func OpenRoot(path string) (*os.File, error) {
return winio.OpenForBackup(longpath, syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.OPEN_EXISTING)
}
-func ntRelativePath(path string) ([]uint16, error) {
+func cleanGoStringRelativePath(path string) (string, error) {
path = filepath.Clean(path)
if strings.Contains(path, ":") {
// Since alternate data streams must follow the file they
// are attached to, finding one here (out of order) is invalid.
- return nil, errors.New("path contains invalid character `:`")
+ return "", errors.New("path contains invalid character `:`")
}
fspath := filepath.FromSlash(path)
if len(fspath) > 0 && fspath[0] == '\\' {
- return nil, errors.New("expected relative path")
+ return "", errors.New("expected relative path")
+ }
+ return fspath, nil
+}
+
+func ntRelativePath(path string) ([]uint16, error) {
+ fspath, err := cleanGoStringRelativePath(path)
+ if err != nil {
+ return nil, err
}
path16 := utf16.Encode(([]rune)(fspath))
@@ -110,11 +57,11 @@ func ntRelativePath(path string) ([]uint16, error) {
func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
var (
h uintptr
- iosb ioStatusBlock
- oa objectAttributes
+ iosb winapi.IOStatusBlock
+ oa winapi.ObjectAttributes
)
- path16, err := ntRelativePath(path)
+ cleanRelativePath, err := cleanGoStringRelativePath(path)
if err != nil {
return nil, err
}
@@ -123,20 +70,16 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
return nil, errors.New("missing root directory")
}
- upathBuffer := localAlloc(0, int(unsafe.Sizeof(unicodeString{}))+len(path16)*2)
- defer localFree(upathBuffer)
-
- upath := (*unicodeString)(unsafe.Pointer(upathBuffer))
- upath.Length = uint16(len(path16) * 2)
- upath.MaximumLength = upath.Length
- upath.Buffer = upathBuffer + unsafe.Sizeof(*upath)
- copy((*[32768]uint16)(unsafe.Pointer(upath.Buffer))[:], path16)
+ pathUnicode, err := winapi.NewUnicodeString(cleanRelativePath)
+ if err != nil {
+ return nil, err
+ }
oa.Length = unsafe.Sizeof(oa)
- oa.ObjectName = upathBuffer
+ oa.ObjectName = uintptr(unsafe.Pointer(pathUnicode))
oa.RootDirectory = uintptr(root.Fd())
- oa.Attributes = _OBJ_DONT_REPARSE
- status := ntCreateFile(
+ oa.Attributes = winapi.OBJ_DONT_REPARSE
+ status := winapi.NtCreateFile(
&h,
accessMask|syscall.SYNCHRONIZE,
&oa,
@@ -145,12 +88,12 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
0,
shareFlags,
createDisposition,
- FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|flags,
+ winapi.FILE_OPEN_FOR_BACKUP_INTENT|winapi.FILE_SYNCHRONOUS_IO_NONALERT|flags,
nil,
0,
)
if status != 0 {
- return nil, rtlNtStatusToDosError(status)
+ return nil, winapi.RtlNtStatusToDosError(status)
}
fullPath, err := longpath.LongAbs(filepath.Join(root.Name(), path))
@@ -182,7 +125,7 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
oldroot,
syscall.FILE_WRITE_ATTRIBUTES,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_OPEN,
+ winapi.FILE_OPEN,
0,
)
if err != nil {
@@ -199,8 +142,8 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
newroot,
syscall.GENERIC_READ,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_OPEN,
- FILE_DIRECTORY_FILE)
+ winapi.FILE_OPEN,
+ winapi.FILE_DIRECTORY_FILE)
if err != nil {
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
}
@@ -211,7 +154,7 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
return err
}
if (fi.FileAttributes & syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
- return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: rtlNtStatusToDosError(_STATUS_REPARSE_POINT_ENCOUNTERED)}
+ return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: winapi.RtlNtStatusToDosError(winapi.STATUS_REPARSE_POINT_ENCOUNTERED)}
}
} else {
@@ -227,24 +170,25 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
return err
}
- size := int(unsafe.Offsetof(fileLinkInformation{}.FileName)) + len(newbase16)*2
- linkinfoBuffer := localAlloc(0, size)
- defer localFree(linkinfoBuffer)
- linkinfo := (*fileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
+ size := int(unsafe.Offsetof(winapi.FileLinkInformation{}.FileName)) + len(newbase16)*2
+ linkinfoBuffer := winapi.LocalAlloc(0, size)
+ defer winapi.LocalFree(linkinfoBuffer)
+
+ linkinfo := (*winapi.FileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
linkinfo.RootDirectory = parent.Fd()
linkinfo.FileNameLength = uint32(len(newbase16) * 2)
copy((*[32768]uint16)(unsafe.Pointer(&linkinfo.FileName[0]))[:], newbase16)
- var iosb ioStatusBlock
- status := ntSetInformationFile(
+ var iosb winapi.IOStatusBlock
+ status := winapi.NtSetInformationFile(
oldf.Fd(),
&iosb,
linkinfoBuffer,
uint32(size),
- _FileLinkInformation,
+ winapi.FileLinkInformationClass,
)
if status != 0 {
- return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: rtlNtStatusToDosError(status)}
+ return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: winapi.RtlNtStatusToDosError(status)}
}
return nil
@@ -252,17 +196,17 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
// deleteOnClose marks a file to be deleted when the handle is closed.
func deleteOnClose(f *os.File) error {
- disposition := fileDispositionInformationEx{Flags: FILE_DISPOSITION_DELETE}
- var iosb ioStatusBlock
- status := ntSetInformationFile(
+ disposition := winapi.FileDispositionInformationEx{Flags: winapi.FILE_DISPOSITION_DELETE}
+ var iosb winapi.IOStatusBlock
+ status := winapi.NtSetInformationFile(
f.Fd(),
&iosb,
uintptr(unsafe.Pointer(&disposition)),
uint32(unsafe.Sizeof(disposition)),
- _FileDispositionInformationEx,
+ winapi.FileDispositionInformationExClass,
)
if status != 0 {
- return rtlNtStatusToDosError(status)
+ return winapi.RtlNtStatusToDosError(status)
}
return nil
}
@@ -291,10 +235,10 @@ func RemoveRelative(path string, root *os.File) error {
f, err := openRelativeInternal(
path,
root,
- FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|DELETE,
+ winapi.FILE_READ_ATTRIBUTES|winapi.FILE_WRITE_ATTRIBUTES|winapi.DELETE,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_OPEN,
- FILE_OPEN_REPARSE_POINT)
+ winapi.FILE_OPEN,
+ winapi.FILE_OPEN_REPARSE_POINT)
if err == nil {
defer f.Close()
err = deleteOnClose(f)
@@ -385,8 +329,8 @@ func MkdirRelative(path string, root *os.File) error {
root,
0,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_CREATE,
- FILE_DIRECTORY_FILE)
+ winapi.FILE_CREATE,
+ winapi.FILE_DIRECTORY_FILE)
if err == nil {
f.Close()
} else {
@@ -401,10 +345,10 @@ func LstatRelative(path string, root *os.File) (os.FileInfo, error) {
f, err := openRelativeInternal(
path,
root,
- FILE_READ_ATTRIBUTES,
+ winapi.FILE_READ_ATTRIBUTES,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_OPEN,
- FILE_OPEN_REPARSE_POINT)
+ winapi.FILE_OPEN,
+ winapi.FILE_OPEN_REPARSE_POINT)
if err != nil {
return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
}
@@ -421,7 +365,7 @@ func EnsureNotReparsePointRelative(path string, root *os.File) error {
root,
0,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- FILE_OPEN,
+ winapi.FILE_OPEN,
0)
if err != nil {
return err
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
deleted file mode 100644
index 709b9d347..000000000
--- a/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Code generated by 'go generate'; DO NOT EDIT.
-
-package safefile
-
-import (
- "syscall"
- "unsafe"
-
- "golang.org/x/sys/windows"
-)
-
-var _ unsafe.Pointer
-
-// Do the interface allocations only once for common
-// Errno values.
-const (
- errnoERROR_IO_PENDING = 997
-)
-
-var (
- errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
-)
-
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e syscall.Errno) error {
- switch e {
- case 0:
- return nil
- case errnoERROR_IO_PENDING:
- return errERROR_IO_PENDING
- }
- // TODO: add more here, after collecting data on the common
- // error values see on Windows. (perhaps when running
- // all.bat?)
- return e
-}
-
-var (
- modntdll = windows.NewLazySystemDLL("ntdll.dll")
- modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
-
- procNtCreateFile = modntdll.NewProc("NtCreateFile")
- procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
- procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
- procLocalAlloc = modkernel32.NewProc("LocalAlloc")
- procLocalFree = modkernel32.NewProc("LocalFree")
-)
-
-func ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) {
- r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0)
- status = uint32(r0)
- return
-}
-
-func ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) {
- r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0)
- status = uint32(r0)
- return
-}
-
-func rtlNtStatusToDosError(status uint32) (winerr error) {
- r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
- if r0 != 0 {
- winerr = syscall.Errno(r0)
- }
- return
-}
-
-func localAlloc(flags uint32, size int) (ptr uintptr) {
- r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0)
- ptr = uintptr(r0)
- return
-}
-
-func localFree(ptr uintptr) {
- syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0)
- return
-}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_add_instance_request.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_add_instance_request.go
new file mode 100644
index 000000000..495c6ebc8
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_add_instance_request.go
@@ -0,0 +1,16 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardAddInstanceRequest struct {
+ Id string `json:"Id,omitempty"`
+ CredentialSpec string `json:"CredentialSpec,omitempty"`
+ Transport string `json:"Transport,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_hv_socket_service_config.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_hv_socket_service_config.go
new file mode 100644
index 000000000..1ed4c008f
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_hv_socket_service_config.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardHvSocketServiceConfig struct {
+ ServiceId string `json:"ServiceId,omitempty"`
+ ServiceConfig *HvSocketServiceConfig `json:"ServiceConfig,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_instance.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_instance.go
new file mode 100644
index 000000000..d7ebd0fcc
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_instance.go
@@ -0,0 +1,16 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardInstance struct {
+ Id string `json:"Id,omitempty"`
+ CredentialGuard *ContainerCredentialGuardState `json:"CredentialGuard,omitempty"`
+ HvSocketConfig *ContainerCredentialGuardHvSocketServiceConfig `json:"HvSocketConfig,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_modify_operation.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_modify_operation.go
new file mode 100644
index 000000000..71005b090
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_modify_operation.go
@@ -0,0 +1,17 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardModifyOperation string
+
+const (
+ AddInstance ContainerCredentialGuardModifyOperation = "AddInstance"
+ RemoveInstance ContainerCredentialGuardModifyOperation = "RemoveInstance"
+)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_operation_request.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_operation_request.go
new file mode 100644
index 000000000..952cda496
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_operation_request.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardOperationRequest struct {
+ Operation ContainerCredentialGuardModifyOperation `json:"Operation,omitempty"`
+ OperationDetails interface{} `json:"OperationDetails,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_remove_instance_request.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_remove_instance_request.go
new file mode 100644
index 000000000..32e5a3bee
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_remove_instance_request.go
@@ -0,0 +1,14 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardRemoveInstanceRequest struct {
+ Id string `json:"Id,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_system_info.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_system_info.go
new file mode 100644
index 000000000..ea306fa21
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_system_info.go
@@ -0,0 +1,14 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ContainerCredentialGuardSystemInfo struct {
+ Instances []ContainerCredentialGuardInstance `json:"Instances,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group.go
new file mode 100644
index 000000000..90332a519
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// CPU groups allow Hyper-V administrators to better manage and allocate the host's CPU resources across guest virtual machines
+type CpuGroup struct {
+ Id string `json:"Id,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_affinity.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_affinity.go
new file mode 100644
index 000000000..8794961bf
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_affinity.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type CpuGroupAffinity struct {
+ LogicalProcessorCount int32 `json:"LogicalProcessorCount,omitempty"`
+ LogicalProcessors []int32 `json:"LogicalProcessors,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_config.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_config.go
new file mode 100644
index 000000000..f1a28cd38
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_config.go
@@ -0,0 +1,18 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type CpuGroupConfig struct {
+ GroupId string `json:"GroupId,omitempty"`
+ Affinity *CpuGroupAffinity `json:"Affinity,omitempty"`
+ GroupProperties []CpuGroupProperty `json:"GroupProperties,omitempty"`
+ // Hypervisor CPU group IDs exposed to clients
+ HypervisorGroupId int32 `json:"HypervisorGroupId,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go
new file mode 100644
index 000000000..3ace0ccc3
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// Structure used to return cpu groups for a Service property query
+type CpuGroupConfigurations struct {
+ CpuGroups []CpuGroupConfig `json:"CpuGroups,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_operations.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_operations.go
new file mode 100644
index 000000000..7d8978070
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_operations.go
@@ -0,0 +1,18 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type CPUGroupOperation string
+
+const (
+ CreateGroup CPUGroupOperation = "CreateGroup"
+ DeleteGroup CPUGroupOperation = "DeleteGroup"
+ SetProperty CPUGroupOperation = "SetProperty"
+)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_property.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_property.go
new file mode 100644
index 000000000..bbad6a2c4
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_property.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type CpuGroupProperty struct {
+ PropertyCode uint32 `json:"PropertyCode,omitempty"`
+ PropertyValue uint32 `json:"PropertyValue,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go
new file mode 100644
index 000000000..91a8278fe
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go
@@ -0,0 +1,17 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// Create group operation settings
+type CreateGroupOperation struct {
+ GroupId string `json:"GroupId,omitempty"`
+ LogicalProcessorCount uint32 `json:"LogicalProcessorCount,omitempty"`
+ LogicalProcessors []uint32 `json:"LogicalProcessors,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go
new file mode 100644
index 000000000..134bd9881
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// Delete group operation settings
+type DeleteGroupOperation struct {
+ GroupId string `json:"GroupId,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/device.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/device.go
index ca319bbbc..0b9c0fbf7 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/device.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/device.go
@@ -9,8 +9,19 @@
package hcsschema
-type Device struct {
+type DeviceType string
+
+const (
+ ClassGUID DeviceType = "ClassGuid"
+ DeviceInstance = "DeviceInstance"
+ GPUMirror = "GpuMirror"
+)
- // The interface class guid of the device to assign to container.
+type Device struct {
+ // The type of device to assign to the container.
+ Type DeviceType `json:"Type,omitempty"`
+ // The interface class guid of the device interfaces to assign to the container. Only used when Type is ClassGuid.
InterfaceClassGuid string `json:"InterfaceClassGuid,omitempty"`
+ // The location path of the device to assign to the container. Only used when Type is DeviceInstance.
+ LocationPath string `json:"LocationPath,omitempty"`
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go
new file mode 100644
index 000000000..2238ce530
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go
@@ -0,0 +1,16 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// Structure used to request a service processor modification
+type HostProcessorModificationRequest struct {
+ Operation CPUGroupOperation `json:"Operation,omitempty"`
+ OperationDetails interface{} `json:"OperationDetails,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_address.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_address.go
new file mode 100644
index 000000000..84c11b93e
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_address.go
@@ -0,0 +1,17 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// This class defines address settings applied to a VM
+// by the GCS every time a VM starts or restores.
+type HvSocketAddress struct {
+ LocalAddress string `json:"LocalAddress,omitempty"`
+ ParentAddress string `json:"ParentAddress,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_service_config.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_service_config.go
index a848e91e6..ecd9f7fba 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_service_config.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/hv_socket_service_config.go
@@ -19,4 +19,10 @@ type HvSocketServiceConfig struct {
// If true, HvSocket will process wildcard binds for this service/system combination. Wildcard binds are secured in the registry at SOFTWARE/Microsoft/Windows NT/CurrentVersion/Virtualization/HvSocket/WildcardDescriptors
AllowWildcardBinds bool `json:"AllowWildcardBinds,omitempty"`
+
+ // Disabled controls whether the HvSocket service is accepting connection requests.
+ // This set to true will make the service refuse all incoming connections as well as cancel
+ // any connections already established. The service itself will still be active however
+ // and can be re-enabled at a future time.
+ Disabled bool `json:"Disabled,omitempty"`
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/logical_processor.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/logical_processor.go
new file mode 100644
index 000000000..676ad300d
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/logical_processor.go
@@ -0,0 +1,18 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type LogicalProcessor struct {
+ LpIndex uint32 `json:"LpIndex,omitempty"`
+ NodeNumber uint8 `json:"NodeNumber, omitempty"`
+ PackageId uint32 `json:"PackageId, omitempty"`
+ CoreId uint32 `json:"CoreId, omitempty"`
+ RootVpIndex int32 `json:"RootVpIndex, omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory.go
index ec93d004e..30749c672 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory.go
@@ -10,5 +10,5 @@
package hcsschema
type Memory struct {
- SizeInMB int32 `json:"SizeInMB,omitempty"`
+ SizeInMB uint64 `json:"SizeInMB,omitempty"`
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory_2.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory_2.go
index 95328ec30..71224c75b 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory_2.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/memory_2.go
@@ -10,7 +10,7 @@
package hcsschema
type Memory2 struct {
- SizeInMB int32 `json:"SizeInMB,omitempty"`
+ SizeInMB uint64 `json:"SizeInMB,omitempty"`
AllowOvercommit bool `json:"AllowOvercommit,omitempty"`
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/modification_request.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/modification_request.go
new file mode 100644
index 000000000..1384ed888
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/modification_request.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ModificationRequest struct {
+ PropertyType PropertyType `json:"PropertyType,omitempty"`
+ Settings interface{} `json:"Settings,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/processor_topology.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/processor_topology.go
new file mode 100644
index 000000000..885156e77
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/processor_topology.go
@@ -0,0 +1,15 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+type ProcessorTopology struct {
+ LogicalProcessorCount uint32 `json:"LogicalProcessorCount,omitempty"`
+ LogicalProcessors []LogicalProcessor `json:"LogicalProcessors,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/property_type.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/property_type.go
index f092b737f..98f2c96ed 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/property_type.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/property_type.go
@@ -18,6 +18,9 @@ const (
PTProcessList PropertyType = "ProcessList"
PTTerminateOnLastHandleClosed PropertyType = "TerminateOnLastHandleClosed"
PTSharedMemoryRegion PropertyType = "SharedMemoryRegion"
+ PTContainerCredentialGuard PropertyType = "ContainerCredentialGuard" // This field is not generated by swagger. This was added manually.
PTGuestConnection PropertyType = "GuestConnection"
PTICHeartbeatStatus PropertyType = "ICHeartbeatStatus"
+ PTProcessorTopology PropertyType = "ProcessorTopology"
+ PTCPUGroup PropertyType = "CpuGroup"
)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/service_properties.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/service_properties.go
new file mode 100644
index 000000000..b8142ca6a
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/service_properties.go
@@ -0,0 +1,18 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+import "encoding/json"
+
+type ServiceProperties struct {
+ // Changed Properties field to []json.RawMessage from []interface{} to avoid having to
+ // remarshal sp.Properties[n] and unmarshal into the type(s) we want.
+ Properties []json.RawMessage `json:"Properties,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/vm_processor_limits.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/vm_processor_limits.go
new file mode 100644
index 000000000..de1b9cf1a
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/vm_processor_limits.go
@@ -0,0 +1,22 @@
+/*
+ * HCS API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * API version: 2.4
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+
+package hcsschema
+
+// ProcessorLimits is used when modifying processor scheduling limits of a virtual machine.
+type ProcessorLimits struct {
+ // Maximum amount of host CPU resources that the virtual machine can use.
+ Limit uint64 `json:"Limit,omitempty"`
+ // Value describing the relative priority of this virtual machine compared to other virtual machines.
+ Weight uint64 `json:"Weight,omitempty"`
+ // Minimum amount of host CPU resources that the virtual machine is guaranteed.
+ Reservation uint64 `json:"Reservation,omitempty"`
+ // Provides the target maximum CPU frequency, in MHz, for a virtual machine.
+ MaximumFrequencyMHz uint32 `json:"MaximumFrequencyMHz,omitempty"`
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go
index 7c2a0dc28..e42bf8cfa 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go
@@ -26,6 +26,7 @@ import (
//sys hcsResumeComputeSystem(computeSystem HcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
//sys hcsGetComputeSystemProperties(computeSystem HcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties?
//sys hcsModifyComputeSystem(computeSystem HcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem?
+//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings?
//sys hcsRegisterComputeSystemCallback(computeSystem HcsSystem, callback uintptr, context uintptr, callbackHandle *HcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
//sys hcsUnregisterComputeSystemCallback(callbackHandle HcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
@@ -337,6 +338,27 @@ func HcsModifyComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, confi
})
}
+func HcsModifyServiceSettings(ctx gcontext.Context, settings string) (result string, hr error) {
+ ctx, span := trace.StartSpan(ctx, "HcsModifyServiceSettings")
+ defer span.End()
+ defer func() {
+ if result != "" {
+ span.AddAttributes(trace.StringAttribute("result", result))
+ }
+ oc.SetSpanStatus(span, hr)
+ }()
+ span.AddAttributes(trace.StringAttribute("settings", settings))
+
+ return result, execute(ctx, timeout.SyscallWatcher, func() error {
+ var resultp *uint16
+ err := hcsModifyServiceSettings(settings, &resultp)
+ if resultp != nil {
+ result = interop.ConvertAndFreeCoTaskMemString(resultp)
+ }
+ return err
+ })
+}
+
func HcsRegisterComputeSystemCallback(ctx gcontext.Context, computeSystem HcsSystem, callback uintptr, context uintptr) (callbackHandle HcsCallback, hr error) {
ctx, span := trace.StartSpan(ctx, "HcsRegisterComputeSystemCallback")
defer span.End()
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go
index 0f2a69f6a..8cfded496 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go
@@ -50,6 +50,7 @@ var (
procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem")
procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties")
procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem")
+ procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings")
procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess")
@@ -314,6 +315,29 @@ func _hcsModifyComputeSystem(computeSystem HcsSystem, configuration *uint16, res
return
}
+func hcsModifyServiceSettings(settings string, result **uint16) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(settings)
+ if hr != nil {
+ return
+ }
+ return _hcsModifyServiceSettings(_p0, result)
+}
+
+func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) {
+ if hr = procHcsModifyServiceSettings.Find(); hr != nil {
+ return
+ }
+ r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
func hcsRegisterComputeSystemCallback(computeSystem HcsSystem, callback uintptr, context uintptr, callbackHandle *HcsCallback) (hr error) {
if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil {
return
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayer.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayer.go
index f907a7044..3ec708d1e 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayer.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayer.go
@@ -11,6 +11,7 @@ import (
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/safefile"
+ "github.com/Microsoft/hcsshim/internal/winapi"
"go.opencensus.io/trace"
)
@@ -37,7 +38,7 @@ type dirInfo struct {
func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
for i := range dis {
di := &dis[len(dis)-i-1] // reverse order: process child directories first
- f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_OPEN, safefile.FILE_DIRECTORY_FILE)
+ f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, winapi.FILE_OPEN, winapi.FILE_DIRECTORY_FILE|syscall.FILE_FLAG_OPEN_REPARSE_POINT)
if err != nil {
return err
}
@@ -47,6 +48,7 @@ func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
if err != nil {
return err
}
+
}
return nil
}
@@ -92,14 +94,12 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
extraFlags := uint32(0)
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
- extraFlags |= safefile.FILE_DIRECTORY_FILE
- if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
- w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
- }
+ extraFlags |= winapi.FILE_DIRECTORY_FILE
+ w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
}
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
- f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, extraFlags)
+ f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, winapi.FILE_CREATE, extraFlags)
if err != nil {
return hcserror.New(err, "Failed to safefile.OpenRelative", name)
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go
index e3ff952a7..5a3809ae2 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go
@@ -10,9 +10,7 @@ import (
)
// CreateScratchLayer creates and populates new read-write layer for use by a container.
-// This requires both the id of the direct parent layer, as well as the full list
-// of paths to all parent layers up to the base (and including the direct parent
-// whose id was provided).
+// This requires the full list of paths to all parent layers up to the base
func CreateScratchLayer(ctx context.Context, path string, parentLayerPaths []string) (err error) {
title := "hcsshim::CreateScratchLayer"
ctx, span := trace.StartSpan(ctx, title)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go
index 16800b394..b3c150d66 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go
@@ -93,6 +93,19 @@ func (r *legacyLayerWriterWrapper) Close() (err error) {
return err
}
}
+
+ // The reapplyDirectoryTimes must be called AFTER we are done with Tombstone
+ // deletion and hard link creation. This is because Tombstone deletion and hard link
+ // creation updates the directory last write timestamps so that will change the
+ // timestamps added by the `Add` call. Some container applications depend on the
+ // correctness of these timestamps and so we should change the timestamps back to
+ // the original value (i.e the value provided in the Add call) after this
+ // processing is done.
+ err = reapplyDirectoryTimes(r.destRoot, r.changedDi)
+ if err != nil {
+ return err
+ }
+
// Prepare the utility VM for use if one is present in the layer.
if r.HasUtilityVM {
err := safefile.EnsureNotReparsePointRelative("UtilityVM", r.destRoot)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go
index b8ea5d263..dc3caf751 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go
@@ -15,6 +15,7 @@ import (
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/longpath"
"github.com/Microsoft/hcsshim/internal/safefile"
+ "github.com/Microsoft/hcsshim/internal/winapi"
)
var errorIterationCanceled = errors.New("")
@@ -341,7 +342,7 @@ type legacyLayerWriter struct {
backupWriter *winio.BackupFileWriter
Tombstones []string
HasUtilityVM bool
- uvmDi []dirInfo
+ changedDi []dirInfo
addedFiles map[string]bool
PendingLinks []pendingLink
pendingDirs []pendingDir
@@ -472,8 +473,8 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
srcRoot,
syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
- safefile.FILE_OPEN,
- safefile.FILE_OPEN_REPARSE_POINT)
+ winapi.FILE_OPEN,
+ winapi.FILE_OPEN_REPARSE_POINT)
if err != nil {
return nil, err
}
@@ -488,14 +489,14 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
extraFlags := uint32(0)
if isDir {
- extraFlags |= safefile.FILE_DIRECTORY_FILE
+ extraFlags |= winapi.FILE_DIRECTORY_FILE
}
dest, err := safefile.OpenRelative(
subPath,
destRoot,
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
- safefile.FILE_CREATE,
+ winapi.FILE_CREATE,
extraFlags)
if err != nil {
return nil, err
@@ -555,7 +556,7 @@ func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles
if err != nil {
return err
}
- if isDir && !isReparsePoint {
+ if isDir {
di = append(di, dirInfo{path: relPath, fileInfo: *fi})
}
} else {
@@ -583,6 +584,10 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return w.initUtilityVM()
}
+ if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
+ w.changedDi = append(w.changedDi, dirInfo{path: name, fileInfo: *fileInfo})
+ }
+
name = filepath.Clean(name)
if hasPathPrefix(name, utilityVMPath) {
if !w.HasUtilityVM {
@@ -591,7 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
return errors.New("invalid UtilityVM layer")
}
- createDisposition := uint32(safefile.FILE_OPEN)
+ createDisposition := uint32(winapi.FILE_OPEN)
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
st, err := safefile.LstatRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) {
@@ -612,16 +617,13 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return err
}
}
- if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
- w.uvmDi = append(w.uvmDi, dirInfo{path: name, fileInfo: *fileInfo})
- }
} else {
// Overwrite any existing hard link.
err := safefile.RemoveRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) {
return err
}
- createDisposition = safefile.FILE_CREATE
+ createDisposition = winapi.FILE_CREATE
}
f, err := safefile.OpenRelative(
@@ -630,7 +632,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
createDisposition,
- safefile.FILE_OPEN_REPARSE_POINT,
+ winapi.FILE_OPEN_REPARSE_POINT,
)
if err != nil {
return err
@@ -667,7 +669,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
w.currentIsDir = true
}
- f, err := safefile.OpenRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, 0)
+ f, err := safefile.OpenRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, winapi.FILE_CREATE, 0)
if err != nil {
return err
}
@@ -805,11 +807,5 @@ func (w *legacyLayerWriter) Close() error {
return err
}
}
- if w.HasUtilityVM {
- err := reapplyDirectoryTimes(w.destRoot, w.uvmDi)
- if err != nil {
- return err
- }
- }
return nil
}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/wclayer.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/wclayer.go
index dc40bf519..9b1e06d50 100644
--- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/wclayer.go
+++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/wclayer.go
@@ -1,3 +1,6 @@
+// Package wclayer provides bindings to HCS's legacy layer management API and
+// provides a higher level interface around these calls for container layer
+// management.
package wclayer
import "github.com/Microsoft/go-winio/pkg/guid"
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/devices.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/devices.go
new file mode 100644
index 000000000..df28ea242
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/devices.go
@@ -0,0 +1,13 @@
+package winapi
+
+import "github.com/Microsoft/go-winio/pkg/guid"
+
+//sys CMGetDeviceIDListSize(pulLen *uint32, pszFilter *byte, uFlags uint32) (hr error) = cfgmgr32.CM_Get_Device_ID_List_SizeA
+//sys CMGetDeviceIDList(pszFilter *byte, buffer *byte, bufferLen uint32, uFlags uint32) (hr error)= cfgmgr32.CM_Get_Device_ID_ListA
+//sys CMLocateDevNode(pdnDevInst *uint32, pDeviceID string, uFlags uint32) (hr error) = cfgmgr32.CM_Locate_DevNodeW
+//sys CMGetDevNodeProperty(dnDevInst uint32, propertyKey *DevPropKey, propertyType *uint32, propertyBuffer *uint16, propertyBufferSize *uint32, uFlags uint32) (hr error) = cfgmgr32.CM_Get_DevNode_PropertyW
+
+type DevPropKey struct {
+ Fmtid guid.GUID
+ Pid uint32
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/errors.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/errors.go
new file mode 100644
index 000000000..4e80ef68c
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/errors.go
@@ -0,0 +1,15 @@
+package winapi
+
+import "syscall"
+
+//sys RtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosError
+
+const (
+ STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
+ ERROR_NO_MORE_ITEMS = 0x103
+ ERROR_MORE_DATA syscall.Errno = 234
+)
+
+func NTSuccess(status uint32) bool {
+ return status == 0
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/filesystem.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/filesystem.go
new file mode 100644
index 000000000..490576b94
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/filesystem.go
@@ -0,0 +1,110 @@
+package winapi
+
+//sys NtCreateFile(handle *uintptr, accessMask uint32, oa *ObjectAttributes, iosb *IOStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) = ntdll.NtCreateFile
+//sys NtSetInformationFile(handle uintptr, iosb *IOStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile
+
+//sys NtOpenDirectoryObject(handle *uintptr, accessMask uint32, oa *ObjectAttributes) (status uint32) = ntdll.NtOpenDirectoryObject
+//sys NtQueryDirectoryObject(handle uintptr, buffer *byte, length uint32, singleEntry bool, restartScan bool, context *uint32, returnLength *uint32)(status uint32) = ntdll.NtQueryDirectoryObject
+
+const (
+ FileLinkInformationClass = 11
+ FileDispositionInformationExClass = 64
+
+ FILE_READ_ATTRIBUTES = 0x0080
+ FILE_WRITE_ATTRIBUTES = 0x0100
+ DELETE = 0x10000
+
+ FILE_OPEN = 1
+ FILE_CREATE = 2
+
+ FILE_LIST_DIRECTORY = 0x00000001
+ FILE_DIRECTORY_FILE = 0x00000001
+ FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
+ FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
+ FILE_OPEN_REPARSE_POINT = 0x00200000
+
+ FILE_DISPOSITION_DELETE = 0x00000001
+
+ OBJ_DONT_REPARSE = 0x1000
+
+ STATUS_MORE_ENTRIES = 0x105
+ STATUS_NO_MORE_ENTRIES = 0x8000001a
+)
+
+// Select entries from FILE_INFO_BY_HANDLE_CLASS.
+//
+// C declaration:
+// typedef enum _FILE_INFO_BY_HANDLE_CLASS {
+// FileBasicInfo,
+// FileStandardInfo,
+// FileNameInfo,
+// FileRenameInfo,
+// FileDispositionInfo,
+// FileAllocationInfo,
+// FileEndOfFileInfo,
+// FileStreamInfo,
+// FileCompressionInfo,
+// FileAttributeTagInfo,
+// FileIdBothDirectoryInfo,
+// FileIdBothDirectoryRestartInfo,
+// FileIoPriorityHintInfo,
+// FileRemoteProtocolInfo,
+// FileFullDirectoryInfo,
+// FileFullDirectoryRestartInfo,
+// FileStorageInfo,
+// FileAlignmentInfo,
+// FileIdInfo,
+// FileIdExtdDirectoryInfo,
+// FileIdExtdDirectoryRestartInfo,
+// FileDispositionInfoEx,
+// FileRenameInfoEx,
+// FileCaseSensitiveInfo,
+// FileNormalizedNameInfo,
+// MaximumFileInfoByHandleClass
+// } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;
+//
+// Documentation: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ne-minwinbase-file_info_by_handle_class
+const (
+ FileIdInfo = 18
+)
+
+type FileDispositionInformationEx struct {
+ Flags uintptr
+}
+
+type IOStatusBlock struct {
+ Status, Information uintptr
+}
+
+type ObjectAttributes struct {
+ Length uintptr
+ RootDirectory uintptr
+ ObjectName uintptr
+ Attributes uintptr
+ SecurityDescriptor uintptr
+ SecurityQoS uintptr
+}
+
+type ObjectDirectoryInformation struct {
+ Name UnicodeString
+ TypeName UnicodeString
+}
+
+type FileLinkInformation struct {
+ ReplaceIfExists bool
+ RootDirectory uintptr
+ FileNameLength uint32
+ FileName [1]uint16
+}
+
+// C declaration:
+// typedef struct _FILE_ID_INFO {
+// ULONGLONG VolumeSerialNumber;
+// FILE_ID_128 FileId;
+// } FILE_ID_INFO, *PFILE_ID_INFO;
+//
+// Documentation: https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_info
+type FILE_ID_INFO struct {
+ VolumeSerialNumber uint64
+ FileID [16]byte
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go
new file mode 100644
index 000000000..4e609cbf1
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go
@@ -0,0 +1,3 @@
+package winapi
+
+//sys GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go
new file mode 100644
index 000000000..6cb411cc4
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go
@@ -0,0 +1,185 @@
+package winapi
+
+import (
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// Messages that can be received from an assigned io completion port.
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_associate_completion_port
+const (
+ JOB_OBJECT_MSG_END_OF_JOB_TIME uint32 = 1
+ JOB_OBJECT_MSG_END_OF_PROCESS_TIME uint32 = 2
+ JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT uint32 = 3
+ JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO uint32 = 4
+ JOB_OBJECT_MSG_NEW_PROCESS uint32 = 6
+ JOB_OBJECT_MSG_EXIT_PROCESS uint32 = 7
+ JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS uint32 = 8
+ JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT uint32 = 9
+ JOB_OBJECT_MSG_JOB_MEMORY_LIMIT uint32 = 10
+ JOB_OBJECT_MSG_NOTIFICATION_LIMIT uint32 = 11
+)
+
+// IO limit flags
+//
+// https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/ns-jobapi2-jobobject_io_rate_control_information
+const JOB_OBJECT_IO_RATE_CONTROL_ENABLE = 0x1
+
+const JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE uint32 = 0x1
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
+const (
+ JOB_OBJECT_CPU_RATE_CONTROL_ENABLE uint32 = 1 << iota
+ JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED
+ JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP
+ JOB_OBJECT_CPU_RATE_CONTROL_NOTIFY
+ JOB_OBJECT_CPU_RATE_CONTROL_MIN_MAX_RATE
+)
+
+// JobObjectInformationClass values. Used for a call to QueryInformationJobObject
+//
+// https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/nf-jobapi2-queryinformationjobobject
+const (
+ JobObjectBasicAccountingInformation uint32 = 1
+ JobObjectBasicProcessIdList uint32 = 3
+ JobObjectBasicAndIoAccountingInformation uint32 = 8
+ JobObjectLimitViolationInformation uint32 = 13
+ JobObjectMemoryUsageInformation uint32 = 28
+ JobObjectNotificationLimitInformation2 uint32 = 33
+ JobObjectIoAttribution uint32 = 42
+)
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_limit_information
+type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
+ PerProcessUserTimeLimit int64
+ PerJobUserTimeLimit int64
+ LimitFlags uint32
+ MinimumWorkingSetSize uintptr
+ MaximumWorkingSetSize uintptr
+ ActiveProcessLimit uint32
+ Affinity uintptr
+ PriorityClass uint32
+ SchedulingClass uint32
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
+type JOBOBJECT_CPU_RATE_CONTROL_INFORMATION struct {
+ ControlFlags uint32
+ Value uint32
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/ns-jobapi2-jobobject_io_rate_control_information
+type JOBOBJECT_IO_RATE_CONTROL_INFORMATION struct {
+ MaxIops int64
+ MaxBandwidth int64
+ ReservationIops int64
+ BaseIOSize uint32
+ VolumeName string
+ ControlFlags uint32
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_process_id_list
+type JOBOBJECT_BASIC_PROCESS_ID_LIST struct {
+ NumberOfAssignedProcesses uint32
+ NumberOfProcessIdsInList uint32
+ ProcessIdList [1]uintptr
+}
+
+// AllPids returns all the process Ids in the job object.
+func (p *JOBOBJECT_BASIC_PROCESS_ID_LIST) AllPids() []uintptr {
+ return (*[(1 << 27) - 1]uintptr)(unsafe.Pointer(&p.ProcessIdList[0]))[:p.NumberOfProcessIdsInList]
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_accounting_information
+type JOBOBJECT_BASIC_ACCOUNTING_INFORMATION struct {
+ TotalUserTime int64
+ TotalKernelTime int64
+ ThisPeriodTotalUserTime int64
+ ThisPeriodTotalKernelTime int64
+ TotalPageFaultCount uint32
+ TotalProcesses uint32
+ ActiveProcesses uint32
+ TotalTerminateProcesses uint32
+}
+
+//https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_and_io_accounting_information
+type JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION struct {
+ BasicInfo JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
+ IoInfo windows.IO_COUNTERS
+}
+
+// typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION {
+// ULONG64 JobMemory;
+// ULONG64 PeakJobMemoryUsed;
+// } JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION;
+//
+type JOBOBJECT_MEMORY_USAGE_INFORMATION struct {
+ JobMemory uint64
+ PeakJobMemoryUsed uint64
+}
+
+// typedef struct _JOBOBJECT_IO_ATTRIBUTION_STATS {
+// ULONG_PTR IoCount;
+// ULONGLONG TotalNonOverlappedQueueTime;
+// ULONGLONG TotalNonOverlappedServiceTime;
+// ULONGLONG TotalSize;
+// } JOBOBJECT_IO_ATTRIBUTION_STATS, *PJOBOBJECT_IO_ATTRIBUTION_STATS;
+//
+type JOBOBJECT_IO_ATTRIBUTION_STATS struct {
+ IoCount uintptr
+ TotalNonOverlappedQueueTime uint64
+ TotalNonOverlappedServiceTime uint64
+ TotalSize uint64
+}
+
+// typedef struct _JOBOBJECT_IO_ATTRIBUTION_INFORMATION {
+// ULONG ControlFlags;
+// JOBOBJECT_IO_ATTRIBUTION_STATS ReadStats;
+// JOBOBJECT_IO_ATTRIBUTION_STATS WriteStats;
+// } JOBOBJECT_IO_ATTRIBUTION_INFORMATION, *PJOBOBJECT_IO_ATTRIBUTION_INFORMATION;
+//
+type JOBOBJECT_IO_ATTRIBUTION_INFORMATION struct {
+ ControlFlags uint32
+ ReadStats JOBOBJECT_IO_ATTRIBUTION_STATS
+ WriteStats JOBOBJECT_IO_ATTRIBUTION_STATS
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_associate_completion_port
+type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
+ CompletionKey windows.Handle
+ CompletionPort windows.Handle
+}
+
+// BOOL IsProcessInJob(
+// HANDLE ProcessHandle,
+// HANDLE JobHandle,
+// PBOOL Result
+// );
+//
+//sys IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *bool) (err error) = kernel32.IsProcessInJob
+
+// BOOL QueryInformationJobObject(
+// HANDLE hJob,
+// JOBOBJECTINFOCLASS JobObjectInformationClass,
+// LPVOID lpJobObjectInformation,
+// DWORD cbJobObjectInformationLength,
+// LPDWORD lpReturnLength
+// );
+//
+//sys QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) = kernel32.QueryInformationJobObject
+
+// HANDLE OpenJobObjectW(
+// DWORD dwDesiredAccess,
+// BOOL bInheritHandle,
+// LPCWSTR lpName
+// );
+//
+//sys OpenJobObject(desiredAccess uint32, inheritHandle bool, lpName *uint16) (handle windows.Handle, err error) = kernel32.OpenJobObjectW
+
+// DWORD SetIoRateControlInformationJobObject(
+// HANDLE hJob,
+// JOBOBJECT_IO_RATE_CONTROL_INFORMATION *IoRateControlInfo
+// );
+//
+//sys SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateControlInfo *JOBOBJECT_IO_RATE_CONTROL_INFORMATION) (ret uint32, err error) = kernel32.SetIoRateControlInformationJobObject
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/logon.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/logon.go
new file mode 100644
index 000000000..b6e7cfd46
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/logon.go
@@ -0,0 +1,30 @@
+package winapi
+
+// BOOL LogonUserA(
+// LPCWSTR lpszUsername,
+// LPCWSTR lpszDomain,
+// LPCWSTR lpszPassword,
+// DWORD dwLogonType,
+// DWORD dwLogonProvider,
+// PHANDLE phToken
+// );
+//
+//sys LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) = advapi32.LogonUserW
+
+// Logon types
+const (
+ LOGON32_LOGON_INTERACTIVE uint32 = 2
+ LOGON32_LOGON_NETWORK uint32 = 3
+ LOGON32_LOGON_BATCH uint32 = 4
+ LOGON32_LOGON_SERVICE uint32 = 5
+ LOGON32_LOGON_UNLOCK uint32 = 7
+ LOGON32_LOGON_NETWORK_CLEARTEXT uint32 = 8
+ LOGON32_LOGON_NEW_CREDENTIALS uint32 = 9
+)
+
+// Logon providers
+const (
+ LOGON32_PROVIDER_DEFAULT uint32 = 0
+ LOGON32_PROVIDER_WINNT40 uint32 = 2
+ LOGON32_PROVIDER_WINNT50 uint32 = 3
+)
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/memory.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/memory.go
new file mode 100644
index 000000000..ccaf5a624
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/memory.go
@@ -0,0 +1,11 @@
+package winapi
+
+// VOID RtlMoveMemory(
+// _Out_ VOID UNALIGNED *Destination,
+// _In_ const VOID UNALIGNED *Source,
+// _In_ SIZE_T Length
+// );
+//sys RtlMoveMemory(destination *byte, source *byte, length uintptr) (err error) = kernel32.RtlMoveMemory
+
+//sys LocalAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc
+//sys LocalFree(ptr uintptr) = kernel32.LocalFree
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/net.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/net.go
new file mode 100644
index 000000000..f37910024
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/net.go
@@ -0,0 +1,3 @@
+package winapi
+
+//sys SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) = iphlpapi.SetJobCompartmentId
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/path.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/path.go
new file mode 100644
index 000000000..0ae8f33ea
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/path.go
@@ -0,0 +1,11 @@
+package winapi
+
+// DWORD SearchPathW(
+// LPCWSTR lpPath,
+// LPCWSTR lpFileName,
+// LPCWSTR lpExtension,
+// DWORD nBufferLength,
+// LPWSTR lpBuffer,
+// LPWSTR *lpFilePart
+// );
+//sys SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath **uint16) (size uint32, err error) = kernel32.SearchPathW
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go
new file mode 100644
index 000000000..adf0168ea
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go
@@ -0,0 +1,3 @@
+package winapi
+
+const PROCESS_ALL_ACCESS uint32 = 2097151
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/processor.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/processor.go
new file mode 100644
index 000000000..ce79ac2cd
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/processor.go
@@ -0,0 +1,7 @@
+package winapi
+
+// Get count from all processor groups.
+// https://docs.microsoft.com/en-us/windows/win32/procthread/processor-groups
+const ALL_PROCESSOR_GROUPS = 0xFFFF
+
+//sys GetActiveProcessorCount(groupNumber uint16) (amount uint32) = kernel32.GetActiveProcessorCount
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/utils.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/utils.go
new file mode 100644
index 000000000..f3055d417
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/utils.go
@@ -0,0 +1,60 @@
+package winapi
+
+import (
+ "errors"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+type UnicodeString struct {
+ Length uint16
+ MaximumLength uint16
+ Buffer *uint16
+}
+
+//String converts a UnicodeString to a golang string
+func (uni UnicodeString) String() string {
+ p := (*[0xffff]uint16)(unsafe.Pointer(uni.Buffer))
+
+ // UnicodeString is not guaranteed to be null terminated, therefore
+ // use the UnicodeString's Length field
+ lengthInChars := uni.Length / 2
+ return syscall.UTF16ToString(p[:lengthInChars])
+}
+
+// NewUnicodeString allocates a new UnicodeString and copies `s` into
+// the buffer of the new UnicodeString.
+func NewUnicodeString(s string) (*UnicodeString, error) {
+ ws := utf16.Encode(([]rune)(s))
+ if len(ws) > 32767 {
+ return nil, syscall.ENAMETOOLONG
+ }
+
+ uni := &UnicodeString{
+ Length: uint16(len(ws) * 2),
+ MaximumLength: uint16(len(ws) * 2),
+ Buffer: &make([]uint16, len(ws))[0],
+ }
+ copy((*[32768]uint16)(unsafe.Pointer(uni.Buffer))[:], ws)
+ return uni, nil
+}
+
+// ConvertStringSetToSlice is a helper function used to convert the contents of
+// `buf` into a string slice. `buf` contains a set of null terminated strings
+// with an additional null at the end to indicate the end of the set.
+func ConvertStringSetToSlice(buf []byte) ([]string, error) {
+ var results []string
+ prev := 0
+ for i := range buf {
+ if buf[i] == 0 {
+ if prev == i {
+ // found two null characters in a row, return result
+ return results, nil
+ }
+ results = append(results, string(buf[prev:i]))
+ prev = i + 1
+ }
+ }
+ return nil, errors.New("string set malformed: missing null terminator at end of buffer")
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go
new file mode 100644
index 000000000..77ea13e3e
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go
@@ -0,0 +1,5 @@
+// Package winapi contains various low-level bindings to Windows APIs. It can
+// be thought of as an extension to golang.org/x/sys/windows.
+package winapi
+
+//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go net.go iocp.go jobobject.go path.go logon.go memory.go processor.go devices.go filesystem.go errors.go
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
new file mode 100644
index 000000000..0a990951d
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
@@ -0,0 +1,294 @@
+// Code generated mksyscall_windows.exe DO NOT EDIT
+
+package winapi
+
+import (
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
+var (
+ modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
+ modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+ modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
+ modcfgmgr32 = windows.NewLazySystemDLL("cfgmgr32.dll")
+ modntdll = windows.NewLazySystemDLL("ntdll.dll")
+
+ procSetJobCompartmentId = modiphlpapi.NewProc("SetJobCompartmentId")
+ procIsProcessInJob = modkernel32.NewProc("IsProcessInJob")
+ procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject")
+ procOpenJobObjectW = modkernel32.NewProc("OpenJobObjectW")
+ procSetIoRateControlInformationJobObject = modkernel32.NewProc("SetIoRateControlInformationJobObject")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procSearchPathW = modkernel32.NewProc("SearchPathW")
+ procLogonUserW = modadvapi32.NewProc("LogonUserW")
+ procRtlMoveMemory = modkernel32.NewProc("RtlMoveMemory")
+ procLocalAlloc = modkernel32.NewProc("LocalAlloc")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount")
+ procCM_Get_Device_ID_List_SizeA = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA")
+ procCM_Get_Device_ID_ListA = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA")
+ procCM_Locate_DevNodeW = modcfgmgr32.NewProc("CM_Locate_DevNodeW")
+ procCM_Get_DevNode_PropertyW = modcfgmgr32.NewProc("CM_Get_DevNode_PropertyW")
+ procNtCreateFile = modntdll.NewProc("NtCreateFile")
+ procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
+ procNtOpenDirectoryObject = modntdll.NewProc("NtOpenDirectoryObject")
+ procNtQueryDirectoryObject = modntdll.NewProc("NtQueryDirectoryObject")
+ procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError")
+)
+
+func SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) {
+ r0, _, _ := syscall.Syscall(procSetJobCompartmentId.Addr(), 2, uintptr(handle), uintptr(compartmentId), 0)
+ if r0 != 0 {
+ win32Err = syscall.Errno(r0)
+ }
+ return
+}
+
+func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *bool) (err error) {
+ r1, _, e1 := syscall.Syscall(procIsProcessInJob.Addr(), 3, uintptr(procHandle), uintptr(jobHandle), uintptr(unsafe.Pointer(result)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(jobHandle), uintptr(infoClass), uintptr(jobObjectInfo), uintptr(jobObjectInformationLength), uintptr(unsafe.Pointer(lpReturnLength)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenJobObject(desiredAccess uint32, inheritHandle bool, lpName *uint16) (handle windows.Handle, err error) {
+ var _p0 uint32
+ if inheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := syscall.Syscall(procOpenJobObjectW.Addr(), 3, uintptr(desiredAccess), uintptr(_p0), uintptr(unsafe.Pointer(lpName)))
+ handle = windows.Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateControlInfo *JOBOBJECT_IO_RATE_CONTROL_INFORMATION) (ret uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procSetIoRateControlInformationJobObject.Addr(), 2, uintptr(jobHandle), uintptr(unsafe.Pointer(ioRateControlInfo)), 0)
+ ret = uint32(r0)
+ if ret == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath **uint16) (size uint32, err error) {
+ r0, _, e1 := syscall.Syscall6(procSearchPathW.Addr(), 6, uintptr(unsafe.Pointer(lpPath)), uintptr(unsafe.Pointer(lpFileName)), uintptr(unsafe.Pointer(lpExtension)), uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), uintptr(unsafe.Pointer(lpFilePath)))
+ size = uint32(r0)
+ if size == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) {
+ r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonType), uintptr(logonProvider), uintptr(unsafe.Pointer(token)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func RtlMoveMemory(destination *byte, source *byte, length uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procRtlMoveMemory.Addr(), 3, uintptr(unsafe.Pointer(destination)), uintptr(unsafe.Pointer(source)), uintptr(length))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LocalAlloc(flags uint32, size int) (ptr uintptr) {
+ r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0)
+ ptr = uintptr(r0)
+ return
+}
+
+func LocalFree(ptr uintptr) {
+ syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0)
+ return
+}
+
+func GetActiveProcessorCount(groupNumber uint16) (amount uint32) {
+ r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0)
+ amount = uint32(r0)
+ return
+}
+
+func CMGetDeviceIDListSize(pulLen *uint32, pszFilter *byte, uFlags uint32) (hr error) {
+ r0, _, _ := syscall.Syscall(procCM_Get_Device_ID_List_SizeA.Addr(), 3, uintptr(unsafe.Pointer(pulLen)), uintptr(unsafe.Pointer(pszFilter)), uintptr(uFlags))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func CMGetDeviceIDList(pszFilter *byte, buffer *byte, bufferLen uint32, uFlags uint32) (hr error) {
+ r0, _, _ := syscall.Syscall6(procCM_Get_Device_ID_ListA.Addr(), 4, uintptr(unsafe.Pointer(pszFilter)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(uFlags), 0, 0)
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func CMLocateDevNode(pdnDevInst *uint32, pDeviceID string, uFlags uint32) (hr error) {
+ var _p0 *uint16
+ _p0, hr = syscall.UTF16PtrFromString(pDeviceID)
+ if hr != nil {
+ return
+ }
+ return _CMLocateDevNode(pdnDevInst, _p0, uFlags)
+}
+
+func _CMLocateDevNode(pdnDevInst *uint32, pDeviceID *uint16, uFlags uint32) (hr error) {
+ r0, _, _ := syscall.Syscall(procCM_Locate_DevNodeW.Addr(), 3, uintptr(unsafe.Pointer(pdnDevInst)), uintptr(unsafe.Pointer(pDeviceID)), uintptr(uFlags))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func CMGetDevNodeProperty(dnDevInst uint32, propertyKey *DevPropKey, propertyType *uint32, propertyBuffer *uint16, propertyBufferSize *uint32, uFlags uint32) (hr error) {
+ r0, _, _ := syscall.Syscall6(procCM_Get_DevNode_PropertyW.Addr(), 6, uintptr(dnDevInst), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(unsafe.Pointer(propertyBufferSize)), uintptr(uFlags))
+ if int32(r0) < 0 {
+ if r0&0x1fff0000 == 0x00070000 {
+ r0 &= 0xffff
+ }
+ hr = syscall.Errno(r0)
+ }
+ return
+}
+
+func NtCreateFile(handle *uintptr, accessMask uint32, oa *ObjectAttributes, iosb *IOStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) {
+ r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0)
+ status = uint32(r0)
+ return
+}
+
+func NtSetInformationFile(handle uintptr, iosb *IOStatusBlock, information uintptr, length uint32, class uint32) (status uint32) {
+ r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0)
+ status = uint32(r0)
+ return
+}
+
+func NtOpenDirectoryObject(handle *uintptr, accessMask uint32, oa *ObjectAttributes) (status uint32) {
+ r0, _, _ := syscall.Syscall(procNtOpenDirectoryObject.Addr(), 3, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)))
+ status = uint32(r0)
+ return
+}
+
+func NtQueryDirectoryObject(handle uintptr, buffer *byte, length uint32, singleEntry bool, restartScan bool, context *uint32, returnLength *uint32) (status uint32) {
+ var _p0 uint32
+ if singleEntry {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ var _p1 uint32
+ if restartScan {
+ _p1 = 1
+ } else {
+ _p1 = 0
+ }
+ r0, _, _ := syscall.Syscall9(procNtQueryDirectoryObject.Addr(), 7, uintptr(handle), uintptr(unsafe.Pointer(buffer)), uintptr(length), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(returnLength)), 0, 0)
+ status = uint32(r0)
+ return
+}
+
+func RtlNtStatusToDosError(status uint32) (winerr error) {
+ r0, _, _ := syscall.Syscall(procRtlNtStatusToDosError.Addr(), 1, uintptr(status), 0, 0)
+ if r0 != 0 {
+ winerr = syscall.Errno(r0)
+ }
+ return
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go b/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
index 726d1c8c1..e9267b955 100644
--- a/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
+++ b/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
@@ -24,4 +24,15 @@ const (
// V19H1 (version 1903) corresponds to Windows Server 1903 (semi-annual
// channel).
V19H1 = 18362
+
+ // V19H2 (version 1909) corresponds to Windows Server 1909 (semi-annual
+ // channel).
+ V19H2 = 18363
+
+ // V20H1 (version 2004) corresponds to Windows Server 2004 (semi-annual
+ // channel).
+ V20H1 = 19041
+
+ // V20H2 corresponds to Windows Server 20H2 (semi-annual channel).
+ V20H2 = 19042
)
diff --git a/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go b/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
index c7884e8ef..713376d5e 100644
--- a/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
+++ b/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
@@ -32,6 +32,7 @@ type Metrics struct {
Blkio *BlkIOStat `protobuf:"bytes,5,opt,name=blkio,proto3" json:"blkio,omitempty"`
Rdma *RdmaStat `protobuf:"bytes,6,opt,name=rdma,proto3" json:"rdma,omitempty"`
Network []*NetworkStat `protobuf:"bytes,7,rep,name=network,proto3" json:"network,omitempty"`
+ CgroupStats *CgroupStats `protobuf:"bytes,8,opt,name=cgroup_stats,json=cgroupStats,proto3" json:"cgroup_stats,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -608,6 +609,55 @@ func (m *NetworkStat) XXX_DiscardUnknown() {
var xxx_messageInfo_NetworkStat proto.InternalMessageInfo
+// CgroupStats exports per-cgroup statistics.
+type CgroupStats struct {
+ // number of tasks sleeping
+ NrSleeping uint64 `protobuf:"varint,1,opt,name=nr_sleeping,json=nrSleeping,proto3" json:"nr_sleeping,omitempty"`
+ // number of tasks running
+ NrRunning uint64 `protobuf:"varint,2,opt,name=nr_running,json=nrRunning,proto3" json:"nr_running,omitempty"`
+ // number of tasks in stopped state
+ NrStopped uint64 `protobuf:"varint,3,opt,name=nr_stopped,json=nrStopped,proto3" json:"nr_stopped,omitempty"`
+ // number of tasks in uninterruptible state
+ NrUninterruptible uint64 `protobuf:"varint,4,opt,name=nr_uninterruptible,json=nrUninterruptible,proto3" json:"nr_uninterruptible,omitempty"`
+ // number of tasks waiting on IO
+ NrIoWait uint64 `protobuf:"varint,5,opt,name=nr_io_wait,json=nrIoWait,proto3" json:"nr_io_wait,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CgroupStats) Reset() { *m = CgroupStats{} }
+func (*CgroupStats) ProtoMessage() {}
+func (*CgroupStats) Descriptor() ([]byte, []int) {
+ return fileDescriptor_a17b2d87c332bfaa, []int{13}
+}
+func (m *CgroupStats) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *CgroupStats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CgroupStats.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *CgroupStats) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CgroupStats.Merge(m, src)
+}
+func (m *CgroupStats) XXX_Size() int {
+ return m.Size()
+}
+func (m *CgroupStats) XXX_DiscardUnknown() {
+ xxx_messageInfo_CgroupStats.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CgroupStats proto.InternalMessageInfo
+
func init() {
proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v1.Metrics")
proto.RegisterType((*HugetlbStat)(nil), "io.containerd.cgroups.v1.HugetlbStat")
@@ -622,6 +672,7 @@ func init() {
proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v1.RdmaStat")
proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v1.RdmaEntry")
proto.RegisterType((*NetworkStat)(nil), "io.containerd.cgroups.v1.NetworkStat")
+ proto.RegisterType((*CgroupStats)(nil), "io.containerd.cgroups.v1.CgroupStats")
}
func init() {
@@ -629,105 +680,112 @@ func init() {
}
var fileDescriptor_a17b2d87c332bfaa = []byte{
- // 1558 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0xcf, 0x73, 0x13, 0x39,
- 0x16, 0xc6, 0xb1, 0x13, 0xbb, 0x9f, 0x93, 0x90, 0x28, 0x10, 0x3a, 0x01, 0xe2, 0xe0, 0x24, 0xbb,
- 0xd9, 0xa5, 0xca, 0x29, 0xd8, 0x2d, 0x6a, 0x61, 0xa1, 0xb6, 0x70, 0x80, 0x82, 0xda, 0xcd, 0x62,
- 0xda, 0x49, 0xb1, 0x7b, 0xea, 0x92, 0xdb, 0xa2, 0xad, 0xc4, 0x6e, 0x35, 0x6a, 0xb5, 0xe3, 0xcc,
- 0x69, 0x0e, 0x53, 0x35, 0xa7, 0xf9, 0x67, 0xe6, 0xaf, 0xe0, 0x38, 0x97, 0xa9, 0x9a, 0xb9, 0xa4,
- 0x06, 0xff, 0x25, 0x53, 0x92, 0xfa, 0x87, 0x0c, 0x84, 0x8c, 0x6f, 0x2d, 0xe9, 0xfb, 0xbe, 0xf7,
- 0xf4, 0xfa, 0x53, 0xeb, 0x35, 0xfc, 0xdd, 0xa7, 0xa2, 0x17, 0x77, 0x1a, 0x1e, 0x1b, 0xec, 0x79,
- 0x2c, 0x10, 0x98, 0x06, 0x84, 0x77, 0xf7, 0x3c, 0x9f, 0xb3, 0x38, 0x8c, 0xf6, 0x22, 0x81, 0x45,
- 0xb4, 0x37, 0xbc, 0xb7, 0x37, 0x20, 0x82, 0x53, 0x2f, 0x6a, 0x84, 0x9c, 0x09, 0x86, 0x6c, 0xca,
- 0x1a, 0x39, 0xba, 0x91, 0xa0, 0x1b, 0xc3, 0x7b, 0xeb, 0xd7, 0x7c, 0xe6, 0x33, 0x05, 0xda, 0x93,
- 0x4f, 0x1a, 0x5f, 0xff, 0xb1, 0x08, 0xe5, 0x03, 0xad, 0x80, 0xfe, 0x05, 0xe5, 0x5e, 0xec, 0x13,
- 0xd1, 0xef, 0xd8, 0x85, 0xcd, 0xe2, 0x6e, 0xf5, 0xfe, 0x4e, 0xe3, 0x22, 0xb5, 0xc6, 0x4b, 0x0d,
- 0x6c, 0x0b, 0x2c, 0x9c, 0x94, 0x85, 0x1e, 0x40, 0x29, 0xa4, 0xdd, 0xc8, 0x9e, 0xd9, 0x2c, 0xec,
- 0x56, 0xef, 0xd7, 0x2f, 0x66, 0xb7, 0x68, 0x37, 0x52, 0x54, 0x85, 0x47, 0x8f, 0xa1, 0xe8, 0x85,
- 0xb1, 0x5d, 0x54, 0xb4, 0x3b, 0x17, 0xd3, 0xf6, 0x5b, 0x47, 0x92, 0xd5, 0x2c, 0x8f, 0xcf, 0x6b,
- 0xc5, 0xfd, 0xd6, 0x91, 0x23, 0x69, 0xe8, 0x31, 0xcc, 0x0d, 0xc8, 0x80, 0xf1, 0x33, 0xbb, 0xa4,
- 0x04, 0xb6, 0x2f, 0x16, 0x38, 0x50, 0x38, 0x15, 0x39, 0xe1, 0xa0, 0x87, 0x30, 0xdb, 0xe9, 0x9f,
- 0x50, 0x66, 0xcf, 0x2a, 0xf2, 0xd6, 0xc5, 0xe4, 0x66, 0xff, 0xe4, 0xd5, 0x6b, 0xc5, 0xd5, 0x0c,
- 0xb9, 0x5d, 0xde, 0x1d, 0x60, 0x7b, 0xee, 0xb2, 0xed, 0x3a, 0xdd, 0x01, 0xd6, 0xdb, 0x95, 0x78,
- 0x59, 0xe7, 0x80, 0x88, 0x53, 0xc6, 0x4f, 0xec, 0xf2, 0x65, 0x75, 0xfe, 0xaf, 0x06, 0xea, 0x3a,
- 0x27, 0xac, 0xfa, 0x09, 0x54, 0x8d, 0xfa, 0xa3, 0x6b, 0x30, 0x1b, 0x47, 0xd8, 0x27, 0x76, 0x61,
- 0xb3, 0xb0, 0x5b, 0x72, 0xf4, 0x00, 0x2d, 0x41, 0x71, 0x80, 0x47, 0xea, 0x5d, 0x94, 0x1c, 0xf9,
- 0x88, 0x6c, 0x28, 0xbf, 0xc3, 0xb4, 0xef, 0x05, 0x42, 0x95, 0xba, 0xe4, 0xa4, 0x43, 0xb4, 0x0e,
- 0x95, 0x10, 0xfb, 0x24, 0xa2, 0xdf, 0x10, 0x55, 0x44, 0xcb, 0xc9, 0xc6, 0xf5, 0x47, 0x50, 0x49,
- 0x5f, 0x97, 0x54, 0xf0, 0x62, 0xce, 0x49, 0x20, 0x92, 0x58, 0xe9, 0x50, 0xe6, 0xd0, 0xa7, 0x03,
- 0x2a, 0x92, 0x78, 0x7a, 0x50, 0xff, 0xbe, 0x00, 0xe5, 0xe4, 0xa5, 0xa1, 0x7f, 0x98, 0x59, 0x7e,
- 0xb5, 0x5c, 0xfb, 0xad, 0xa3, 0x23, 0x89, 0x4c, 0x77, 0xd2, 0x04, 0x10, 0x3d, 0xce, 0x84, 0xe8,
- 0xd3, 0xc0, 0xbf, 0xdc, 0x5c, 0x87, 0x1a, 0x4b, 0x1c, 0x83, 0x55, 0x7f, 0x0f, 0x95, 0x54, 0x56,
- 0xe6, 0x2a, 0x98, 0xc0, 0xfd, 0xb4, 0x5e, 0x6a, 0x80, 0x56, 0x61, 0xee, 0x84, 0xf0, 0x80, 0xf4,
- 0x93, 0x2d, 0x24, 0x23, 0x84, 0xa0, 0x14, 0x47, 0x84, 0x27, 0x25, 0x53, 0xcf, 0x68, 0x0b, 0xca,
- 0x21, 0xe1, 0xae, 0x34, 0x6d, 0x69, 0xb3, 0xb8, 0x5b, 0x6a, 0xc2, 0xf8, 0xbc, 0x36, 0xd7, 0x22,
- 0x5c, 0x9a, 0x72, 0x2e, 0x24, 0x7c, 0x3f, 0x8c, 0xeb, 0x23, 0xa8, 0xa4, 0xa9, 0xc8, 0xc2, 0x85,
- 0x84, 0x53, 0xd6, 0x8d, 0xd2, 0xc2, 0x25, 0x43, 0x74, 0x17, 0x96, 0x93, 0x34, 0x49, 0xd7, 0x4d,
- 0x31, 0x3a, 0x83, 0xa5, 0x6c, 0xa1, 0x95, 0x80, 0x77, 0x60, 0x31, 0x07, 0x0b, 0x3a, 0x20, 0x49,
- 0x56, 0x0b, 0xd9, 0xec, 0x21, 0x1d, 0x90, 0xfa, 0xaf, 0x55, 0x80, 0xdc, 0xea, 0x72, 0xbf, 0x1e,
- 0xf6, 0x7a, 0x99, 0x3f, 0xd4, 0x00, 0xad, 0x41, 0x91, 0x47, 0x49, 0x28, 0x7d, 0xa2, 0x9c, 0x76,
- 0xdb, 0x91, 0x73, 0xe8, 0x4f, 0x50, 0xe1, 0x51, 0xe4, 0xca, 0x63, 0xad, 0x03, 0x34, 0xab, 0xe3,
- 0xf3, 0x5a, 0xd9, 0x69, 0xb7, 0xa5, 0xed, 0x9c, 0x32, 0x8f, 0x22, 0xf9, 0x80, 0x6a, 0x50, 0x1d,
- 0xe0, 0x30, 0x24, 0x5d, 0xf7, 0x1d, 0xed, 0x6b, 0xe7, 0x94, 0x1c, 0xd0, 0x53, 0x2f, 0x68, 0x5f,
- 0x55, 0xba, 0x4b, 0xb9, 0x38, 0x53, 0x87, 0xab, 0xe4, 0xe8, 0x01, 0xba, 0x05, 0xd6, 0x29, 0xa7,
- 0x82, 0x74, 0xb0, 0x77, 0xa2, 0x0e, 0x4f, 0xc9, 0xc9, 0x27, 0x90, 0x0d, 0x95, 0xd0, 0x77, 0x43,
- 0xdf, 0xa5, 0x81, 0x5d, 0xd6, 0x6f, 0x22, 0xf4, 0x5b, 0xfe, 0xab, 0x00, 0xad, 0x83, 0xa5, 0x57,
- 0x58, 0x2c, 0xec, 0x4a, 0x52, 0x46, 0xbf, 0xe5, 0xbf, 0x8e, 0x05, 0x5a, 0x53, 0xac, 0x77, 0x38,
- 0xee, 0x0b, 0xdb, 0x4a, 0x97, 0x5e, 0xc8, 0x21, 0xda, 0x84, 0xf9, 0xd0, 0x77, 0x07, 0xf8, 0x38,
- 0x59, 0x06, 0x9d, 0x66, 0xe8, 0x1f, 0xe0, 0x63, 0x8d, 0xd8, 0x82, 0x05, 0x1a, 0x60, 0x4f, 0xd0,
- 0x21, 0x71, 0x71, 0xc0, 0x02, 0xbb, 0xaa, 0x20, 0xf3, 0xe9, 0xe4, 0xd3, 0x80, 0x05, 0x72, 0xb3,
- 0x26, 0x64, 0x5e, 0xab, 0x18, 0x00, 0x53, 0x45, 0xd5, 0x63, 0x61, 0x52, 0x45, 0x55, 0x24, 0x57,
- 0x51, 0x90, 0x45, 0x53, 0x45, 0x01, 0x36, 0xa1, 0x1a, 0x07, 0x64, 0x48, 0x3d, 0x81, 0x3b, 0x7d,
- 0x62, 0x5f, 0x55, 0x00, 0x73, 0x0a, 0x3d, 0x82, 0xb5, 0x1e, 0x25, 0x1c, 0x73, 0xaf, 0x47, 0x3d,
- 0xdc, 0x77, 0xf5, 0x87, 0xcc, 0xd5, 0xc7, 0x6f, 0x49, 0xe1, 0x6f, 0x98, 0x00, 0xed, 0x84, 0xff,
- 0xc8, 0x65, 0xf4, 0x00, 0x26, 0x96, 0xdc, 0xe8, 0x14, 0x87, 0x09, 0x73, 0x59, 0x31, 0xaf, 0x9b,
- 0xcb, 0xed, 0x53, 0x1c, 0x6a, 0x5e, 0x0d, 0xaa, 0xea, 0x94, 0xb8, 0xda, 0x48, 0x48, 0xa7, 0xad,
- 0xa6, 0xf6, 0x95, 0x9b, 0xfe, 0x02, 0x96, 0x06, 0x48, 0x4f, 0xad, 0x28, 0xcf, 0xcc, 0x8f, 0xcf,
- 0x6b, 0x95, 0x43, 0x39, 0x29, 0x8d, 0x55, 0x51, 0xcb, 0x4e, 0x14, 0xa1, 0x07, 0xb0, 0x98, 0x41,
- 0xb5, 0xc7, 0xae, 0x29, 0xfc, 0xd2, 0xf8, 0xbc, 0x36, 0x9f, 0xe2, 0x95, 0xd1, 0xe6, 0x53, 0x8e,
- 0x72, 0xdb, 0x5f, 0x61, 0x59, 0xf3, 0x4c, 0xcf, 0x5d, 0x57, 0x99, 0x5c, 0x55, 0x0b, 0x07, 0xb9,
- 0xf1, 0xb2, 0x7c, 0xb5, 0xfd, 0x56, 0x8d, 0x7c, 0x9f, 0x29, 0x0f, 0xfe, 0x19, 0x34, 0xc7, 0xcd,
- 0x9d, 0x78, 0x43, 0x81, 0x74, 0x6e, 0x6f, 0x33, 0x3b, 0x6e, 0xa5, 0xd9, 0x66, 0xa6, 0xb4, 0xf5,
- 0x2b, 0x51, 0xb3, 0x2d, 0xed, 0xcc, 0x9d, 0x54, 0x2d, 0xf7, 0xe7, 0x9a, 0x7e, 0xf9, 0x19, 0x4a,
- 0x9a, 0x74, 0xdb, 0xd0, 0xd2, 0x5e, 0x5c, 0x9f, 0x40, 0x69, 0x37, 0xde, 0x05, 0x94, 0xa1, 0x72,
- 0xd7, 0xde, 0x34, 0x36, 0xda, 0xca, 0xad, 0xdb, 0x80, 0x15, 0x0d, 0x9e, 0x34, 0xf0, 0x2d, 0x85,
- 0xd6, 0xf5, 0x7a, 0x65, 0xba, 0x38, 0x2b, 0xa2, 0x89, 0xbe, 0x6d, 0x68, 0x3f, 0xcd, 0xb1, 0x9f,
- 0x6b, 0xab, 0x92, 0x6f, 0x7c, 0x41, 0x5b, 0x15, 0xfd, 0x53, 0x6d, 0x85, 0xae, 0x7d, 0xa6, 0xad,
- 0xb0, 0x77, 0x53, 0xac, 0x69, 0xf6, 0xcd, 0xe4, 0xb3, 0x27, 0x17, 0x8e, 0x0c, 0xc7, 0xff, 0x33,
- 0xbd, 0x3a, 0xee, 0xa8, 0x6f, 0xff, 0xce, 0x65, 0x17, 0xfc, 0xf3, 0x40, 0xf0, 0xb3, 0xf4, 0xf6,
- 0x78, 0x08, 0x25, 0xe9, 0x72, 0xbb, 0x3e, 0x0d, 0x57, 0x51, 0xd0, 0x93, 0xec, 0x4a, 0xd8, 0x9a,
- 0x86, 0x9c, 0xde, 0x1c, 0x6d, 0x00, 0xfd, 0xe4, 0x0a, 0x2f, 0xb4, 0xb7, 0xa7, 0x90, 0x68, 0x2e,
- 0x8c, 0xcf, 0x6b, 0xd6, 0xbf, 0x15, 0xf9, 0x70, 0xbf, 0xe5, 0x58, 0x5a, 0xe7, 0xd0, 0x0b, 0xeb,
- 0x04, 0xaa, 0x06, 0x30, 0xbf, 0x77, 0x0b, 0xc6, 0xbd, 0x9b, 0x77, 0x04, 0x33, 0x5f, 0xe8, 0x08,
- 0x8a, 0x5f, 0xec, 0x08, 0x4a, 0x13, 0x1d, 0x41, 0xfd, 0xe7, 0x59, 0xb0, 0xb2, 0x86, 0x07, 0x61,
- 0x58, 0xa7, 0xcc, 0x8d, 0x08, 0x1f, 0x52, 0x8f, 0xb8, 0x9d, 0x33, 0x41, 0x22, 0x97, 0x13, 0x2f,
- 0xe6, 0x11, 0x1d, 0x92, 0xa4, 0x59, 0xdc, 0xbe, 0xa4, 0x73, 0xd2, 0xb5, 0xb9, 0x41, 0x59, 0x5b,
- 0xcb, 0x34, 0xa5, 0x8a, 0x93, 0x8a, 0xa0, 0xff, 0xc1, 0xf5, 0x3c, 0x44, 0xd7, 0x50, 0x9f, 0x99,
- 0x42, 0x7d, 0x25, 0x53, 0xef, 0xe6, 0xca, 0x87, 0xb0, 0x42, 0x99, 0xfb, 0x3e, 0x26, 0xf1, 0x84,
- 0x6e, 0x71, 0x0a, 0xdd, 0x65, 0xca, 0xde, 0x28, 0x7e, 0xae, 0xea, 0xc2, 0x9a, 0x51, 0x12, 0x79,
- 0x17, 0x1b, 0xda, 0xa5, 0x29, 0xb4, 0x57, 0xb3, 0x9c, 0xe5, 0xdd, 0x9d, 0x07, 0xf8, 0x3f, 0xac,
- 0x52, 0xe6, 0x9e, 0x62, 0x2a, 0x3e, 0x55, 0x9f, 0x9d, 0xae, 0x22, 0x6f, 0x31, 0x15, 0x93, 0xd2,
- 0xba, 0x22, 0x03, 0xc2, 0xfd, 0x89, 0x8a, 0xcc, 0x4d, 0x57, 0x91, 0x03, 0xc5, 0xcf, 0x55, 0x5b,
- 0xb0, 0x4c, 0xd9, 0xa7, 0xb9, 0x96, 0xa7, 0xd0, 0xbc, 0x4a, 0xd9, 0x64, 0x9e, 0x6f, 0x60, 0x39,
- 0x22, 0x9e, 0x60, 0xdc, 0x74, 0x5b, 0x65, 0x0a, 0xc5, 0xa5, 0x84, 0x9e, 0x49, 0xd6, 0x87, 0x00,
- 0xf9, 0x3a, 0x5a, 0x84, 0x19, 0x16, 0xaa, 0xa3, 0x63, 0x39, 0x33, 0x2c, 0x94, 0x3d, 0x60, 0x57,
- 0x7e, 0x76, 0xf4, 0xc1, 0xb1, 0x9c, 0x64, 0x24, 0xcf, 0xd3, 0x00, 0x1f, 0xb3, 0xb4, 0x09, 0xd4,
- 0x03, 0x35, 0x4b, 0x03, 0xc6, 0x93, 0xb3, 0xa3, 0x07, 0x72, 0x76, 0x88, 0xfb, 0x31, 0x49, 0x7b,
- 0x1e, 0x35, 0xa8, 0x7f, 0x57, 0x80, 0x4a, 0xfa, 0x1b, 0x80, 0x9e, 0x98, 0x6d, 0x74, 0xf1, 0xeb,
- 0x7f, 0x1d, 0x92, 0xa4, 0x37, 0x93, 0xf5, 0xda, 0x0f, 0xf3, 0x5e, 0xfb, 0x0f, 0x93, 0x93, 0x86,
- 0x9c, 0x80, 0x95, 0xcd, 0x19, 0xbb, 0x2d, 0x4c, 0xec, 0xb6, 0x06, 0xd5, 0x9e, 0x87, 0xdd, 0x1e,
- 0x0e, 0xba, 0x7d, 0xa2, 0x3b, 0xc4, 0x05, 0x07, 0x7a, 0x1e, 0x7e, 0xa9, 0x67, 0x52, 0x00, 0xeb,
- 0x1c, 0x13, 0x4f, 0x44, 0xaa, 0x28, 0x1a, 0xf0, 0x5a, 0xcf, 0xd4, 0x7f, 0x98, 0x81, 0xaa, 0xf1,
- 0xe7, 0x22, 0x7b, 0xe8, 0x00, 0x0f, 0xd2, 0x38, 0xea, 0x59, 0x76, 0x6c, 0x7c, 0xa4, 0xbf, 0x25,
- 0xc9, 0x67, 0xaa, 0xcc, 0x47, 0xea, 0xa3, 0x80, 0x6e, 0x03, 0xf0, 0x91, 0x1b, 0x62, 0xef, 0x84,
- 0x24, 0xf2, 0x25, 0xc7, 0xe2, 0xa3, 0x96, 0x9e, 0x40, 0x37, 0xc1, 0xe2, 0x23, 0x97, 0x70, 0xce,
- 0x78, 0x94, 0xd4, 0xbe, 0xc2, 0x47, 0xcf, 0xd5, 0x38, 0xe1, 0x76, 0x39, 0x93, 0xbd, 0x40, 0xf2,
- 0x0e, 0x2c, 0x3e, 0x7a, 0xa6, 0x27, 0x64, 0x54, 0x91, 0x46, 0xd5, 0xad, 0x67, 0x59, 0xe4, 0x51,
- 0x45, 0x1e, 0x55, 0xb7, 0x9e, 0x96, 0x30, 0xa3, 0x8a, 0x2c, 0xaa, 0xee, 0x3e, 0x2b, 0xc2, 0x88,
- 0x2a, 0xf2, 0xa8, 0x56, 0xca, 0x4d, 0xa2, 0x36, 0xed, 0x0f, 0x1f, 0x37, 0xae, 0xfc, 0xf2, 0x71,
- 0xe3, 0xca, 0xb7, 0xe3, 0x8d, 0xc2, 0x87, 0xf1, 0x46, 0xe1, 0xa7, 0xf1, 0x46, 0xe1, 0xb7, 0xf1,
- 0x46, 0xa1, 0x33, 0xa7, 0x7e, 0xc3, 0xff, 0xf6, 0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2f, 0xc0,
- 0x49, 0x92, 0xee, 0x0f, 0x00, 0x00,
+ // 1669 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4f, 0x73, 0x1b, 0xb7,
+ 0x15, 0x0f, 0xc5, 0x95, 0xc8, 0x7d, 0x94, 0x6c, 0x09, 0xfe, 0xb7, 0x52, 0x1c, 0x51, 0xa1, 0xec,
+ 0xd6, 0xad, 0xa7, 0xd2, 0x24, 0xed, 0x78, 0xea, 0x34, 0x99, 0x4e, 0xa4, 0x24, 0x63, 0x4f, 0xab,
+ 0x9a, 0x59, 0x4a, 0x93, 0xf6, 0xb4, 0x03, 0x2e, 0xe1, 0x25, 0xac, 0xe5, 0x62, 0x83, 0xc5, 0x52,
+ 0x74, 0x4f, 0x3d, 0x74, 0xa6, 0xa7, 0x7e, 0xa0, 0x7e, 0x83, 0x1c, 0x7b, 0xe9, 0x4c, 0x7b, 0xd1,
+ 0x34, 0xfc, 0x1c, 0x3d, 0x74, 0x80, 0x87, 0xfd, 0x43, 0xc7, 0xb2, 0xc2, 0xdb, 0xe2, 0xe1, 0xf7,
+ 0x7e, 0xef, 0xe1, 0xe1, 0x07, 0xe0, 0x91, 0xf0, 0xab, 0x88, 0xab, 0x71, 0x3e, 0x3c, 0x08, 0xc5,
+ 0xe4, 0x30, 0x14, 0x89, 0xa2, 0x3c, 0x61, 0x72, 0x74, 0x18, 0x46, 0x52, 0xe4, 0x69, 0x76, 0x98,
+ 0x29, 0xaa, 0xb2, 0xc3, 0xe9, 0x47, 0x87, 0x13, 0xa6, 0x24, 0x0f, 0xb3, 0x83, 0x54, 0x0a, 0x25,
+ 0x88, 0xc7, 0xc5, 0x41, 0x85, 0x3e, 0xb0, 0xe8, 0x83, 0xe9, 0x47, 0x3b, 0xb7, 0x23, 0x11, 0x09,
+ 0x03, 0x3a, 0xd4, 0x5f, 0x88, 0xef, 0xfd, 0xaf, 0x09, 0xad, 0x13, 0x64, 0x20, 0xbf, 0x85, 0xd6,
+ 0x38, 0x8f, 0x98, 0x8a, 0x87, 0x5e, 0x63, 0xaf, 0xf9, 0xa8, 0xf3, 0xf1, 0xc3, 0x83, 0xab, 0xd8,
+ 0x0e, 0x9e, 0x21, 0x70, 0xa0, 0xa8, 0xf2, 0x0b, 0x2f, 0xf2, 0x04, 0x9c, 0x94, 0x8f, 0x32, 0x6f,
+ 0x65, 0xaf, 0xf1, 0xa8, 0xf3, 0x71, 0xef, 0x6a, 0xef, 0x3e, 0x1f, 0x65, 0xc6, 0xd5, 0xe0, 0xc9,
+ 0xa7, 0xd0, 0x0c, 0xd3, 0xdc, 0x6b, 0x1a, 0xb7, 0x0f, 0xaf, 0x76, 0x3b, 0xee, 0x9f, 0x69, 0xaf,
+ 0xa3, 0xd6, 0xfc, 0xb2, 0xdb, 0x3c, 0xee, 0x9f, 0xf9, 0xda, 0x8d, 0x7c, 0x0a, 0x6b, 0x13, 0x36,
+ 0x11, 0xf2, 0xb5, 0xe7, 0x18, 0x82, 0x07, 0x57, 0x13, 0x9c, 0x18, 0x9c, 0x89, 0x6c, 0x7d, 0xc8,
+ 0x53, 0x58, 0x1d, 0xc6, 0xe7, 0x5c, 0x78, 0xab, 0xc6, 0x79, 0xff, 0x6a, 0xe7, 0xa3, 0xf8, 0xfc,
+ 0xf9, 0x0b, 0xe3, 0x8b, 0x1e, 0x7a, 0xb9, 0x72, 0x34, 0xa1, 0xde, 0xda, 0x75, 0xcb, 0xf5, 0x47,
+ 0x13, 0x8a, 0xcb, 0xd5, 0x78, 0x5d, 0xe7, 0x84, 0xa9, 0x0b, 0x21, 0xcf, 0xbd, 0xd6, 0x75, 0x75,
+ 0xfe, 0x03, 0x02, 0xb1, 0xce, 0xd6, 0x8b, 0x3c, 0x83, 0x75, 0x84, 0x04, 0x46, 0x05, 0x5e, 0xdb,
+ 0x24, 0xf0, 0x0e, 0x96, 0x63, 0xf3, 0xa9, 0x49, 0x32, 0xbf, 0x13, 0x56, 0x83, 0xde, 0x39, 0x74,
+ 0x6a, 0x3b, 0x49, 0x6e, 0xc3, 0x6a, 0x9e, 0xd1, 0x88, 0x79, 0x8d, 0xbd, 0xc6, 0x23, 0xc7, 0xc7,
+ 0x01, 0xd9, 0x84, 0xe6, 0x84, 0xce, 0xcc, 0xae, 0x3a, 0xbe, 0xfe, 0x24, 0x1e, 0xb4, 0x5e, 0x52,
+ 0x1e, 0x87, 0x89, 0x32, 0x9b, 0xe6, 0xf8, 0xc5, 0x90, 0xec, 0x40, 0x3b, 0xa5, 0x11, 0xcb, 0xf8,
+ 0x9f, 0x99, 0xd9, 0x0e, 0xd7, 0x2f, 0xc7, 0xbd, 0x4f, 0xa0, 0x5d, 0x6c, 0xbc, 0x66, 0x08, 0x73,
+ 0x29, 0x59, 0xa2, 0x6c, 0xac, 0x62, 0xa8, 0x73, 0x88, 0xf9, 0x84, 0x2b, 0x1b, 0x0f, 0x07, 0xbd,
+ 0xbf, 0x35, 0xa0, 0x65, 0xb7, 0x9f, 0xfc, 0xba, 0x9e, 0xe5, 0x3b, 0x0b, 0x7f, 0xdc, 0x3f, 0x3b,
+ 0xd3, 0xc8, 0x62, 0x25, 0x47, 0x00, 0x6a, 0x2c, 0x85, 0x52, 0x31, 0x4f, 0xa2, 0xeb, 0x65, 0x7a,
+ 0x8a, 0x58, 0xe6, 0xd7, 0xbc, 0x7a, 0xdf, 0x42, 0xbb, 0xa0, 0xd5, 0xb9, 0x2a, 0xa1, 0x68, 0x5c,
+ 0xd4, 0xcb, 0x0c, 0xc8, 0x5d, 0x58, 0x3b, 0x67, 0x32, 0x61, 0xb1, 0x5d, 0x82, 0x1d, 0x11, 0x02,
+ 0x4e, 0x9e, 0x31, 0x69, 0x4b, 0x66, 0xbe, 0xc9, 0x3e, 0xb4, 0x52, 0x26, 0x03, 0x2d, 0x7f, 0x67,
+ 0xaf, 0xf9, 0xc8, 0x39, 0x82, 0xf9, 0x65, 0x77, 0xad, 0xcf, 0xa4, 0x96, 0xf7, 0x5a, 0xca, 0xe4,
+ 0x71, 0x9a, 0xf7, 0x66, 0xd0, 0x2e, 0x52, 0xd1, 0x85, 0x4b, 0x99, 0xe4, 0x62, 0x94, 0x15, 0x85,
+ 0xb3, 0x43, 0xf2, 0x18, 0xb6, 0x6c, 0x9a, 0x6c, 0x14, 0x14, 0x18, 0xcc, 0x60, 0xb3, 0x9c, 0xe8,
+ 0x5b, 0xf0, 0x43, 0xb8, 0x51, 0x81, 0x15, 0x9f, 0x30, 0x9b, 0xd5, 0x46, 0x69, 0x3d, 0xe5, 0x13,
+ 0xd6, 0xfb, 0x4f, 0x07, 0xa0, 0x3a, 0x34, 0x7a, 0xbd, 0x21, 0x0d, 0xc7, 0xa5, 0x3e, 0xcc, 0x80,
+ 0x6c, 0x43, 0x53, 0x66, 0x36, 0x14, 0x9e, 0x4d, 0x7f, 0x30, 0xf0, 0xb5, 0x8d, 0xfc, 0x04, 0xda,
+ 0x32, 0xcb, 0x02, 0x7d, 0x41, 0x60, 0x80, 0xa3, 0xce, 0xfc, 0xb2, 0xdb, 0xf2, 0x07, 0x03, 0x2d,
+ 0x3b, 0xbf, 0x25, 0xb3, 0x4c, 0x7f, 0x90, 0x2e, 0x74, 0x26, 0x34, 0x4d, 0xd9, 0x28, 0x78, 0xc9,
+ 0x63, 0x54, 0x8e, 0xe3, 0x03, 0x9a, 0xbe, 0xe2, 0xb1, 0xa9, 0xf4, 0x88, 0x4b, 0xf5, 0xda, 0x1c,
+ 0x53, 0xc7, 0xc7, 0x01, 0xb9, 0x0f, 0xee, 0x85, 0xe4, 0x8a, 0x0d, 0x69, 0x78, 0x6e, 0x8e, 0xa1,
+ 0xe3, 0x57, 0x06, 0xe2, 0x41, 0x3b, 0x8d, 0x82, 0x34, 0x0a, 0x78, 0xe2, 0xb5, 0x70, 0x27, 0xd2,
+ 0xa8, 0x1f, 0x3d, 0x4f, 0xc8, 0x0e, 0xb8, 0x38, 0x23, 0x72, 0x65, 0x4e, 0x8f, 0x2e, 0x63, 0xd4,
+ 0x8f, 0x5e, 0xe4, 0x8a, 0x6c, 0x1b, 0xaf, 0x97, 0x34, 0x8f, 0x95, 0xe7, 0x16, 0x53, 0x5f, 0xe9,
+ 0x21, 0xd9, 0x83, 0xf5, 0x34, 0x0a, 0x26, 0xf4, 0x95, 0x9d, 0x06, 0x4c, 0x33, 0x8d, 0x4e, 0xe8,
+ 0x2b, 0x44, 0xec, 0xc3, 0x06, 0x4f, 0x68, 0xa8, 0xf8, 0x94, 0x05, 0x34, 0x11, 0x89, 0xd7, 0x31,
+ 0x90, 0xf5, 0xc2, 0xf8, 0x79, 0x22, 0x12, 0xbd, 0xd8, 0x3a, 0x64, 0x1d, 0x59, 0x6a, 0x80, 0x3a,
+ 0x8b, 0xa9, 0xc7, 0xc6, 0x22, 0x8b, 0xa9, 0x48, 0xc5, 0x62, 0x20, 0x37, 0xea, 0x2c, 0x06, 0xb0,
+ 0x07, 0x9d, 0x3c, 0x61, 0x53, 0x1e, 0x2a, 0x3a, 0x8c, 0x99, 0x77, 0xd3, 0x00, 0xea, 0x26, 0xf2,
+ 0x09, 0x6c, 0x8f, 0x39, 0x93, 0x54, 0x86, 0x63, 0x1e, 0xd2, 0x38, 0xc0, 0x2b, 0x31, 0xc0, 0xe3,
+ 0xb7, 0x69, 0xf0, 0xf7, 0xea, 0x00, 0x54, 0xc2, 0xef, 0xf5, 0x34, 0x79, 0x02, 0x0b, 0x53, 0x41,
+ 0x76, 0x41, 0x53, 0xeb, 0xb9, 0x65, 0x3c, 0xef, 0xd4, 0xa7, 0x07, 0x17, 0x34, 0x45, 0xbf, 0x2e,
+ 0x74, 0xcc, 0x29, 0x09, 0x50, 0x48, 0x04, 0xd3, 0x36, 0xa6, 0x63, 0xa3, 0xa6, 0x9f, 0x81, 0x8b,
+ 0x00, 0xad, 0xa9, 0x5b, 0x46, 0x33, 0xeb, 0xf3, 0xcb, 0x6e, 0xfb, 0x54, 0x1b, 0xb5, 0xb0, 0xda,
+ 0x66, 0xda, 0xcf, 0x32, 0xf2, 0x04, 0x6e, 0x94, 0x50, 0xd4, 0xd8, 0x6d, 0x83, 0xdf, 0x9c, 0x5f,
+ 0x76, 0xd7, 0x0b, 0xbc, 0x11, 0xda, 0x7a, 0xe1, 0x63, 0xd4, 0xf6, 0x73, 0xd8, 0x42, 0xbf, 0xba,
+ 0xe6, 0xee, 0x98, 0x4c, 0x6e, 0x9a, 0x89, 0x93, 0x4a, 0x78, 0x65, 0xbe, 0x28, 0xbf, 0xbb, 0xb5,
+ 0x7c, 0xbf, 0x30, 0x1a, 0xfc, 0x29, 0xa0, 0x4f, 0x50, 0x29, 0xf1, 0x9e, 0x01, 0x61, 0x6e, 0xdf,
+ 0x94, 0x72, 0xdc, 0x2f, 0xb2, 0x2d, 0x45, 0xe9, 0xe1, 0x96, 0x18, 0x6b, 0x1f, 0x95, 0xf9, 0xb0,
+ 0x60, 0xab, 0xf4, 0xb9, 0x8d, 0x9b, 0x5f, 0xa2, 0xb4, 0x48, 0x1f, 0xd4, 0xb8, 0x50, 0x8b, 0x3b,
+ 0x0b, 0x28, 0x54, 0xe3, 0x63, 0x20, 0x25, 0xaa, 0x52, 0xed, 0xfb, 0xb5, 0x85, 0xf6, 0x2b, 0xe9,
+ 0x1e, 0xc0, 0x2d, 0x04, 0x2f, 0x0a, 0xf8, 0xbe, 0x41, 0x63, 0xbd, 0x9e, 0xd7, 0x55, 0x5c, 0x16,
+ 0xb1, 0x8e, 0xfe, 0xa0, 0xc6, 0xfd, 0x79, 0x85, 0xfd, 0x21, 0xb7, 0x29, 0xf9, 0xee, 0x5b, 0xb8,
+ 0x4d, 0xd1, 0xdf, 0xe4, 0x36, 0xe8, 0xee, 0x0f, 0xb8, 0x0d, 0xf6, 0x71, 0x81, 0xad, 0x8b, 0x7d,
+ 0xcf, 0x5e, 0x7b, 0x7a, 0xe2, 0xac, 0xa6, 0xf8, 0xdf, 0x14, 0x4f, 0xc7, 0x87, 0xd7, 0x3d, 0x99,
+ 0xa8, 0xf5, 0x2f, 0x13, 0x25, 0x5f, 0x17, 0xaf, 0xc7, 0x53, 0x70, 0xb4, 0xca, 0xbd, 0xde, 0x32,
+ 0xbe, 0xc6, 0x85, 0x7c, 0x56, 0x3e, 0x09, 0xfb, 0xcb, 0x38, 0x17, 0x2f, 0xc7, 0x00, 0x00, 0xbf,
+ 0x02, 0x15, 0xa6, 0xde, 0x83, 0x25, 0x28, 0x8e, 0x36, 0xe6, 0x97, 0x5d, 0xf7, 0x77, 0xc6, 0xf9,
+ 0xf4, 0xb8, 0xef, 0xbb, 0xc8, 0x73, 0x1a, 0xa6, 0x3d, 0x06, 0x9d, 0x1a, 0xb0, 0x7a, 0x77, 0x1b,
+ 0xb5, 0x77, 0xb7, 0xea, 0x08, 0x56, 0xde, 0xd2, 0x11, 0x34, 0xdf, 0xda, 0x11, 0x38, 0x0b, 0x1d,
+ 0x41, 0xef, 0x5f, 0xab, 0xe0, 0x96, 0xad, 0x13, 0xa1, 0xb0, 0xc3, 0x45, 0x90, 0x31, 0x39, 0xe5,
+ 0x21, 0x0b, 0x86, 0xaf, 0x15, 0xcb, 0x02, 0xc9, 0xc2, 0x5c, 0x66, 0x7c, 0xca, 0x6c, 0xdb, 0xf9,
+ 0xe0, 0x9a, 0x1e, 0x0c, 0x6b, 0x73, 0x8f, 0x8b, 0x01, 0xd2, 0x1c, 0x69, 0x16, 0xbf, 0x20, 0x21,
+ 0x7f, 0x84, 0x3b, 0x55, 0x88, 0x51, 0x8d, 0x7d, 0x65, 0x09, 0xf6, 0x5b, 0x25, 0xfb, 0xa8, 0x62,
+ 0x3e, 0x85, 0x5b, 0x5c, 0x04, 0xdf, 0xe6, 0x2c, 0x5f, 0xe0, 0x6d, 0x2e, 0xc1, 0xbb, 0xc5, 0xc5,
+ 0xd7, 0xc6, 0xbf, 0x62, 0x0d, 0x60, 0xbb, 0x56, 0x12, 0xfd, 0x16, 0xd7, 0xb8, 0x9d, 0x25, 0xb8,
+ 0xef, 0x96, 0x39, 0xeb, 0xb7, 0xbb, 0x0a, 0xf0, 0x27, 0xb8, 0xcb, 0x45, 0x70, 0x41, 0xb9, 0x7a,
+ 0x93, 0x7d, 0x75, 0xb9, 0x8a, 0x7c, 0x43, 0xb9, 0x5a, 0xa4, 0xc6, 0x8a, 0x4c, 0x98, 0x8c, 0x16,
+ 0x2a, 0xb2, 0xb6, 0x5c, 0x45, 0x4e, 0x8c, 0x7f, 0xc5, 0xda, 0x87, 0x2d, 0x2e, 0xde, 0xcc, 0xb5,
+ 0xb5, 0x04, 0xe7, 0x4d, 0x2e, 0x16, 0xf3, 0xfc, 0x1a, 0xb6, 0x32, 0x16, 0x2a, 0x21, 0xeb, 0x6a,
+ 0x6b, 0x2f, 0xc1, 0xb8, 0x69, 0xdd, 0x4b, 0xca, 0xde, 0x14, 0xa0, 0x9a, 0x27, 0x37, 0x60, 0x45,
+ 0xa4, 0xe6, 0xe8, 0xb8, 0xfe, 0x8a, 0x48, 0x75, 0x0f, 0x38, 0xd2, 0xd7, 0x0e, 0x1e, 0x1c, 0xd7,
+ 0xb7, 0x23, 0x7d, 0x9e, 0x26, 0xf4, 0x95, 0x28, 0x9a, 0x40, 0x1c, 0x18, 0x2b, 0x4f, 0x84, 0xb4,
+ 0x67, 0x07, 0x07, 0xda, 0x3a, 0xa5, 0x71, 0xce, 0x8a, 0x9e, 0xc7, 0x0c, 0x7a, 0x7f, 0x6d, 0x40,
+ 0xbb, 0xf8, 0x41, 0x41, 0x3e, 0xab, 0xb7, 0xd1, 0xcd, 0x77, 0xff, 0x7e, 0xd1, 0x4e, 0xb8, 0x98,
+ 0xb2, 0xd7, 0x7e, 0x5a, 0xf5, 0xda, 0x3f, 0xda, 0xd9, 0x36, 0xe4, 0x0c, 0xdc, 0xd2, 0x56, 0x5b,
+ 0x6d, 0x63, 0x61, 0xb5, 0x5d, 0xe8, 0x8c, 0x43, 0x1a, 0x8c, 0x69, 0x32, 0x8a, 0x19, 0x76, 0x88,
+ 0x1b, 0x3e, 0x8c, 0x43, 0xfa, 0x0c, 0x2d, 0x05, 0x40, 0x0c, 0x5f, 0xb1, 0x50, 0x65, 0xa6, 0x28,
+ 0x08, 0x78, 0x81, 0x96, 0xde, 0xdf, 0x57, 0xa0, 0x53, 0xfb, 0x0d, 0xa4, 0x7b, 0xe8, 0x84, 0x4e,
+ 0x8a, 0x38, 0xe6, 0x5b, 0x77, 0x6c, 0x72, 0x86, 0x77, 0x89, 0xbd, 0xa6, 0x5a, 0x72, 0x66, 0x2e,
+ 0x05, 0xf2, 0x01, 0x80, 0x9c, 0x05, 0x29, 0x0d, 0xcf, 0x99, 0xa5, 0x77, 0x7c, 0x57, 0xce, 0xfa,
+ 0x68, 0x20, 0xef, 0x83, 0x2b, 0x67, 0x01, 0x93, 0x52, 0xc8, 0xcc, 0xd6, 0xbe, 0x2d, 0x67, 0x5f,
+ 0x9a, 0xb1, 0xf5, 0x1d, 0x49, 0xa1, 0x7b, 0x01, 0xbb, 0x07, 0xae, 0x9c, 0x7d, 0x81, 0x06, 0x1d,
+ 0x55, 0x15, 0x51, 0xb1, 0xf5, 0x6c, 0xa9, 0x2a, 0xaa, 0xaa, 0xa2, 0x62, 0xeb, 0xe9, 0xaa, 0x7a,
+ 0x54, 0x55, 0x46, 0xc5, 0xee, 0xb3, 0xad, 0x6a, 0x51, 0x55, 0x15, 0xd5, 0x2d, 0x7c, 0x6d, 0xd4,
+ 0xde, 0x3f, 0x1a, 0xd0, 0xa9, 0xfd, 0x9a, 0xd3, 0x05, 0x4c, 0x64, 0x90, 0xc5, 0x8c, 0xa5, 0xfa,
+ 0x27, 0x0d, 0xde, 0xdd, 0x90, 0xc8, 0x81, 0xb5, 0x68, 0xbe, 0x44, 0x06, 0x32, 0x4f, 0x92, 0xe2,
+ 0x27, 0x8f, 0xe3, 0xbb, 0x89, 0xf4, 0xd1, 0x60, 0xa7, 0x33, 0x85, 0xe1, 0x9a, 0xc5, 0xf4, 0x00,
+ 0x0d, 0xe4, 0x17, 0x40, 0x12, 0x19, 0xe4, 0x09, 0x4f, 0x14, 0x93, 0x32, 0x4f, 0x15, 0x1f, 0x96,
+ 0xed, 0xf9, 0x56, 0x22, 0xcf, 0x16, 0x27, 0xc8, 0x7d, 0xc3, 0x66, 0x2f, 0x1b, 0x5b, 0xb2, 0x76,
+ 0x22, 0x9f, 0x9b, 0x9b, 0xe3, 0xc8, 0xfb, 0xee, 0xfb, 0xdd, 0xf7, 0xfe, 0xfd, 0xfd, 0xee, 0x7b,
+ 0x7f, 0x99, 0xef, 0x36, 0xbe, 0x9b, 0xef, 0x36, 0xfe, 0x39, 0xdf, 0x6d, 0xfc, 0x77, 0xbe, 0xdb,
+ 0x18, 0xae, 0x99, 0x3f, 0x23, 0x7e, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x78, 0x66,
+ 0x06, 0xf4, 0x10, 0x00, 0x00,
}
func (m *Metrics) Marshal() (dAtA []byte, err error) {
@@ -819,6 +877,16 @@ func (m *Metrics) MarshalTo(dAtA []byte) (int, error) {
i += n
}
}
+ if m.CgroupStats != nil {
+ dAtA[i] = 0x42
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.CgroupStats.Size()))
+ n6, err := m.CgroupStats.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n6
+ }
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
@@ -917,21 +985,21 @@ func (m *CPUStat) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
- n6, err := m.Usage.MarshalTo(dAtA[i:])
+ n7, err := m.Usage.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n6
+ i += n7
}
if m.Throttling != nil {
dAtA[i] = 0x12
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.Throttling.Size()))
- n7, err := m.Throttling.MarshalTo(dAtA[i:])
+ n8, err := m.Throttling.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n7
+ i += n8
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -970,21 +1038,21 @@ func (m *CPUUsage) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintMetrics(dAtA, i, uint64(m.User))
}
if len(m.PerCPU) > 0 {
- dAtA9 := make([]byte, len(m.PerCPU)*10)
- var j8 int
+ dAtA10 := make([]byte, len(m.PerCPU)*10)
+ var j9 int
for _, num := range m.PerCPU {
for num >= 1<<7 {
- dAtA9[j8] = uint8(uint64(num)&0x7f | 0x80)
+ dAtA10[j9] = uint8(uint64(num)&0x7f | 0x80)
num >>= 7
- j8++
+ j9++
}
- dAtA9[j8] = uint8(num)
- j8++
+ dAtA10[j9] = uint8(num)
+ j9++
}
dAtA[i] = 0x22
i++
- i = encodeVarintMetrics(dAtA, i, uint64(j8))
- i += copy(dAtA[i:], dAtA9[:j8])
+ i = encodeVarintMetrics(dAtA, i, uint64(j9))
+ i += copy(dAtA[i:], dAtA10[:j9])
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -1243,11 +1311,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
- n10, err := m.Usage.MarshalTo(dAtA[i:])
+ n11, err := m.Usage.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n10
+ i += n11
}
if m.Swap != nil {
dAtA[i] = 0x92
@@ -1255,11 +1323,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.Swap.Size()))
- n11, err := m.Swap.MarshalTo(dAtA[i:])
+ n12, err := m.Swap.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n11
+ i += n12
}
if m.Kernel != nil {
dAtA[i] = 0x9a
@@ -1267,11 +1335,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel.Size()))
- n12, err := m.Kernel.MarshalTo(dAtA[i:])
+ n13, err := m.Kernel.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n12
+ i += n13
}
if m.KernelTCP != nil {
dAtA[i] = 0xa2
@@ -1279,11 +1347,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintMetrics(dAtA, i, uint64(m.KernelTCP.Size()))
- n13, err := m.KernelTCP.MarshalTo(dAtA[i:])
+ n14, err := m.KernelTCP.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n13
+ i += n14
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -1646,6 +1714,52 @@ func (m *NetworkStat) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
+func (m *CgroupStats) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CgroupStats) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if m.NrSleeping != 0 {
+ dAtA[i] = 0x8
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.NrSleeping))
+ }
+ if m.NrRunning != 0 {
+ dAtA[i] = 0x10
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.NrRunning))
+ }
+ if m.NrStopped != 0 {
+ dAtA[i] = 0x18
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.NrStopped))
+ }
+ if m.NrUninterruptible != 0 {
+ dAtA[i] = 0x20
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.NrUninterruptible))
+ }
+ if m.NrIoWait != 0 {
+ dAtA[i] = 0x28
+ i++
+ i = encodeVarintMetrics(dAtA, i, uint64(m.NrIoWait))
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
@@ -1693,6 +1807,10 @@ func (m *Metrics) Size() (n int) {
n += 1 + l + sovMetrics(uint64(l))
}
}
+ if m.CgroupStats != nil {
+ l = m.CgroupStats.Size()
+ n += 1 + l + sovMetrics(uint64(l))
+ }
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -2134,6 +2252,33 @@ func (m *NetworkStat) Size() (n int) {
return n
}
+func (m *CgroupStats) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if m.NrSleeping != 0 {
+ n += 1 + sovMetrics(uint64(m.NrSleeping))
+ }
+ if m.NrRunning != 0 {
+ n += 1 + sovMetrics(uint64(m.NrRunning))
+ }
+ if m.NrStopped != 0 {
+ n += 1 + sovMetrics(uint64(m.NrStopped))
+ }
+ if m.NrUninterruptible != 0 {
+ n += 1 + sovMetrics(uint64(m.NrUninterruptible))
+ }
+ if m.NrIoWait != 0 {
+ n += 1 + sovMetrics(uint64(m.NrIoWait))
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
func sovMetrics(x uint64) (n int) {
for {
n++
@@ -2159,6 +2304,7 @@ func (this *Metrics) String() string {
`Blkio:` + strings.Replace(fmt.Sprintf("%v", this.Blkio), "BlkIOStat", "BlkIOStat", 1) + `,`,
`Rdma:` + strings.Replace(fmt.Sprintf("%v", this.Rdma), "RdmaStat", "RdmaStat", 1) + `,`,
`Network:` + strings.Replace(fmt.Sprintf("%v", this.Network), "NetworkStat", "NetworkStat", 1) + `,`,
+ `CgroupStats:` + strings.Replace(fmt.Sprintf("%v", this.CgroupStats), "CgroupStats", "CgroupStats", 1) + `,`,
`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
`}`,
}, "")
@@ -2366,6 +2512,21 @@ func (this *NetworkStat) String() string {
}, "")
return s
}
+func (this *CgroupStats) String() string {
+ if this == nil {
+ return "nil"
+ }
+ s := strings.Join([]string{`&CgroupStats{`,
+ `NrSleeping:` + fmt.Sprintf("%v", this.NrSleeping) + `,`,
+ `NrRunning:` + fmt.Sprintf("%v", this.NrRunning) + `,`,
+ `NrStopped:` + fmt.Sprintf("%v", this.NrStopped) + `,`,
+ `NrUninterruptible:` + fmt.Sprintf("%v", this.NrUninterruptible) + `,`,
+ `NrIoWait:` + fmt.Sprintf("%v", this.NrIoWait) + `,`,
+ `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
+ `}`,
+ }, "")
+ return s
+}
func valueToStringMetrics(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.IsNil() {
@@ -2651,6 +2812,42 @@ func (m *Metrics) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
+ case 8:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field CgroupStats", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthMetrics
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthMetrics
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.CgroupStats == nil {
+ m.CgroupStats = &CgroupStats{}
+ }
+ if err := m.CgroupStats.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipMetrics(dAtA[iNdEx:])
@@ -5256,6 +5453,155 @@ func (m *NetworkStat) Unmarshal(dAtA []byte) error {
}
return nil
}
+func (m *CgroupStats) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CgroupStats: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CgroupStats: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NrSleeping", wireType)
+ }
+ m.NrSleeping = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.NrSleeping |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 2:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NrRunning", wireType)
+ }
+ m.NrRunning = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.NrRunning |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NrStopped", wireType)
+ }
+ m.NrStopped = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.NrStopped |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 4:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NrUninterruptible", wireType)
+ }
+ m.NrUninterruptible = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.NrUninterruptible |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 5:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NrIoWait", wireType)
+ }
+ m.NrIoWait = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMetrics
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.NrIoWait |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ default:
+ iNdEx = preIndex
+ skippy, err := skipMetrics(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthMetrics
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthMetrics
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
func skipMetrics(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
diff --git a/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt b/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt
index 7a960c678..b7e87f00a 100644
--- a/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt
+++ b/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt
@@ -63,6 +63,14 @@ file {
type_name: ".io.containerd.cgroups.v1.NetworkStat"
json_name: "network"
}
+ field {
+ name: "cgroup_stats"
+ number: 8
+ label: LABEL_OPTIONAL
+ type: TYPE_MESSAGE
+ type_name: ".io.containerd.cgroups.v1.CgroupStats"
+ json_name: "cgroupStats"
+ }
}
message_type {
name: "HugetlbStat"
@@ -708,5 +716,43 @@ file {
json_name: "txDropped"
}
}
+ message_type {
+ name: "CgroupStats"
+ field {
+ name: "nr_sleeping"
+ number: 1
+ label: LABEL_OPTIONAL
+ type: TYPE_UINT64
+ json_name: "nrSleeping"
+ }
+ field {
+ name: "nr_running"
+ number: 2
+ label: LABEL_OPTIONAL
+ type: TYPE_UINT64
+ json_name: "nrRunning"
+ }
+ field {
+ name: "nr_stopped"
+ number: 3
+ label: LABEL_OPTIONAL
+ type: TYPE_UINT64
+ json_name: "nrStopped"
+ }
+ field {
+ name: "nr_uninterruptible"
+ number: 4
+ label: LABEL_OPTIONAL
+ type: TYPE_UINT64
+ json_name: "nrUninterruptible"
+ }
+ field {
+ name: "nr_io_wait"
+ number: 5
+ label: LABEL_OPTIONAL
+ type: TYPE_UINT64
+ json_name: "nrIoWait"
+ }
+ }
syntax: "proto3"
}
diff --git a/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto b/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto
index 62b519806..ba6be851d 100644
--- a/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto
+++ b/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto
@@ -12,6 +12,7 @@ message Metrics {
BlkIOStat blkio = 5;
RdmaStat rdma = 6;
repeated NetworkStat network = 7;
+ CgroupStats cgroup_stats = 8;
}
message HugetlbStat {
@@ -134,3 +135,17 @@ message NetworkStat {
uint64 tx_errors = 8;
uint64 tx_dropped = 9;
}
+
+// CgroupStats exports per-cgroup statistics.
+message CgroupStats {
+ // number of tasks sleeping
+ uint64 nr_sleeping = 1;
+ // number of tasks running
+ uint64 nr_running = 2;
+ // number of tasks in stopped state
+ uint64 nr_stopped = 3;
+ // number of tasks in uninterruptible state
+ uint64 nr_uninterruptible = 4;
+ // number of tasks waiting on IO
+ uint64 nr_io_wait = 5;
+}
diff --git a/vendor/github.com/containers/buildah/.cirrus.yml b/vendor/github.com/containers/buildah/.cirrus.yml
index 65ce26080..589de9c61 100644
--- a/vendor/github.com/containers/buildah/.cirrus.yml
+++ b/vendor/github.com/containers/buildah/.cirrus.yml
@@ -178,7 +178,7 @@ gce_instance:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
- image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
+# image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
# Separate scripts for separate outputs, makes debugging easier.
setup_script: '${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}'
diff --git a/vendor/github.com/containers/buildah/Makefile b/vendor/github.com/containers/buildah/Makefile
index e70dd161d..45f8a8ec8 100644
--- a/vendor/github.com/containers/buildah/Makefile
+++ b/vendor/github.com/containers/buildah/Makefile
@@ -39,6 +39,14 @@ SOURCES=*.go imagebuildah/*.go bind/*.go chroot/*.go cmd/buildah/*.go copier/*.g
LINTFLAGS ?=
+ifeq ($(DEBUG), 1)
+ override GOGCFLAGS += -N -l
+endif
+
+# make all DEBUG=1
+# Note: Uses the -N -l go compiler options to disable compiler optimizations
+# and inlining. Using these build options allows you to subsequently
+# use source debugging tools like delve.
all: bin/buildah bin/imgtype docs
# Update nix/nixpkgs.json its latest stable commit
@@ -56,7 +64,7 @@ static:
.PHONY: bin/buildah
bin/buildah: $(SOURCES)
- $(GO_BUILD) $(BUILDAH_LDFLAGS) -o $@ $(BUILDFLAGS) ./cmd/buildah
+ $(GO_BUILD) $(BUILDAH_LDFLAGS) -gcflags "$(GOGCFLAGS)" -o $@ $(BUILDFLAGS) ./cmd/buildah
.PHONY: buildah
buildah: bin/buildah
diff --git a/vendor/github.com/containers/buildah/copier/copier.go b/vendor/github.com/containers/buildah/copier/copier.go
index 84b636202..ef0e4778d 100644
--- a/vendor/github.com/containers/buildah/copier/copier.go
+++ b/vendor/github.com/containers/buildah/copier/copier.go
@@ -10,6 +10,7 @@ import (
"net"
"os"
"os/user"
+ "path"
"path/filepath"
"strconv"
"strings"
@@ -202,11 +203,11 @@ type StatOptions struct {
// If root and directory are both not specified, the current root directory is
// used, and relative names in the globs list are treated as being relative to
// the current working directory.
-// If root is specified and the current OS supports it, the stat() is performed
-// in a chrooted context. If the directory is specified as an absolute path,
-// it should either be the root directory or a subdirectory of the root
-// directory. Otherwise, the directory is treated as a path relative to the
-// root directory.
+// If root is specified and the current OS supports it, and the calling process
+// has the necessary privileges, the stat() is performed in a chrooted context.
+// If the directory is specified as an absolute path, it should either be the
+// root directory or a subdirectory of the root directory. Otherwise, the
+// directory is treated as a path relative to the root directory.
// Relative names in the glob list are treated as being relative to the
// directory.
func Stat(root string, directory string, options StatOptions, globs []string) ([]*StatsForGlob, error) {
@@ -229,18 +230,19 @@ func Stat(root string, directory string, options StatOptions, globs []string) ([
// GetOptions controls parts of Get()'s behavior.
type GetOptions struct {
- UIDMap, GIDMap []idtools.IDMap // map from hostIDs to containerIDs in the output archive
- Excludes []string // contents to pretend don't exist, using the OS-specific path separator
- ExpandArchives bool // extract the contents of named items that are archives
- ChownDirs *idtools.IDPair // set ownership on directories. no effect on archives being extracted
- ChmodDirs *os.FileMode // set permissions on directories. no effect on archives being extracted
- ChownFiles *idtools.IDPair // set ownership of files. no effect on archives being extracted
- ChmodFiles *os.FileMode // set permissions on files. no effect on archives being extracted
- StripSetuidBit bool // strip the setuid bit off of items being copied. no effect on archives being extracted
- StripSetgidBit bool // strip the setgid bit off of items being copied. no effect on archives being extracted
- StripStickyBit bool // strip the sticky bit off of items being copied. no effect on archives being extracted
- StripXattrs bool // don't record extended attributes of items being copied. no effect on archives being extracted
- KeepDirectoryNames bool // don't strip the top directory's basename from the paths of items in subdirectories
+ UIDMap, GIDMap []idtools.IDMap // map from hostIDs to containerIDs in the output archive
+ Excludes []string // contents to pretend don't exist, using the OS-specific path separator
+ ExpandArchives bool // extract the contents of named items that are archives
+ ChownDirs *idtools.IDPair // set ownership on directories. no effect on archives being extracted
+ ChmodDirs *os.FileMode // set permissions on directories. no effect on archives being extracted
+ ChownFiles *idtools.IDPair // set ownership of files. no effect on archives being extracted
+ ChmodFiles *os.FileMode // set permissions on files. no effect on archives being extracted
+ StripSetuidBit bool // strip the setuid bit off of items being copied. no effect on archives being extracted
+ StripSetgidBit bool // strip the setgid bit off of items being copied. no effect on archives being extracted
+ StripStickyBit bool // strip the sticky bit off of items being copied. no effect on archives being extracted
+ StripXattrs bool // don't record extended attributes of items being copied. no effect on archives being extracted
+ KeepDirectoryNames bool // don't strip the top directory's basename from the paths of items in subdirectories
+ Rename map[string]string // rename items with the specified names, or under the specified names
}
// Get produces an archive containing items that match the specified glob
@@ -248,11 +250,11 @@ type GetOptions struct {
// If root and directory are both not specified, the current root directory is
// used, and relative names in the globs list are treated as being relative to
// the current working directory.
-// If root is specified and the current OS supports it, the contents are read
-// in a chrooted context. If the directory is specified as an absolute path,
-// it should either be the root directory or a subdirectory of the root
-// directory. Otherwise, the directory is treated as a path relative to the
-// root directory.
+// If root is specified and the current OS supports it, and the calling process
+// has the necessary privileges, the contents are read in a chrooted context.
+// If the directory is specified as an absolute path, it should either be the
+// root directory or a subdirectory of the root directory. Otherwise, the
+// directory is treated as a path relative to the root directory.
// Relative names in the glob list are treated as being relative to the
// directory.
func Get(root string, directory string, options GetOptions, globs []string, bulkWriter io.Writer) error {
@@ -278,25 +280,28 @@ func Get(root string, directory string, options GetOptions, globs []string, bulk
// PutOptions controls parts of Put()'s behavior.
type PutOptions struct {
- UIDMap, GIDMap []idtools.IDMap // map from containerIDs to hostIDs when writing contents to disk
- DefaultDirOwner *idtools.IDPair // set ownership of implicitly-created directories, default is ChownDirs, or 0:0 if ChownDirs not set
- DefaultDirMode *os.FileMode // set permissions on implicitly-created directories, default is ChmodDirs, or 0755 if ChmodDirs not set
- ChownDirs *idtools.IDPair // set ownership of newly-created directories
- ChmodDirs *os.FileMode // set permissions on newly-created directories
- ChownFiles *idtools.IDPair // set ownership of newly-created files
- ChmodFiles *os.FileMode // set permissions on newly-created files
- StripXattrs bool // don't bother trying to set extended attributes of items being copied
- IgnoreXattrErrors bool // ignore any errors encountered when attempting to set extended attributes
+ UIDMap, GIDMap []idtools.IDMap // map from containerIDs to hostIDs when writing contents to disk
+ DefaultDirOwner *idtools.IDPair // set ownership of implicitly-created directories, default is ChownDirs, or 0:0 if ChownDirs not set
+ DefaultDirMode *os.FileMode // set permissions on implicitly-created directories, default is ChmodDirs, or 0755 if ChmodDirs not set
+ ChownDirs *idtools.IDPair // set ownership of newly-created directories
+ ChmodDirs *os.FileMode // set permissions on newly-created directories
+ ChownFiles *idtools.IDPair // set ownership of newly-created files
+ ChmodFiles *os.FileMode // set permissions on newly-created files
+ StripXattrs bool // don't bother trying to set extended attributes of items being copied
+ IgnoreXattrErrors bool // ignore any errors encountered when attempting to set extended attributes
+ NoOverwriteDirNonDir bool // instead of quietly overwriting directories with non-directories, return an error
+ Rename map[string]string // rename items with the specified names, or under the specified names
}
// Put extracts an archive from the bulkReader at the specified directory.
// If root and directory are both not specified, the current root directory is
// used.
-// If root is specified and the current OS supports it, the contents are written
-// in a chrooted context. If the directory is specified as an absolute path,
-// it should either be the root directory or a subdirectory of the root
-// directory. Otherwise, the directory is treated as a path relative to the
-// root directory.
+// If root is specified and the current OS supports it, and the calling process
+// has the necessary privileges, the contents are written in a chrooted
+// context. If the directory is specified as an absolute path, it should
+// either be the root directory or a subdirectory of the root directory.
+// Otherwise, the directory is treated as a path relative to the root
+// directory.
func Put(root string, directory string, options PutOptions, bulkReader io.Reader) error {
req := request{
Request: requestPut,
@@ -325,11 +330,12 @@ type MkdirOptions struct {
// need to be created will be given the specified ownership and permissions.
// If root and directory are both not specified, the current root directory is
// used.
-// If root is specified and the current OS supports it, the directory is
-// created in a chrooted context. If the directory is specified as an absolute
-// path, it should either be the root directory or a subdirectory of the root
-// directory. Otherwise, the directory is treated as a path relative to the
-// root directory.
+// If root is specified and the current OS supports it, and the calling process
+// has the necessary privileges, the directory is created in a chrooted
+// context. If the directory is specified as an absolute path, it should
+// either be the root directory or a subdirectory of the root directory.
+// Otherwise, the directory is treated as a path relative to the root
+// directory.
func Mkdir(root string, directory string, options MkdirOptions) error {
req := request{
Request: requestMkdir,
@@ -547,13 +553,13 @@ func copierWithSubprocess(bulkReader io.Reader, bulkWriter io.Writer, req reques
return nil, errors.Wrap(err, step)
}
if err = encoder.Encode(req); err != nil {
- return killAndReturn(err, "error encoding request")
+ return killAndReturn(err, "error encoding request for copier subprocess")
}
if err = decoder.Decode(&resp); err != nil {
- return killAndReturn(err, "error decoding response")
+ return killAndReturn(err, "error decoding response from copier subprocess")
}
if err = encoder.Encode(&request{Request: requestQuit}); err != nil {
- return killAndReturn(err, "error encoding request")
+ return killAndReturn(err, "error encoding request for copier subprocess")
}
stdinWrite.Close()
stdinWrite = nil
@@ -626,7 +632,7 @@ func copierMain() {
// Read a request.
req := new(request)
if err := decoder.Decode(req); err != nil {
- fmt.Fprintf(os.Stderr, "error decoding request: %v", err)
+ fmt.Fprintf(os.Stderr, "error decoding request from copier parent process: %v", err)
os.Exit(1)
}
if req.Request == requestQuit {
@@ -717,12 +723,12 @@ func copierMain() {
}
resp, cb, err := copierHandler(bulkReader, bulkWriter, *req)
if err != nil {
- fmt.Fprintf(os.Stderr, "error handling request %#v: %v", *req, err)
+ fmt.Fprintf(os.Stderr, "error handling request %#v from copier parent process: %v", *req, err)
os.Exit(1)
}
// Encode the response.
if err := encoder.Encode(resp); err != nil {
- fmt.Fprintf(os.Stderr, "error encoding response %#v: %v", *req, err)
+ fmt.Fprintf(os.Stderr, "error encoding response %#v for copier parent process: %v", *req, err)
os.Exit(1)
}
// If there's bulk data to transfer, run the callback to either
@@ -1118,6 +1124,34 @@ func copierHandlerGet(bulkWriter io.Writer, req request, pm *fileutils.PatternMa
return &response{Stat: statResponse.Stat, Get: getResponse{}}, cb, nil
}
+func handleRename(rename map[string]string, name string) string {
+ if rename == nil {
+ return name
+ }
+ // header names always use '/', so use path instead of filepath to manipulate it
+ if directMapping, ok := rename[name]; ok {
+ return directMapping
+ }
+ prefix, remainder := path.Split(name)
+ for prefix != "" {
+ if mappedPrefix, ok := rename[prefix]; ok {
+ return path.Join(mappedPrefix, remainder)
+ }
+ if prefix[len(prefix)-1] == '/' {
+ if mappedPrefix, ok := rename[prefix[:len(prefix)-1]]; ok {
+ return path.Join(mappedPrefix, remainder)
+ }
+ }
+ newPrefix, middlePart := path.Split(prefix)
+ if newPrefix == prefix {
+ return name
+ }
+ prefix = newPrefix
+ remainder = path.Join(middlePart, remainder)
+ }
+ return name
+}
+
func copierHandlerGetOne(srcfi os.FileInfo, symlinkTarget, name, contentPath string, options GetOptions, tw *tar.Writer, hardlinkChecker *util.HardlinkChecker, idMappings *idtools.IDMappings) error {
// build the header using the name provided
hdr, err := tar.FileInfoHeader(srcfi, symlinkTarget)
@@ -1127,6 +1161,9 @@ func copierHandlerGetOne(srcfi os.FileInfo, symlinkTarget, name, contentPath str
if name != "" {
hdr.Name = filepath.ToSlash(name)
}
+ if options.Rename != nil {
+ hdr.Name = handleRename(options.Rename, hdr.Name)
+ }
if options.StripSetuidBit {
hdr.Mode &^= cISUID
}
@@ -1164,6 +1201,9 @@ func copierHandlerGetOne(srcfi os.FileInfo, symlinkTarget, name, contentPath str
tr := tar.NewReader(rc)
hdr, err := tr.Next()
for err == nil {
+ if options.Rename != nil {
+ hdr.Name = handleRename(options.Rename, hdr.Name)
+ }
if err = tw.WriteHeader(hdr); err != nil {
return errors.Wrapf(err, "error writing tar header from %q to pipe", contentPath)
}
@@ -1311,8 +1351,13 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
createFile := func(path string, tr *tar.Reader) (int64, error) {
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_EXCL, 0600)
if err != nil && os.IsExist(err) {
- if err = os.Remove(path); err != nil {
- return 0, errors.Wrapf(err, "copier: put: error removing file to be overwritten %q", path)
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err2 := os.Lstat(path); err2 == nil && st.IsDir() {
+ return 0, errors.Wrapf(err, "copier: put: error creating file at %q", path)
+ }
+ }
+ if err = os.RemoveAll(path); err != nil {
+ return 0, errors.Wrapf(err, "copier: put: error removing item to be overwritten %q", path)
}
f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_EXCL, 0600)
}
@@ -1360,6 +1405,14 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
tr := tar.NewReader(bulkReader)
hdr, err := tr.Next()
for err == nil {
+ if len(hdr.Name) == 0 {
+ // no name -> ignore the entry
+ hdr, err = tr.Next()
+ continue
+ }
+ if req.PutOptions.Rename != nil {
+ hdr.Name = handleRename(req.PutOptions.Rename, hdr.Name)
+ }
// figure out who should own this new item
if idMappings != nil && !idMappings.Empty() {
containerPair := idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
@@ -1412,35 +1465,70 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
}
case tar.TypeLink:
var linkTarget string
+ if req.PutOptions.Rename != nil {
+ hdr.Linkname = handleRename(req.PutOptions.Rename, hdr.Linkname)
+ }
if linkTarget, err = resolvePath(targetDirectory, filepath.Join(req.Root, filepath.FromSlash(hdr.Linkname)), nil); err != nil {
return errors.Errorf("error resolving hardlink target path %q under root %q", hdr.Linkname, req.Root)
}
if err = os.Link(linkTarget, path); err != nil && os.IsExist(err) {
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err := os.Lstat(path); err == nil && st.IsDir() {
+ break
+ }
+ }
if err = os.Remove(path); err == nil {
err = os.Link(linkTarget, path)
}
}
case tar.TypeSymlink:
+ // if req.PutOptions.Rename != nil {
+ // todo: the general solution requires resolving to an absolute path, handling
+ // renaming, and then possibly converting back to a relative symlink
+ // }
if err = os.Symlink(filepath.FromSlash(hdr.Linkname), filepath.FromSlash(path)); err != nil && os.IsExist(err) {
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err := os.Lstat(path); err == nil && st.IsDir() {
+ break
+ }
+ }
if err = os.Remove(path); err == nil {
err = os.Symlink(filepath.FromSlash(hdr.Linkname), filepath.FromSlash(path))
}
}
case tar.TypeChar:
if err = mknod(path, chrMode(0600), int(mkdev(devMajor, devMinor))); err != nil && os.IsExist(err) {
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err := os.Lstat(path); err == nil && st.IsDir() {
+ break
+ }
+ }
if err = os.Remove(path); err == nil {
err = mknod(path, chrMode(0600), int(mkdev(devMajor, devMinor)))
}
}
case tar.TypeBlock:
if err = mknod(path, blkMode(0600), int(mkdev(devMajor, devMinor))); err != nil && os.IsExist(err) {
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err := os.Lstat(path); err == nil && st.IsDir() {
+ break
+ }
+ }
if err = os.Remove(path); err == nil {
err = mknod(path, blkMode(0600), int(mkdev(devMajor, devMinor)))
}
}
case tar.TypeDir:
if err = os.Mkdir(path, 0700); err != nil && os.IsExist(err) {
- err = nil
+ var st os.FileInfo
+ if st, err = os.Stat(path); err == nil && !st.IsDir() {
+ // it's not a directory, so remove it and mkdir
+ if err = os.Remove(path); err == nil {
+ err = os.Mkdir(path, 0700)
+ }
+ }
+ // either we removed it and retried, or it was a directory,
+ // in which case we want to just add the new stuff under it
}
// make a note of the directory's times. we
// might create items under it, which will
@@ -1453,6 +1541,11 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
})
case tar.TypeFifo:
if err = mkfifo(path, 0600); err != nil && os.IsExist(err) {
+ if req.PutOptions.NoOverwriteDirNonDir {
+ if st, err := os.Lstat(path); err == nil && st.IsDir() {
+ break
+ }
+ }
if err = os.Remove(path); err == nil {
err = mkfifo(path, 0600)
}
diff --git a/vendor/github.com/containers/buildah/copier/syscall_unix.go b/vendor/github.com/containers/buildah/copier/syscall_unix.go
index 55f2f368a..2c2806d0a 100644
--- a/vendor/github.com/containers/buildah/copier/syscall_unix.go
+++ b/vendor/github.com/containers/buildah/copier/syscall_unix.go
@@ -10,7 +10,7 @@ import (
"golang.org/x/sys/unix"
)
-var canChroot = true
+var canChroot = os.Getuid() == 0
func chroot(root string) (bool, error) {
if canChroot {
diff --git a/vendor/github.com/containers/buildah/go.mod b/vendor/github.com/containers/buildah/go.mod
index 0d795f6b6..ea9a956be 100644
--- a/vendor/github.com/containers/buildah/go.mod
+++ b/vendor/github.com/containers/buildah/go.mod
@@ -5,10 +5,10 @@ go 1.12
require (
github.com/containerd/containerd v1.4.1 // indirect
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784
- github.com/containers/common v0.29.0
+ github.com/containers/common v0.31.0
github.com/containers/image/v5 v5.8.1
github.com/containers/ocicrypt v1.0.3
- github.com/containers/storage v1.24.1
+ github.com/containers/storage v1.24.3
github.com/docker/distribution v2.7.1+incompatible
github.com/docker/go-units v0.4.0
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316
@@ -21,7 +21,7 @@ require (
github.com/moby/sys/mount v0.1.1 // indirect
github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 // indirect
github.com/onsi/ginkgo v1.14.2
- github.com/onsi/gomega v1.10.3
+ github.com/onsi/gomega v1.10.4
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/runc v1.0.0-rc91
diff --git a/vendor/github.com/containers/buildah/go.sum b/vendor/github.com/containers/buildah/go.sum
index e3413bc68..c2082c5ef 100644
--- a/vendor/github.com/containers/buildah/go.sum
+++ b/vendor/github.com/containers/buildah/go.sum
@@ -73,8 +73,8 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 h1:rqUVLD8I859xRgUx/WMC3v7QAFqbLKZbs+0kqYboRJc=
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
-github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ=
-github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
+github.com/containers/common v0.31.0 h1:SRnjfoqbjfaojpY9YJq9JBPEslwB5hoXJbaE+5zMFwM=
+github.com/containers/common v0.31.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q=
github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
@@ -84,6 +84,8 @@ github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQ
github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI=
github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc=
github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
+github.com/containers/storage v1.24.3 h1:8UB4S62l4hrU6Yw3dbsLCJtLg7Ofo39IN2HdckBIX4E=
+github.com/containers/storage v1.24.3/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -303,6 +305,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U=
+github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -482,6 +486,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md
index 119315d1f..90e844c3e 100644
--- a/vendor/github.com/containers/buildah/install.md
+++ b/vendor/github.com/containers/buildah/install.md
@@ -69,15 +69,35 @@ sudo apt-get update
sudo apt-get -y install buildah
```
-The [Kubic project](https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable)
-provides packages for Debian 10. The Kubic packages for Debian Testing/Bullseye and Debian Unstable/Sid
-have been discontinued to avoid
-[conflicts](https://github.com/containers/buildah/issues/2797) with the official packages.
+If you would prefer newer (though not as well-tested) packages,
+the [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah)
+provides packages for Debian 10 and newer. The packages in Kubic project repos are more frequently
+updated than the one in Debian's official repositories, due to how Debian works.
+The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
+
+CAUTION: On Debian 11 and newer, including Testing and Sid/Unstable, we highly recommend you use Buildah, Podman and Skopeo ONLY from EITHER the Kubic repo
+OR the official Debian repos. Mixing and matching may lead to unpredictable situations including installation conflicts.
+
+```bash
+# Debian 10
+echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
+curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/Release.key | sudo apt-key add -
+sudo apt-get update
+sudo apt-get -y install buildah
+
+# Debian Testing
+echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
+curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/Release.key | sudo apt-key add -
+sudo apt-get update
+sudo apt-get -y install buildah
+
+# Debian Sid/Unstable
+echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
+curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/Release.key | sudo apt-key add -
+sudo apt-get update
+sudo apt-get -y install buildah
+```
-Caution: If you upgrade from Debian 10 to Testing/Bullseye or
-Unstable/Sid you would likely end up downgrading Buildah because the version in
-OBS is more frequently updated than the one in Debian's official repositories,
-due to how Debian works.
### [Fedora](https://www.fedoraproject.org)
@@ -125,7 +145,8 @@ sudo yum -y install buildah
#### [Raspberry Pi OS armhf (ex Raspbian)](https://www.raspberrypi.org/downloads/raspberry-pi-os/)
-The Kubic project provides packages for Raspbian 10.
+The [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah) provides
+packages for Raspbian 10.
```bash
# Raspbian 10
@@ -135,6 +156,8 @@ sudo apt-get update -qq
sudo apt-get -qq -y install buildah
```
+The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
+
#### [Raspberry Pi OS arm64 (beta)](https://downloads.raspberrypi.org/raspios_arm64/images/)
Raspberry Pi OS use the standard Debian's repositories,
@@ -160,7 +183,16 @@ sudo apt-get -y update
sudo apt-get -y install buildah
```
-The [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah) provides packages for some older but supported Ubuntu versions (it should also work with direct derivatives like Pop!\_OS).
+If you would prefer newer (though not as well-tested) packages,
+the [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah)
+provides packages for active Ubuntu releases 18.04 and newer (it should also work with direct derivatives like Pop!\_OS).
+The packages in Kubic project repos are more frequently updated than the one in Ubuntu's official repositories, due to how Debian/Ubuntu works.
+Checkout the Kubic project page for a list of supported Ubuntu version and architecture combinations.
+The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
+
+CAUTION: On Ubuntu 20.10 and newer, we highly recommend you use Buildah, Podman and Skopeo ONLY from EITHER the Kubic repo
+OR the official Ubuntu repos. Mixing and matching may lead to unpredictable situations including installation conflicts.
+
```bash
. /etc/os-release
@@ -473,6 +505,13 @@ cat /etc/containers/policy.json
}
```
+## Debug with Delve and the like
+
+To make a source debug build without optimizations use `DEBUG=1`, like:
+```
+make all DEBUG=1
+```
+
## Vendoring
Buildah uses Go Modules for vendoring purposes. If you need to update or add a vendored package into Buildah, please follow this procedure:
diff --git a/vendor/github.com/containers/buildah/new.go b/vendor/github.com/containers/buildah/new.go
index c1abb1cdb..aab17fea2 100644
--- a/vendor/github.com/containers/buildah/new.go
+++ b/vendor/github.com/containers/buildah/new.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"math/rand"
- "os"
"strings"
"github.com/containers/buildah/util"
@@ -127,27 +126,10 @@ func resolveLocalImage(systemContext *types.SystemContext, store storage.Store,
return nil, "", nil, nil
}
-// getShortNameMode looks up the `CONTAINERS_SHORT_NAME_ALIASING` environment
-// variable. If it's "on", return `nil` to use the defaults from
-// containers/image and the registries.conf files on the system. If it's
-// "off", empty or unset, return types.ShortNameModeDisabled to turn off
-// short-name aliasing by default.
-//
-// TODO: remove this function once we want to default to short-name aliasing.
-func getShortNameMode() *types.ShortNameMode {
- env := os.Getenv("CONTAINERS_SHORT_NAME_ALIASING")
- if strings.ToLower(env) == "on" {
- return nil // default to whatever registries.conf and c/image decide
- }
- mode := types.ShortNameModeDisabled
- return &mode
-}
-
func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) {
if systemContext == nil {
systemContext = &types.SystemContext{}
}
- systemContext.ShortNameMode = getShortNameMode()
fromImage := options.FromImage
// If the image name includes a transport we can use it as it. Special
diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go
index 123548d97..1e2db58c4 100644
--- a/vendor/github.com/containers/buildah/pkg/cli/common.go
+++ b/vendor/github.com/containers/buildah/pkg/cli/common.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/common/pkg/auth"
commonComp "github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
+ "github.com/containers/storage/pkg/unshare"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/spf13/pflag"
@@ -366,6 +367,9 @@ func DefaultIsolation() string {
if isolation != "" {
return isolation
}
+ if unshare.IsRootless() {
+ return "rootless"
+ }
return buildah.OCI
}
diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go
index fb348b252..f256e6c2a 100644
--- a/vendor/github.com/containers/buildah/pkg/parse/parse.go
+++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go
@@ -486,7 +486,7 @@ func ValidateVolumeCtrDir(ctrDir string) error {
// ValidateVolumeOpts validates a volume's options
func ValidateVolumeOpts(options []string) ([]string, error) {
- var foundRootPropagation, foundRWRO, foundLabelChange, bindType, foundExec, foundDev, foundSuid int
+ var foundRootPropagation, foundRWRO, foundLabelChange, bindType, foundExec, foundDev, foundSuid, foundChown int
finalOpts := make([]string, 0, len(options))
for _, opt := range options {
switch opt {
@@ -515,6 +515,11 @@ func ValidateVolumeOpts(options []string) ([]string, error) {
if foundLabelChange > 1 {
return nil, errors.Errorf("invalid options %q, can only specify 1 'z', 'Z', or 'O' option", strings.Join(options, ", "))
}
+ case "U":
+ foundChown++
+ if foundChown > 1 {
+ return nil, errors.Errorf("invalid options %q, can only specify 1 'U' option", strings.Join(options, ", "))
+ }
case "private", "rprivate", "shared", "rshared", "slave", "rslave", "unbindable", "runbindable":
foundRootPropagation++
if foundRootPropagation > 1 {
@@ -878,20 +883,12 @@ func NamespaceOptions(c *cobra.Command) (namespaceOptions buildah.NamespaceOptio
logrus.Debugf("setting network to disabled")
break
}
- if !filepath.IsAbs(how) {
- options.AddOrReplace(buildah.NamespaceOption{
- Name: what,
- Path: how,
- })
- policy = buildah.NetworkEnabled
- logrus.Debugf("setting network configuration to %q", how)
- break
- }
}
how = strings.TrimPrefix(how, "ns:")
if _, err := os.Stat(how); err != nil {
- return nil, buildah.NetworkDefault, errors.Wrapf(err, "error checking for %s namespace at %q", what, how)
+ return nil, buildah.NetworkDefault, errors.Wrapf(err, "error checking for %s namespace", what)
}
+ policy = buildah.NetworkEnabled
logrus.Debugf("setting %q namespace to %q", what, how)
options.AddOrReplace(buildah.NamespaceOption{
Name: what,
diff --git a/vendor/github.com/containers/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go
index d20d39423..dc2f5c5ad 100644
--- a/vendor/github.com/containers/buildah/run_linux.go
+++ b/vendor/github.com/containers/buildah/run_linux.go
@@ -506,8 +506,14 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
return err
}
+ // Get host UID and GID of the container process.
+ processUID, processGID, err := util.GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, spec.Process.User.UID, spec.Process.User.GID)
+ if err != nil {
+ return err
+ }
+
// Get the list of explicitly-specified volume mounts.
- volumes, err := b.runSetupVolumeMounts(spec.Linux.MountLabel, volumeMounts, optionMounts, int(rootUID), int(rootGID))
+ volumes, err := b.runSetupVolumeMounts(spec.Linux.MountLabel, volumeMounts, optionMounts, int(rootUID), int(rootGID), int(processUID), int(processGID))
if err != nil {
return err
}
@@ -1687,7 +1693,7 @@ func (b *Builder) cleanupTempVolumes() {
}
}
-func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string, optionMounts []specs.Mount, rootUID, rootGID int) (mounts []specs.Mount, Err error) {
+func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string, optionMounts []specs.Mount, rootUID, rootGID, processUID, processGID int) (mounts []specs.Mount, Err error) {
// Make sure the overlay directory is clean before running
containerDir, err := b.store.ContainerDirectory(b.ContainerID)
@@ -1699,7 +1705,7 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
}
parseMount := func(mountType, host, container string, options []string) (specs.Mount, error) {
- var foundrw, foundro, foundz, foundZ, foundO bool
+ var foundrw, foundro, foundz, foundZ, foundO, foundU bool
var rootProp string
for _, opt := range options {
switch opt {
@@ -1713,6 +1719,8 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
foundZ = true
case "O":
foundO = true
+ case "U":
+ foundU = true
case "private", "rprivate", "slave", "rslave", "shared", "rshared":
rootProp = opt
}
@@ -1730,6 +1738,11 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
return specs.Mount{}, err
}
}
+ if foundU {
+ if err := chownSourceVolume(host, processUID, processGID); err != nil {
+ return specs.Mount{}, err
+ }
+ }
if foundO {
containerDir, err := b.store.ContainerDirectory(b.ContainerID)
if err != nil {
@@ -1746,6 +1759,14 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
b.TempVolumes[contentDir] = true
}
+
+ // If chown true, add correct ownership to the overlay temp directories.
+ if foundU {
+ if err := chownSourceVolume(contentDir, processUID, processGID); err != nil {
+ return specs.Mount{}, err
+ }
+ }
+
return overlayMount, err
}
if rootProp == "" {
@@ -1789,6 +1810,39 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
return mounts, nil
}
+// chownSourceVolume changes the ownership of a volume source directory or file within the host.
+func chownSourceVolume(path string, UID, GID int) error {
+ fi, err := os.Lstat(path)
+ if err != nil {
+ // Skip if path does not exist
+ if os.IsNotExist(err) {
+ logrus.Debugf("error returning file info of %q: %v", path, err)
+ return nil
+ }
+ return err
+ }
+
+ currentUID := int(fi.Sys().(*syscall.Stat_t).Uid)
+ currentGID := int(fi.Sys().(*syscall.Stat_t).Gid)
+
+ if UID != currentUID || GID != currentGID {
+ err := filepath.Walk(path, func(filePath string, f os.FileInfo, err error) error {
+ return os.Lchown(filePath, UID, GID)
+ })
+
+ if err != nil {
+ // Skip if path does not exist
+ if os.IsNotExist(err) {
+ logrus.Debugf("error changing the uid and gid of %q: %v", path, err)
+ return nil
+ }
+ return err
+ }
+ }
+
+ return nil
+}
+
func setupMaskedPaths(g *generate.Generator) {
for _, mp := range []string{
"/proc/acpi",
diff --git a/vendor/github.com/containers/buildah/troubleshooting.md b/vendor/github.com/containers/buildah/troubleshooting.md
index afd9c640a..02631ae13 100644
--- a/vendor/github.com/containers/buildah/troubleshooting.md
+++ b/vendor/github.com/containers/buildah/troubleshooting.md
@@ -154,5 +154,5 @@ 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.
+ * Add `mount_program = "/usr/bin/fuse-overlayfs"` under `[storage.options]` in your `~/.config/containers/storage.conf` file.
---
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 320d5e0e5..ea08ab6ad 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -586,6 +586,22 @@ func (c *Config) Validate() error {
return nil
}
+func (c *EngineConfig) findRuntime() string {
+ // Search for crun first followed by runc and kata
+ for _, name := range []string{"crun", "runc", "kata"} {
+ for _, v := range c.OCIRuntimes[name] {
+ if _, err := os.Stat(v); err == nil {
+ return name
+ }
+ }
+ if path, err := exec.LookPath(name); err == nil {
+ logrus.Warningf("Found default OCIruntime %s path which is missing from [engine.runtimes] in containers.conf", path)
+ return name
+ }
+ }
+ return ""
+}
+
// Validate is the main entry point for Engine configuration validation
// It returns an `error` on validation failure, otherwise
// `nil`.
diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf
index 12fbecc22..0587469b2 100644
--- a/vendor/github.com/containers/common/pkg/config/containers.conf
+++ b/vendor/github.com/containers/common/pkg/config/containers.conf
@@ -380,7 +380,7 @@ default_sysctls = [
# Directory for temporary files. Must be tmpfs (wiped after reboot)
#
-# tmp_dir = "/var/run/libpod"
+# tmp_dir = "/run/libpod"
# Directory for libpod named volumes.
# By default, this will be configured relative to where containers/storage
@@ -425,18 +425,8 @@ default_sysctls = [
# Path to file containing ssh identity key
# identity = "~/.ssh/id_rsa"
-# Paths to look for a valid OCI runtime (runc, runv, kata, etc)
+# Paths to look for a valid OCI runtime (crun, runc, kata, etc)
[engine.runtimes]
-# runc = [
-# "/usr/bin/runc",
-# "/usr/sbin/runc",
-# "/usr/local/bin/runc",
-# "/usr/local/sbin/runc",
-# "/sbin/runc",
-# "/bin/runc",
-# "/usr/lib/cri-o-runc/sbin/runc",
-# ]
-
# crun = [
# "/usr/bin/crun",
# "/usr/sbin/crun",
@@ -447,6 +437,16 @@ default_sysctls = [
# "/run/current-system/sw/bin/crun",
# ]
+# runc = [
+# "/usr/bin/runc",
+# "/usr/sbin/runc",
+# "/usr/local/bin/runc",
+# "/usr/local/sbin/runc",
+# "/sbin/runc",
+# "/bin/runc",
+# "/usr/lib/cri-o-runc/sbin/runc",
+# ]
+
# kata = [
# "/usr/bin/kata-runtime",
# "/usr/sbin/kata-runtime",
diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go
index 2b3a098a7..6b7aee987 100644
--- a/vendor/github.com/containers/common/pkg/config/default.go
+++ b/vendor/github.com/containers/common/pkg/config/default.go
@@ -242,7 +242,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
c.ImageDefaultTransport = _defaultTransport
c.StateType = BoltDBStateStore
- c.OCIRuntime = "crun"
c.ImageBuildFormat = "oci"
c.CgroupManager = defaultCgroupManager()
@@ -250,6 +249,15 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
c.Remote = isRemote()
c.OCIRuntimes = map[string][]string{
+ "crun": {
+ "/usr/bin/crun",
+ "/usr/sbin/crun",
+ "/usr/local/bin/crun",
+ "/usr/local/sbin/crun",
+ "/sbin/crun",
+ "/bin/crun",
+ "/run/current-system/sw/bin/crun",
+ },
"runc": {
"/usr/bin/runc",
"/usr/sbin/runc",
@@ -260,15 +268,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
"/usr/lib/cri-o-runc/sbin/runc",
"/run/current-system/sw/bin/runc",
},
- "crun": {
- "/usr/bin/crun",
- "/usr/sbin/crun",
- "/usr/local/bin/crun",
- "/usr/local/sbin/crun",
- "/sbin/crun",
- "/bin/crun",
- "/run/current-system/sw/bin/crun",
- },
"kata": {
"/usr/bin/kata-runtime",
"/usr/sbin/kata-runtime",
@@ -280,6 +279,9 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
"/usr/bin/kata-fc",
},
}
+ // Needs to be called after populating c.OCIRuntimes
+ c.OCIRuntime = c.findRuntime()
+
c.ConmonEnvVars = []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
@@ -318,7 +320,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
func defaultTmpDir() (string, error) {
if !unshare.IsRootless() {
- return "/var/run/libpod", nil
+ return "/run/libpod", nil
}
runtimeDir, err := getRuntimeDir()
diff --git a/vendor/github.com/containers/common/pkg/seccomp/default_linux.go b/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
index 09629724d..a127571b5 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
@@ -75,6 +75,7 @@ func DefaultProfile() *Seccomp {
"clock_nanosleep_time64",
"clone",
"close",
+ "close_range",
"connect",
"copy_file_range",
"creat",
@@ -226,6 +227,8 @@ func DefaultProfile() *Seccomp {
"openat2",
"pause",
"pidfd_getfd",
+ "pidfd_open",
+ "pidfd_send_signal",
"pipe",
"pipe2",
"pivot_root",
diff --git a/vendor/github.com/containers/common/pkg/seccomp/seccomp.json b/vendor/github.com/containers/common/pkg/seccomp/seccomp.json
index bb5956418..8fb509345 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/seccomp.json
+++ b/vendor/github.com/containers/common/pkg/seccomp/seccomp.json
@@ -77,6 +77,7 @@
"clock_nanosleep_time64",
"clone",
"close",
+ "close_range",
"connect",
"copy_file_range",
"creat",
@@ -227,6 +228,8 @@
"openat2",
"pause",
"pidfd_getfd",
+ "pidfd_open",
+ "pidfd_send_signal",
"pipe",
"pipe2",
"pivot_root",
diff --git a/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go b/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
index 84a4c6ed5..8b23ee2c0 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
@@ -1,10 +1,10 @@
-// +build !seccomp
+// +build !linux !seccomp
// SPDX-License-Identifier: Apache-2.0
// Copyright 2013-2018 Docker, Inc.
-package seccomp
+package seccomp
import (
"errors"
@@ -38,3 +38,9 @@ func LoadProfileFromConfig(config *Seccomp, specgen *specs.Spec) (*specs.LinuxSe
func IsEnabled() bool {
return false
}
+
+// IsSupported returns true if the system has been configured to support
+// seccomp.
+func IsSupported() bool {
+ return false
+}
diff --git a/vendor/github.com/containers/common/pkg/seccomp/supported.go b/vendor/github.com/containers/common/pkg/seccomp/supported.go
index 1177ef630..e04324c8a 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/supported.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/supported.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build linux,seccomp
package seccomp
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
index 8df453484..4366848ea 100644
--- a/vendor/github.com/containers/common/version/version.go
+++ b/vendor/github.com/containers/common/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the version of the build.
-const Version = "0.31.0"
+const Version = "0.31.2"
diff --git a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go
index c46468930..1a60b96c4 100644
--- a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go
+++ b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go
@@ -13,7 +13,7 @@
// limitations under the License.
// Package capabilities provides a mapping from common kernel bit masks to the
-// alphanumerical represenation of kernel capabilities. See capabilities(7)
+// alphanumerical representation of kernel capabilities. See capabilities(7)
// for additional information.
package capabilities
diff --git a/vendor/github.com/containers/psgo/internal/dev/tty.go b/vendor/github.com/containers/psgo/internal/dev/tty.go
index b7d6f28ac..863767f75 100644
--- a/vendor/github.com/containers/psgo/internal/dev/tty.go
+++ b/vendor/github.com/containers/psgo/internal/dev/tty.go
@@ -113,8 +113,9 @@ func TTYs() (*[]TTY, error) {
}
s := fi.Sys().(*syscall.Stat_t)
t := TTY{
- Minor: minDevNum(s.Rdev),
- Major: majDevNum(s.Rdev),
+ // Rdev is type uint32 on mips arch so we have to cast to uint64
+ Minor: minDevNum(uint64(s.Rdev)),
+ Major: majDevNum(uint64(s.Rdev)),
Path: dev,
}
ttys = append(ttys, t)
diff --git a/vendor/github.com/containers/psgo/internal/proc/status.go b/vendor/github.com/containers/psgo/internal/proc/status.go
index 29d059361..df31139f8 100644
--- a/vendor/github.com/containers/psgo/internal/proc/status.go
+++ b/vendor/github.com/containers/psgo/internal/proc/status.go
@@ -24,7 +24,7 @@ import (
"github.com/pkg/errors"
)
-// Status is a direct translation of a `/proc/[pid]/status`, wich provides much
+// Status is a direct translation of a `/proc/[pid]/status`, which provides much
// of the information in /proc/[pid]/stat and /proc/[pid]/statm in a format
// that's easier for humans to parse.
type Status struct {
diff --git a/vendor/github.com/containers/psgo/internal/process/process.go b/vendor/github.com/containers/psgo/internal/process/process.go
index b46a39f46..a581921d5 100644
--- a/vendor/github.com/containers/psgo/internal/process/process.go
+++ b/vendor/github.com/containers/psgo/internal/process/process.go
@@ -31,9 +31,9 @@ type Process struct {
Pid string
// Stat contains data from /proc/$pid/stat.
Stat proc.Stat
- // Status containes data from /proc/$pid/status.
+ // Status contains data from /proc/$pid/status.
Status proc.Status
- // CmdLine containes data from /proc/$pid/cmdline.
+ // CmdLine contains data from /proc/$pid/cmdline.
CmdLine []string
// Label containers data from /proc/$pid/attr/current.
Label string
diff --git a/vendor/github.com/containers/psgo/psgo.go b/vendor/github.com/containers/psgo/psgo.go
index c75fc3815..7c74fd716 100644
--- a/vendor/github.com/containers/psgo/psgo.go
+++ b/vendor/github.com/containers/psgo/psgo.go
@@ -482,7 +482,7 @@ func JoinNamespaceAndProcessInfoByPidsWithOptions(pids []string, descriptors []s
// catch race conditions
continue
}
- return nil, errors.Wrapf(err, "error extracing PID namespace")
+ return nil, errors.Wrapf(err, "error extracting PID namespace")
}
if _, exists := nsMap[ns]; !exists {
nsMap[ns] = true
@@ -759,7 +759,7 @@ func processVSZ(p *process.Process, ctx *psContext) (string, error) {
}
// parseCAP parses cap (a string bit mask) and returns the associated set of
-// capabilities. If all capabilties are set, "full" is returned. If no
+// capabilities. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func parseCAP(cap string) (string, error) {
mask, err := strconv.ParseUint(cap, 16, 64)
@@ -777,36 +777,36 @@ func parseCAP(cap string) (string, error) {
return strings.Join(caps, ","), nil
}
-// processCAPAMB returns the set of ambient capabilties associated with
-// process p. If all capabilties are set, "full" is returned. If no
+// processCAPAMB returns the set of ambient capabilities associated with
+// process p. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func processCAPAMB(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapAmb)
}
-// processCAPINH returns the set of inheritable capabilties associated with
-// process p. If all capabilties are set, "full" is returned. If no
+// processCAPINH returns the set of inheritable capabilities associated with
+// process p. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func processCAPINH(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapInh)
}
-// processCAPPRM returns the set of permitted capabilties associated with
-// process p. If all capabilties are set, "full" is returned. If no
+// processCAPPRM returns the set of permitted capabilities associated with
+// process p. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func processCAPPRM(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapPrm)
}
-// processCAPEFF returns the set of effective capabilties associated with
-// process p. If all capabilties are set, "full" is returned. If no
+// processCAPEFF returns the set of effective capabilities associated with
+// process p. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func processCAPEFF(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapEff)
}
-// processCAPBND returns the set of bounding capabilties associated with
-// process p. If all capabilties are set, "full" is returned. If no
+// processCAPBND returns the set of bounding capabilities associated with
+// process p. If all capabilities are set, "full" is returned. If no
// capability is enabled, "none" is returned.
func processCAPBND(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapBnd)
diff --git a/vendor/github.com/containers/storage/.cirrus.yml b/vendor/github.com/containers/storage/.cirrus.yml
index 539bfeabb..cc2dd7952 100644
--- a/vendor/github.com/containers/storage/.cirrus.yml
+++ b/vendor/github.com/containers/storage/.cirrus.yml
@@ -17,19 +17,19 @@ env:
####
#### Cache-image names to test with (double-quotes around names are critical)
###
- FEDORA_NAME: "fedora"
- PRIOR_FEDORA_NAME: "prior-fedora"
- UBUNTU_NAME: "ubuntu"
- PRIOR_UBUNTU_NAME: "prior-ubuntu"
+ FEDORA_NAME: "fedora-33"
+ PRIOR_FEDORA_NAME: "fedora-32"
+ UBUNTU_NAME: "ubuntu-2010"
+ PRIOR_UBUNTU_NAME: "ubuntu-2004"
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
# VM Image built in containers/automation_images
- _BUILT_IMAGE_SUFFIX: "c4948709391728640"
- FEDORA_CACHE_IMAGE_NAME: "${FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
- PRIOR_FEDORA_CACHE_IMAGE_NAME: "${PRIOR_FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
- UBUNTU_CACHE_IMAGE_NAME: "${UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}"
- PRIOR_UBUNTU_CACHE_IMAGE_NAME: "${PRIOR_UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}"
+ _BUILT_IMAGE_SUFFIX: "c6233039174893568"
+ FEDORA_CACHE_IMAGE_NAME: "fedora-${_BUILT_IMAGE_SUFFIX}"
+ PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${_BUILT_IMAGE_SUFFIX}"
+ UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${_BUILT_IMAGE_SUFFIX}"
+ PRIOR_UBUNTU_CACHE_IMAGE_NAME: "prior-ubuntu-${_BUILT_IMAGE_SUFFIX}"
####
#### Command variables to help avoid duplication
@@ -57,42 +57,30 @@ gce_instance:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
-testing_task:
-
+fedora_testing_task: &fedora_testing
+ alias: fedora_testing
+ name: &std_test_name "${OS_NAME} ${TEST_DRIVER}"
depends_on:
- lint
- # Not all $TEST_DRIVER combinations are valid for all OS types.
- # N/B: As of the addition of this note, nested-variable resolution
- # does not happen for boolean `only_if` expressions. Since $VM_IMAGE
- # contains nested variables, we must filter based on that and not the
- # actual distro/version value.
- only_if: >-
- ( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "vfs" ) ||
- ( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "aufs" ) ||
- ( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "overlay" ) ||
- ( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "fuse-overlay" ) ||
- ( $VM_IMAGE =~ '.*FEDORA.*' && $TEST_DRIVER != "aufs" )
-
- allow_failures: $TEST_DRIVER == "devicemapper"
+ gce_instance: # Only need to specify differences from defaults (above)
+ image_name: "${VM_IMAGE}"
env:
- matrix:
- VM_IMAGE: "${FEDORA_CACHE_IMAGE_NAME}"
- VM_IMAGE: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
- VM_IMAGE: "${UBUNTU_CACHE_IMAGE_NAME}"
- # VM_IMAGE: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}" # No fuse3 support
- matrix: # See ./contrib/cirrus/build_and_test.sh
+ OS_NAME: "${FEDORA_NAME}"
+ VM_IMAGE: "${FEDORA_CACHE_IMAGE_NAME}"
+
+ # Not all $TEST_DRIVER combinations valid for all $VM_IMAGE types.
+ matrix: &test_matrix
+ - env:
TEST_DRIVER: "vfs"
- TEST_DRIVER: "aufs"
+ - env:
TEST_DRIVER: "overlay"
+ - env:
TEST_DRIVER: "fuse-overlay"
- TEST_DRIVER: "devicemapper"
+ - env:
TEST_DRIVER: "fuse-overlay-whiteout"
- gce_instance: # Only need to specify differences from defaults (above)
- image_name: "${VM_IMAGE}"
-
# Separate scripts for separate outputs, makes debugging easier.
setup_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}'
build_and_test_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/build_and_test.sh |& ${_TIMESTAMP}'
@@ -103,6 +91,41 @@ testing_task:
ubuntu_audit_log_script: '${_UAUDITCMD} || true'
journal_log_script: '${_JOURNALCMD} || true'
+
+prior_fedora_testing_task:
+ <<: *fedora_testing
+ alias: prior_fedora_testing
+ name: *std_test_name
+ env:
+ OS_NAME: "${PRIOR_FEDORA_NAME}"
+ VM_IMAGE: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+
+
+ubuntu_testing_task: &ubuntu_testing
+ <<: *fedora_testing
+ alias: ubuntu_testing
+ name: *std_test_name
+ env:
+ OS_NAME: "${UBUNTU_NAME}"
+ VM_IMAGE: "${UBUNTU_CACHE_IMAGE_NAME}"
+ matrix:
+ - env:
+ TEST_DRIVER: "vfs"
+ - env:
+ TEST_DRIVER: "aufs"
+ - env:
+ TEST_DRIVER: "overlay"
+
+
+prior_ubuntu_testing_task:
+ <<: *ubuntu_testing
+ alias: prior_ubuntu_testing
+ name: *std_test_name
+ env:
+ OS_NAME: "${PRIOR_UBUNTU_NAME}"
+ VM_IMAGE: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
+
+
lint_task:
env:
CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage"
@@ -117,6 +140,7 @@ lint_task:
apt-get install -y libbtrfs-dev libdevmapper-dev
test_script: make lint
+
# Update metadata on VM images referenced by this repository state
meta_task:
@@ -141,6 +165,7 @@ meta_task:
script: '/usr/local/bin/entrypoint.sh |& ${_TIMESTAMP}'
+
vendor_task:
container:
image: golang:1.15
@@ -150,11 +175,15 @@ vendor_task:
build_script: make vendor
test_script: hack/tree_status.sh
+
# Represent overall pass/fail status from required dependent tasks
success_task:
depends_on:
- lint
- - testing
+ - fedora_testing
+ - prior_fedora_testing
+ - ubuntu_testing
+ - prior_ubuntu_testing
- meta
- vendor
container:
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index f9e8384bb..2f4320f67 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.24.1
+1.24.4
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 86a5d8644..b19b4a7c4 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -4,11 +4,11 @@ module github.com/containers/storage
require (
github.com/BurntSushi/toml v0.3.1
- github.com/Microsoft/go-winio v0.4.15
- github.com/Microsoft/hcsshim v0.8.9
+ github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331
+ github.com/Microsoft/hcsshim v0.8.14
github.com/docker/go-units v0.4.0
github.com/hashicorp/go-multierror v1.1.0
- github.com/klauspost/compress v1.11.3
+ github.com/klauspost/compress v1.11.4
github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
@@ -16,7 +16,7 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.0.0-rc91
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
- github.com/opencontainers/selinux v1.6.0
+ github.com/opencontainers/selinux v1.8.0
github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.7.0
@@ -25,6 +25,6 @@ require (
github.com/tchap/go-patricia v2.3.0+incompatible
github.com/vbatts/tar-split v0.11.1
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
- golang.org/x/sys v0.0.0-20200909081042-eff7692f9009
+ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3
gotest.tools v2.2.0+incompatible
)
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index a5d3f3b82..a7be24d40 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -1,19 +1,18 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc=
-github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331 h1:3YnB7Hpmh1lPecPE8doMOtYCrMdrpedZOvxfuNES/Vk=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/hcsshim v0.8.14 h1:lbPVK25c1cu5xTLITwpUcxoA9vKrKErASPYygvouJns=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/checkpoint-restore/go-criu/v4 v4.0.2 h1:jt+rnBIhFtPw0fhtpYGcUOilh4aO9Hj7r+YLEtf30uA=
github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 h1:qcqzLJa2xCo9sgdCzpT/SJSYxROTEstuhf7ZBHMirms=
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ=
@@ -24,12 +23,11 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -37,11 +35,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -61,14 +56,14 @@ github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
-github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.4 h1:kz40R/YWls3iqT9zX9AHN3WoVsrAWVyui5sxuLqiXqU=
+github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -92,13 +87,12 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc91 h1:Tp8LWs5G8rFpzTsbRjAtQkPVexhCu0bnANE5IfIhJ6g=
github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT54jbi72tT/HqgflT8=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
-github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
-github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -130,18 +124,17 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
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/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
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/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
-github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM=
-github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -166,21 +159,23 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index 2f917344a..aa4875c64 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -641,7 +641,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
}
file.Close()
- case tar.TypeBlock, tar.TypeChar:
+ case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
if inUserns { // cannot create devices in a userns
return nil
}
@@ -650,12 +650,6 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
return err
}
- case tar.TypeFifo:
- // Handle this is an OS-specific way
- if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
- return err
- }
-
case tar.TypeLink:
targetPath := filepath.Join(extractDir, hdr.Linkname)
// check for hardlink breakout
diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf
index 0577e84ca..3ff708e20 100644
--- a/vendor/github.com/containers/storage/storage.conf
+++ b/vendor/github.com/containers/storage/storage.conf
@@ -4,11 +4,11 @@
# The "container storage" table contains all of the server options.
[storage]
-# Default Storage Driver
+# Default Storage Driver, Must be set for proper operation.
driver = ""
# Temporary storage location
-runroot = "/var/run/containers/storage"
+runroot = "/run/containers/storage"
# Primary Read/Write location of container storage
graphroot = "/var/lib/containers/storage"
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index b9115f195..0b53d81ce 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -30,6 +30,7 @@ import (
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
var (
@@ -3527,6 +3528,9 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) {
if config.Storage.Driver != "" {
storeOptions.GraphDriverName = config.Storage.Driver
}
+ if storeOptions.GraphDriverName == "" {
+ logrus.Errorf("The storage 'driver' option must be set in %s, guarantee proper operation.", configFile)
+ }
if config.Storage.RunRoot != "" {
storeOptions.RunRoot = config.Storage.RunRoot
}
@@ -3636,7 +3640,7 @@ func reloadConfigurationFileIfNeeded(configFile string, storeOptions *StoreOptio
}
func init() {
- defaultStoreOptions.RunRoot = "/var/run/containers/storage"
+ defaultStoreOptions.RunRoot = "/run/containers/storage"
defaultStoreOptions.GraphRoot = "/var/lib/containers/storage"
defaultStoreOptions.GraphDriverName = ""
diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go
index 524404cc5..daf3639c1 100644
--- a/vendor/github.com/google/uuid/uuid.go
+++ b/vendor/github.com/google/uuid/uuid.go
@@ -35,6 +35,12 @@ const (
var rander = rand.Reader // random function
+type invalidLengthError struct{ len int }
+
+func (err *invalidLengthError) Error() string {
+ return fmt.Sprintf("invalid UUID length: %d", err.len)
+}
+
// Parse decodes s into a UUID or returns an error. Both the standard UUID
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
@@ -68,7 +74,7 @@ func Parse(s string) (UUID, error) {
}
return uuid, nil
default:
- return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
+ return uuid, &invalidLengthError{len(s)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
@@ -112,7 +118,7 @@ func ParseBytes(b []byte) (UUID, error) {
}
return uuid, nil
default:
- return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
+ return uuid, &invalidLengthError{len(b)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index 08e553f75..7680bfe1d 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -24,22 +24,21 @@ Godoc Documentation: https://godoc.org/github.com/klauspost/compress/zstd
### Status:
STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively
-used by several projects. This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz),
-kindly supplied by [fuzzit.dev](https://fuzzit.dev/).
+used by several projects. This library is being [fuzz-tested](https://github.com/klauspost/compress-fuzz) for all updates.
There may still be specific combinations of data types/size/settings that could lead to edge cases,
so as always, testing is recommended.
For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
-The "Fastest" compression ratio is roughly equivalent to zstd level 1.
-The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
+* The "Fastest" compression ratio is roughly equivalent to zstd level 1.
+* The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
+* The "Better" compression ratio is roughly equivalent to zstd level 7.
+* The "Best" compression ratio is roughly equivalent to zstd level 11.
In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
-Compared to cgo zstd, the speed is around level 3 (default), but compression slightly worse, between level 1&2.
-
### Usage
@@ -140,7 +139,7 @@ I have collected some speed examples to compare speed and compression against ot
* `file` is the input file.
* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library.
-* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default".
+* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".
* `insize`/`outsize` is the input/output size.
* `millis` is the number of milliseconds used for compression.
* `mb/s` is megabytes (2^20 bytes) per second.
@@ -154,11 +153,13 @@ file out level insize outsize millis mb/s
silesia.tar zskp 1 211947520 73101992 643 313.87
silesia.tar zskp 2 211947520 67504318 969 208.38
silesia.tar zskp 3 211947520 65177448 1899 106.44
+silesia.tar zskp 4 211947520 61381950 8115 24.91
cgo zstd:
silesia.tar zstd 1 211947520 73605392 543 371.56
silesia.tar zstd 3 211947520 66793289 864 233.68
silesia.tar zstd 6 211947520 62916450 1913 105.66
+silesia.tar zstd 9 211947520 60212393 5063 39.92
gzip, stdlib/this package:
silesia.tar gzstd 1 211947520 80007735 1654 122.21
@@ -171,9 +172,11 @@ file out level insize outsize millis mb/s
gob-stream zskp 1 1911399616 235022249 3088 590.30
gob-stream zskp 2 1911399616 205669791 3786 481.34
gob-stream zskp 3 1911399616 185792019 9324 195.48
+gob-stream zskp 4 1911399616 171537212 32113 56.76
gob-stream zstd 1 1911399616 249810424 2637 691.26
gob-stream zstd 3 1911399616 208192146 3490 522.31
gob-stream zstd 6 1911399616 193632038 6687 272.56
+gob-stream zstd 9 1911399616 177620386 16175 112.70
gob-stream gzstd 1 1911399616 357382641 10251 177.82
gob-stream gzkp 1 1911399616 362156523 5695 320.08
@@ -185,9 +188,11 @@ file out level insize outsize millis mb/s
enwik9 zskp 1 1000000000 343848582 3609 264.18
enwik9 zskp 2 1000000000 317276632 5746 165.97
enwik9 zskp 3 1000000000 294540704 11725 81.34
+enwik9 zskp 4 1000000000 276609671 44029 21.66
enwik9 zstd 1 1000000000 358072021 3110 306.65
enwik9 zstd 3 1000000000 313734672 4784 199.35
enwik9 zstd 6 1000000000 295138875 10290 92.68
+enwik9 zstd 9 1000000000 278348700 28549 33.40
enwik9 gzstd 1 1000000000 382578136 9604 99.30
enwik9 gzkp 1 1000000000 383825945 6544 145.73
@@ -198,9 +203,11 @@ file out level insize outsize millis mb/s
github-june-2days-2019.json zskp 1 6273951764 699045015 10620 563.40
github-june-2days-2019.json zskp 2 6273951764 617881763 11687 511.96
github-june-2days-2019.json zskp 3 6273951764 537511906 29252 204.54
+github-june-2days-2019.json zskp 4 6273951764 512796117 97791 61.18
github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00
github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57
github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18
+github-june-2days-2019.json zstd 9 6273951764 601974523 52413 114.16
github-june-2days-2019.json gzstd 1 6273951764 1164400847 29948 199.79
github-june-2days-2019.json gzkp 1 6273951764 1128755542 19236 311.03
@@ -211,9 +218,11 @@ file out level insize outsize millis mb/s
rawstudio-mint14.tar zskp 1 8558382592 3667489370 20210 403.84
rawstudio-mint14.tar zskp 2 8558382592 3364592300 31873 256.07
rawstudio-mint14.tar zskp 3 8558382592 3224594213 71751 113.75
+rawstudio-mint14.tar zskp 4 8558382592 3027332295 486243 16.79
rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27
rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92
rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77
+rawstudio-mint14.tar zstd 9 8558382592 3160778861 140946 57.91
rawstudio-mint14.tar gzstd 1 8558382592 3926257486 57722 141.40
rawstudio-mint14.tar gzkp 1 8558382592 3970463184 41749 195.49
@@ -224,9 +233,11 @@ file out level insize outsize millis mb/s
nyc-taxi-data-10M.csv zskp 1 3325605752 641339945 8925 355.35
nyc-taxi-data-10M.csv zskp 2 3325605752 591748091 11268 281.44
nyc-taxi-data-10M.csv zskp 3 3325605752 538490114 19880 159.53
+nyc-taxi-data-10M.csv zskp 4 3325605752 495986829 89368 35.49
nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18
nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07
nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27
+nyc-taxi-data-10M.csv zstd 9 3325605752 517554797 64565 49.12
nyc-taxi-data-10M.csv gzstd 1 3325605752 928656485 23876 132.83
nyc-taxi-data-10M.csv gzkp 1 3325605752 924718719 16388 193.53
```
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index 4733ea876..b51d922bd 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -613,7 +613,7 @@ func (b *blockDec) decodeCompressed(hist *history) error {
// Decode treeless literal block.
if litType == literalsBlockTreeless {
// TODO: We could send the history early WITHOUT the stream history.
- // This would allow decoding treeless literials before the byte history is available.
+ // This would allow decoding treeless literals before the byte history is available.
// Silencia stats: Treeless 4393, with: 32775, total: 37168, 11% treeless.
// So not much obvious gain here.
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
index 083fbb502..c85c40255 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -76,6 +76,7 @@ func (b *blockEnc) reset(prev *blockEnc) {
if prev != nil {
b.recentOffsets = prev.prevRecentOffsets
}
+ b.dictLitEnc = nil
}
// reset will reset the block for a new encode, but in the same stream,
diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
new file mode 100644
index 000000000..87896c5ea
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
@@ -0,0 +1,202 @@
+// Copyright 2020+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "bytes"
+ "errors"
+ "io"
+)
+
+// HeaderMaxSize is the maximum size of a Frame and Block Header.
+// If less is sent to Header.Decode it *may* still contain enough information.
+const HeaderMaxSize = 14 + 3
+
+// Header contains information about the first frame and block within that.
+type Header struct {
+ // Window Size the window of data to keep while decoding.
+ // Will only be set if HasFCS is false.
+ WindowSize uint64
+
+ // Frame content size.
+ // Expected size of the entire frame.
+ FrameContentSize uint64
+
+ // Dictionary ID.
+ // If 0, no dictionary.
+ DictionaryID uint32
+
+ // First block information.
+ FirstBlock struct {
+ // OK will be set if first block could be decoded.
+ OK bool
+
+ // Is this the last block of a frame?
+ Last bool
+
+ // Is the data compressed?
+ // If true CompressedSize will be populated.
+ // Unfortunately DecompressedSize cannot be determined
+ // without decoding the blocks.
+ Compressed bool
+
+ // DecompressedSize is the expected decompressed size of the block.
+ // Will be 0 if it cannot be determined.
+ DecompressedSize int
+
+ // CompressedSize of the data in the block.
+ // Does not include the block header.
+ // Will be equal to DecompressedSize if not Compressed.
+ CompressedSize int
+ }
+
+ // Skippable will be true if the frame is meant to be skipped.
+ // No other information will be populated.
+ Skippable bool
+
+ // If set there is a checksum present for the block content.
+ HasCheckSum bool
+
+ // If this is true FrameContentSize will have a valid value
+ HasFCS bool
+
+ SingleSegment bool
+}
+
+// Decode the header from the beginning of the stream.
+// This will decode the frame header and the first block header if enough bytes are provided.
+// It is recommended to provide at least HeaderMaxSize bytes.
+// If the frame header cannot be read an error will be returned.
+// If there isn't enough input, io.ErrUnexpectedEOF is returned.
+// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
+func (h *Header) Decode(in []byte) error {
+ if len(in) < 4 {
+ return io.ErrUnexpectedEOF
+ }
+ b, in := in[:4], in[4:]
+ if !bytes.Equal(b, frameMagic) {
+ if !bytes.Equal(b[1:4], skippableFrameMagic) || b[0]&0xf0 != 0x50 {
+ return ErrMagicMismatch
+ }
+ *h = Header{Skippable: true}
+ return nil
+ }
+ if len(in) < 1 {
+ return io.ErrUnexpectedEOF
+ }
+
+ // Clear output
+ *h = Header{}
+ fhd, in := in[0], in[1:]
+ h.SingleSegment = fhd&(1<<5) != 0
+ h.HasCheckSum = fhd&(1<<2) != 0
+
+ if fhd&(1<<3) != 0 {
+ return errors.New("Reserved bit set on frame header")
+ }
+
+ // Read Window_Descriptor
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
+ if !h.SingleSegment {
+ if len(in) < 1 {
+ return io.ErrUnexpectedEOF
+ }
+ var wd byte
+ wd, in = in[0], in[1:]
+ windowLog := 10 + (wd >> 3)
+ windowBase := uint64(1) << windowLog
+ windowAdd := (windowBase / 8) * uint64(wd&0x7)
+ h.WindowSize = windowBase + windowAdd
+ }
+
+ // Read Dictionary_ID
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
+ if size := fhd & 3; size != 0 {
+ if size == 3 {
+ size = 4
+ }
+ if len(in) < int(size) {
+ return io.ErrUnexpectedEOF
+ }
+ b, in = in[:size], in[size:]
+ if b == nil {
+ return io.ErrUnexpectedEOF
+ }
+ switch size {
+ case 1:
+ h.DictionaryID = uint32(b[0])
+ case 2:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
+ case 4:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ }
+ }
+
+ // Read Frame_Content_Size
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
+ var fcsSize int
+ v := fhd >> 6
+ switch v {
+ case 0:
+ if h.SingleSegment {
+ fcsSize = 1
+ }
+ default:
+ fcsSize = 1 << v
+ }
+
+ if fcsSize > 0 {
+ h.HasFCS = true
+ if len(in) < fcsSize {
+ return io.ErrUnexpectedEOF
+ }
+ b, in = in[:fcsSize], in[fcsSize:]
+ if b == nil {
+ return io.ErrUnexpectedEOF
+ }
+ switch fcsSize {
+ case 1:
+ h.FrameContentSize = uint64(b[0])
+ case 2:
+ // When FCS_Field_Size is 2, the offset of 256 is added.
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
+ case 4:
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
+ case 8:
+ d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
+ h.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
+ }
+ }
+
+ // Frame Header done, we will not fail from now on.
+ if len(in) < 3 {
+ return nil
+ }
+ tmp, in := in[:3], in[3:]
+ bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
+ h.FirstBlock.Last = bh&1 != 0
+ blockType := blockType((bh >> 1) & 3)
+ // find size.
+ cSize := int(bh >> 3)
+ switch blockType {
+ case blockTypeReserved:
+ return nil
+ case blockTypeRLE:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = 1
+ case blockTypeCompressed:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.CompressedSize = cSize
+ case blockTypeRaw:
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = cSize
+ default:
+ panic("Invalid block type")
+ }
+
+ h.FirstBlock.OK = true
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go
new file mode 100644
index 000000000..c4baa42c6
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go
@@ -0,0 +1,484 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+ "math/bits"
+)
+
+const (
+ bestLongTableBits = 20 // Bits used in the long match table
+ bestLongTableSize = 1 << bestLongTableBits // Size of the table
+
+ // Note: Increasing the short table bits or making the hash shorter
+ // can actually lead to compression degradation since it will 'steal' more from the
+ // long match table and match offsets are quite big.
+ // This greatly depends on the type of input.
+ bestShortTableBits = 16 // Bits used in the short match table
+ bestShortTableSize = 1 << bestShortTableBits // Size of the table
+)
+
+// bestFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches.
+// The long match table contains the previous entry with the same hash,
+// effectively making it a "chain" of length 2.
+// When we find a long match we choose between the two values and select the longest.
+// When we find a short match, after checking the long, we check if we can find a long at n+1
+// and that it is longer (lazy matching).
+type bestFastEncoder struct {
+ fastBase
+ table [bestShortTableSize]prevEntry
+ longTable [bestLongTableSize]prevEntry
+ dictTable []prevEntry
+ dictLongTable []prevEntry
+}
+
+// Encode improves compression...
+func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 4
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = prevEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = prevEntry{}
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ v2 := e.table[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.table[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ const kSearchStrength = 12
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+ offset3 := int32(blk.recentOffsets[2])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ _ = addLiterals
+
+ if debug {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ type match struct {
+ offset int32
+ s int32
+ length int32
+ rep int32
+ }
+ matchAt := func(offset int32, s int32, first uint32, rep int32) match {
+ if s-offset >= e.maxMatchOff || load3232(src, offset) != first {
+ return match{offset: offset, s: s}
+ }
+ return match{offset: offset, s: s, length: 4 + e.matchlen(s+4, offset+4, src), rep: rep}
+ }
+
+ bestOf := func(a, b match) match {
+ aScore := b.s - a.s + a.length
+ bScore := a.s - b.s + b.length
+ if a.rep < 0 {
+ aScore = aScore - int32(bits.Len32(uint32(a.offset)))/8
+ }
+ if b.rep < 0 {
+ bScore = bScore - int32(bits.Len32(uint32(b.offset)))/8
+ }
+ if aScore >= bScore {
+ return a
+ }
+ return b
+ }
+ const goodEnough = 100
+
+ nextHashL := hash8(cv, bestLongTableBits)
+ nextHashS := hash4x64(cv, bestShortTableBits)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ best := bestOf(matchAt(candidateL.offset-e.cur, s, uint32(cv), -1), matchAt(candidateL.prev-e.cur, s, uint32(cv), -1))
+ best = bestOf(best, matchAt(candidateS.offset-e.cur, s, uint32(cv), -1))
+ best = bestOf(best, matchAt(candidateS.prev-e.cur, s, uint32(cv), -1))
+ if canRepeat && best.length < goodEnough {
+ best = bestOf(best, matchAt(s-offset1+1, s+1, uint32(cv>>8), 1))
+ best = bestOf(best, matchAt(s-offset2+1, s+1, uint32(cv>>8), 2))
+ best = bestOf(best, matchAt(s-offset3+1, s+1, uint32(cv>>8), 3))
+ best = bestOf(best, matchAt(s-offset1+3, s+3, uint32(cv>>24), 1))
+ best = bestOf(best, matchAt(s-offset2+3, s+3, uint32(cv>>24), 2))
+ best = bestOf(best, matchAt(s-offset3+3, s+3, uint32(cv>>24), 3))
+ }
+ // Load next and check...
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset}
+ e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset}
+
+ // Look far ahead, unless we have a really long match already...
+ if best.length < goodEnough {
+ // No match found, move forward on input, no need to check forward...
+ if best.length < 4 {
+ s += 1 + (s-nextEmit)>>(kSearchStrength-1)
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+
+ s++
+ candidateS = e.table[hash4x64(cv>>8, bestShortTableBits)]
+ cv = load6432(src, s)
+ cv2 := load6432(src, s+1)
+ candidateL = e.longTable[hash8(cv, bestLongTableBits)]
+ candidateL2 := e.longTable[hash8(cv2, bestLongTableBits)]
+
+ best = bestOf(best, matchAt(candidateS.offset-e.cur, s, uint32(cv), -1))
+ best = bestOf(best, matchAt(candidateL.offset-e.cur, s, uint32(cv), -1))
+ best = bestOf(best, matchAt(candidateL.prev-e.cur, s, uint32(cv), -1))
+ best = bestOf(best, matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1))
+ best = bestOf(best, matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1))
+ }
+
+ // We have a match, we can store the forward value
+ if best.rep > 0 {
+ s = best.s
+ var seq seq
+ seq.matchLen = uint32(best.length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := best.s
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := s - e.maxMatchOff
+ if tMin < 0 {
+ tMin = 0
+ }
+ repIndex := best.offset
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = uint32(best.rep)
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index match start+1 (long) -> s - 1
+ index0 := s
+ s = best.s + best.length
+
+ nextEmit = s
+ if s >= sLimit {
+ if debug {
+ println("repeat ended", s, best.length)
+
+ }
+ break encodeLoop
+ }
+ // Index skipped...
+ off := index0 + e.cur
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ h0 := hash8(cv0, bestLongTableBits)
+ h1 := hash4x64(cv0, bestShortTableBits)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ off++
+ index0++
+ }
+ switch best.rep {
+ case 2:
+ offset1, offset2 = offset2, offset1
+ case 3:
+ offset1, offset2, offset3 = offset3, offset1, offset2
+ }
+ cv = load6432(src, s)
+ continue
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ s = best.s
+ t := best.offset
+ offset1, offset2, offset3 = s-t, offset1, offset2
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the n-byte match as long as possible.
+ l := best.length
+
+ // Extend backwards
+ tMin := s - e.maxMatchOff
+ if tMin < 0 {
+ tMin = 0
+ }
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) -> s - 1
+ index0 := s - l + 1
+ // every entry
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ h0 := hash8(cv0, bestLongTableBits)
+ h1 := hash4x64(cv0, bestShortTableBits)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ index0++
+ }
+
+ cv = load6432(src, s)
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hash4x64(cv, bestShortTableBits)
+ nextHashL := hash8(cv, bestLongTableBits)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
+ e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: e.table[nextHashS].offset}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ blk.recentOffsets[2] = uint32(offset3)
+ if debug {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *bestFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ e.Encode(blk, src)
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]prevEntry, len(e.table))
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = bestShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hash4x64(cv, hashLog) // 0 -> 4
+ nextHash1 := hash4x64(cv>>8, hashLog) // 1 -> 5
+ nextHash2 := hash4x64(cv>>16, hashLog) // 2 -> 6
+ nextHash3 := hash4x64(cv>>24, hashLog) // 3 -> 7
+ e.dictTable[nextHash] = prevEntry{
+ prev: e.dictTable[nextHash].offset,
+ offset: i,
+ }
+ e.dictTable[nextHash1] = prevEntry{
+ prev: e.dictTable[nextHash1].offset,
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = prevEntry{
+ prev: e.dictTable[nextHash2].offset,
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = prevEntry{
+ prev: e.dictTable[nextHash3].offset,
+ offset: i + 3,
+ }
+ }
+ e.lastDictID = d.id
+ }
+
+ // Init or copy dict table
+ if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hash8(cv, bestLongTableBits)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hash8(cv, bestLongTableBits)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ e.lastDictID = d.id
+ }
+ // Reset table to initial state
+ copy(e.longTable[:], e.dictLongTable)
+
+ e.cur = e.maxMatchOff
+ // Reset table to initial state
+ copy(e.table[:], e.dictTable)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
index 1209915bc..a7312f42a 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -47,6 +47,8 @@ func (o encoderOptions) encoder() encoder {
return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize)}}}
case SpeedBetterCompression:
return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize)}}
+ case SpeedBestCompression:
+ return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize)}}
case SpeedFastest:
return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize)}}
}
@@ -143,20 +145,20 @@ const (
// By using this, notice that CPU usage may go up in the future.
SpeedBetterCompression
+ // SpeedBestCompression will choose the best available compression option.
+ // This will offer the best compression no matter the CPU cost.
+ SpeedBestCompression
+
// speedLast should be kept as the last actual compression option.
// The is not for external usage, but is used to keep track of the valid options.
speedLast
-
- // SpeedBestCompression will choose the best available compression option.
- // For now this is not implemented.
- SpeedBestCompression = SpeedBetterCompression
)
// EncoderLevelFromString will convert a string representation of an encoding level back
// to a compression level. The compare is not case sensitive.
// If the string wasn't recognized, (false, SpeedDefault) will be returned.
func EncoderLevelFromString(s string) (bool, EncoderLevel) {
- for l := EncoderLevel(speedNotSet + 1); l < speedLast; l++ {
+ for l := speedNotSet + 1; l < speedLast; l++ {
if strings.EqualFold(s, l.String()) {
return true, l
}
@@ -173,7 +175,9 @@ func EncoderLevelFromZstd(level int) EncoderLevel {
return SpeedFastest
case level >= 3 && level < 6:
return SpeedDefault
- case level > 5:
+ case level >= 6 && level < 10:
+ return SpeedBetterCompression
+ case level >= 10:
return SpeedBetterCompression
}
return SpeedDefault
@@ -188,6 +192,8 @@ func (e EncoderLevel) String() string {
return "default"
case SpeedBetterCompression:
return "better"
+ case SpeedBestCompression:
+ return "best"
default:
return "invalid"
}
@@ -209,6 +215,8 @@ func WithEncoderLevel(l EncoderLevel) EOption {
o.windowSize = 8 << 20
case SpeedBetterCompression:
o.windowSize = 16 << 20
+ case SpeedBestCompression:
+ o.windowSize = 32 << 20
}
}
if !o.customALEntropy {
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/doc.go b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
index 79a8e6446..9c9cbd120 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
@@ -5,9 +5,6 @@ This package uses a selinux build tag to enable the selinux functionality. This
allows non-linux and linux users who do not have selinux support to still use
tools that rely on this library.
-To compile with full selinux support use the -tags=selinux option in your build
-and test commands.
-
Usage:
import "github.com/opencontainers/selinux/go-selinux"
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
index 988adc8f4..439455511 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
@@ -1,5 +1,3 @@
-// +build selinux,linux
-
package label
import (
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
index a7d2d5e34..02d206239 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
@@ -1,4 +1,4 @@
-// +build !selinux !linux
+// +build !linux
package label
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 904f5b04f..5bfcc0490 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -1,5 +1,3 @@
-// +build selinux,linux
-
package selinux
import (
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 e4b65c9e2..70b7b7c85 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
@@ -1,4 +1,4 @@
-// +build !selinux !linux
+// +build !linux
package selinux
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
index 2365b4bda..117c255be 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
@@ -1,5 +1,3 @@
-// +build selinux,linux
-
package selinux
import (
diff --git a/vendor/github.com/vishvananda/netlink/.travis.yml b/vendor/github.com/vishvananda/netlink/.travis.yml
index 7d14af4d6..80219c69d 100644
--- a/vendor/github.com/vishvananda/netlink/.travis.yml
+++ b/vendor/github.com/vishvananda/netlink/.travis.yml
@@ -1,8 +1,8 @@
language: go
go:
- - "1.10.x"
- - "1.11.x"
- "1.12.x"
+ - "1.13.x"
+ - "1.14.x"
before_script:
# make sure we keep path in tact when we sudo
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
@@ -14,6 +14,7 @@ before_script:
- sudo modprobe nf_conntrack_ipv4
- sudo modprobe nf_conntrack_ipv6
- sudo modprobe sch_hfsc
+ - sudo modprobe sch_sfq
install:
- - go get github.com/vishvananda/netns
+ - go get -v -t ./...
go_import_path: github.com/vishvananda/netlink
diff --git a/vendor/github.com/vishvananda/netlink/addr.go b/vendor/github.com/vishvananda/netlink/addr.go
index f08c95696..653f540db 100644
--- a/vendor/github.com/vishvananda/netlink/addr.go
+++ b/vendor/github.com/vishvananda/netlink/addr.go
@@ -17,6 +17,7 @@ type Addr struct {
Broadcast net.IP
PreferedLft int
ValidLft int
+ LinkIndex int
}
// String returns $ip/$netmask $label
diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go
index 28746d5af..71da251ca 100644
--- a/vendor/github.com/vishvananda/netlink/addr_linux.go
+++ b/vendor/github.com/vishvananda/netlink/addr_linux.go
@@ -11,9 +11,6 @@ import (
"golang.org/x/sys/unix"
)
-// IFA_FLAGS is a u32 attribute.
-const IFA_FLAGS = 0x8
-
// AddrAdd will add an IP address to a link device.
//
// Equivalent to: `ip addr add $addr dev $link`
@@ -125,7 +122,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
} else {
b := make([]byte, 4)
native.PutUint32(b, uint32(addr.Flags))
- flagsData := nl.NewRtAttr(IFA_FLAGS, b)
+ flagsData := nl.NewRtAttr(unix.IFA_FLAGS, b)
req.AddData(flagsData)
}
}
@@ -156,10 +153,10 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
// value should be "forever". To compensate for that, only add the attributes if at least one of the values is
// non-zero, which means the caller has explicitly set them
if addr.ValidLft > 0 || addr.PreferedLft > 0 {
- cachedata := nl.IfaCacheInfo{
- IfaValid: uint32(addr.ValidLft),
- IfaPrefered: uint32(addr.PreferedLft),
- }
+ cachedata := nl.IfaCacheInfo{unix.IfaCacheinfo{
+ Valid: uint32(addr.ValidLft),
+ Prefered: uint32(addr.PreferedLft),
+ }}
req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
}
@@ -196,12 +193,12 @@ func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
var res []Addr
for _, m := range msgs {
- addr, msgFamily, ifindex, err := parseAddr(m)
+ addr, msgFamily, err := parseAddr(m)
if err != nil {
return res, err
}
- if link != nil && ifindex != indexFilter {
+ if link != nil && addr.LinkIndex != indexFilter {
// Ignore messages from other interfaces
continue
}
@@ -216,11 +213,11 @@ func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
return res, nil
}
-func parseAddr(m []byte) (addr Addr, family, index int, err error) {
+func parseAddr(m []byte) (addr Addr, family int, err error) {
msg := nl.DeserializeIfAddrmsg(m)
family = -1
- index = -1
+ addr.LinkIndex = -1
attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
if err1 != nil {
@@ -229,7 +226,7 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
}
family = int(msg.Family)
- index = int(msg.Index)
+ addr.LinkIndex = int(msg.Index)
var local, dst *net.IPNet
for _, attr := range attrs {
@@ -254,12 +251,12 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
addr.Broadcast = attr.Value
case unix.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1])
- case IFA_FLAGS:
+ case unix.IFA_FLAGS:
addr.Flags = int(native.Uint32(attr.Value[0:4]))
- case nl.IFA_CACHEINFO:
+ case unix.IFA_CACHEINFO:
ci := nl.DeserializeIfaCacheInfo(attr.Value)
- addr.PreferedLft = int(ci.IfaPrefered)
- addr.ValidLft = int(ci.IfaValid)
+ addr.PreferedLft = int(ci.Prefered)
+ addr.ValidLft = int(ci.Valid)
}
}
@@ -394,7 +391,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
continue
}
- addr, _, ifindex, err := parseAddr(m.Data)
+ addr, _, err := parseAddr(m.Data)
if err != nil {
if cberr != nil {
cberr(fmt.Errorf("could not parse address: %v", err))
@@ -403,7 +400,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
}
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
- LinkIndex: ifindex,
+ LinkIndex: addr.LinkIndex,
NewAddr: msgType == unix.RTM_NEWADDR,
Flags: addr.Flags,
Scope: addr.Scope,
diff --git a/vendor/github.com/vishvananda/netlink/class.go b/vendor/github.com/vishvananda/netlink/class.go
index dcc22d9e9..10ceffed8 100644
--- a/vendor/github.com/vishvananda/netlink/class.go
+++ b/vendor/github.com/vishvananda/netlink/class.go
@@ -132,7 +132,10 @@ func (class *GenericClass) Type() string {
return class.ClassType
}
-// ServiceCurve is the way the HFSC curve are represented
+// ServiceCurve is a nondecreasing function of some time unit, returning the amount of service
+// (an allowed or allocated amount of bandwidth) at some specific point in time. The purpose of it
+// should be subconsciously obvious: if a class was allowed to transfer not less than the amount
+// specified by its service curve, then the service curve is not violated.
type ServiceCurve struct {
m1 uint32
d uint32
@@ -144,6 +147,21 @@ func (c *ServiceCurve) Attrs() (uint32, uint32, uint32) {
return c.m1, c.d, c.m2
}
+// Burst returns the burst rate (m1) of the curve
+func (c *ServiceCurve) Burst() uint32 {
+ return c.m1
+}
+
+// Delay return the delay (d) of the curve
+func (c *ServiceCurve) Delay() uint32 {
+ return c.d
+}
+
+// Rate returns the rate (m2) of the curve
+func (c *ServiceCurve) Rate() uint32 {
+ return c.m2
+}
+
// HfscClass is a representation of the HFSC class
type HfscClass struct {
ClassAttrs
@@ -152,35 +170,44 @@ type HfscClass struct {
Usc ServiceCurve
}
-// SetUsc sets the Usc curve
+// SetUsc sets the USC curve. The bandwidth (m1 and m2) is specified in bits and the delay in
+// seconds.
func (hfsc *HfscClass) SetUsc(m1 uint32, d uint32, m2 uint32) {
- hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
}
-// SetFsc sets the Fsc curve
+// SetFsc sets the Fsc curve. The bandwidth (m1 and m2) is specified in bits and the delay in
+// seconds.
func (hfsc *HfscClass) SetFsc(m1 uint32, d uint32, m2 uint32) {
- hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
}
-// SetRsc sets the Rsc curve
+// SetRsc sets the Rsc curve. The bandwidth (m1 and m2) is specified in bits and the delay in
+// seconds.
func (hfsc *HfscClass) SetRsc(m1 uint32, d uint32, m2 uint32) {
- hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
}
-// SetSC implements the SC from the tc CLI
+// SetSC implements the SC from the `tc` CLI. This function behaves the same as if one would set the
+// USC through the `tc` command-line tool. This means bandwidth (m1 and m2) is specified in bits and
+// the delay in ms.
func (hfsc *HfscClass) SetSC(m1 uint32, d uint32, m2 uint32) {
- hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
- hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.SetRsc(m1, d, m2)
+ hfsc.SetFsc(m1, d, m2)
}
-// SetUL implements the UL from the tc CLI
+// SetUL implements the UL from the `tc` CLI. This function behaves the same as if one would set the
+// USC through the `tc` command-line tool. This means bandwidth (m1 and m2) is specified in bits and
+// the delay in ms.
func (hfsc *HfscClass) SetUL(m1 uint32, d uint32, m2 uint32) {
- hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.SetUsc(m1, d, m2)
}
-// SetLS implements the LS from the tc CLI
+// SetLS implements the LS from the `tc` CLI. This function behaves the same as if one would set the
+// USC through the `tc` command-line tool. This means bandwidth (m1 and m2) is specified in bits and
+// the delay in ms.
func (hfsc *HfscClass) SetLS(m1 uint32, d uint32, m2 uint32) {
- hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.SetFsc(m1, d, m2)
}
// NewHfscClass returns a new HFSC struct with the set parameters
@@ -193,6 +220,7 @@ func NewHfscClass(attrs ClassAttrs) *HfscClass {
}
}
+// String() returns a string that contains the information and attributes of the HFSC class
func (hfsc *HfscClass) String() string {
return fmt.Sprintf(
"{%s -- {RSC: {m1=%d d=%d m2=%d}} {FSC: {m1=%d d=%d m2=%d}} {USC: {m1=%d d=%d m2=%d}}}",
diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go
index 31091e501..e664ade7f 100644
--- a/vendor/github.com/vishvananda/netlink/class_linux.go
+++ b/vendor/github.com/vishvananda/netlink/class_linux.go
@@ -43,12 +43,12 @@ func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
if buffer == 0 {
buffer = uint32(float64(rate)/Hz() + float64(mtu))
}
- buffer = uint32(Xmittime(rate, buffer))
+ buffer = Xmittime(rate, buffer)
if cbuffer == 0 {
cbuffer = uint32(float64(ceil)/Hz() + float64(mtu))
}
- cbuffer = uint32(Xmittime(ceil, cbuffer))
+ cbuffer = Xmittime(ceil, cbuffer)
return &HtbClass{
ClassAttrs: attrs,
@@ -56,9 +56,9 @@ func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
Ceil: ceil,
Buffer: buffer,
Cbuffer: cbuffer,
- Quantum: 10,
Level: 0,
- Prio: 0,
+ Prio: cattrs.Prio,
+ Quantum: cattrs.Quantum,
}
}
@@ -179,12 +179,15 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
case "hfsc":
hfsc := class.(*HfscClass)
opt := nl.HfscCopt{}
- opt.Rsc.Set(hfsc.Rsc.Attrs())
- opt.Fsc.Set(hfsc.Fsc.Attrs())
- opt.Usc.Set(hfsc.Usc.Attrs())
- options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
- options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
- options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
+ rm1, rd, rm2 := hfsc.Rsc.Attrs()
+ opt.Rsc.Set(rm1/8, rd, rm2/8)
+ fm1, fd, fm2 := hfsc.Fsc.Attrs()
+ opt.Fsc.Set(fm1/8, fd, fm2/8)
+ um1, ud, um2 := hfsc.Usc.Attrs()
+ opt.Usc.Set(um1/8, ud, um2/8)
+ nl.NewRtAttrChild(options, nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
+ nl.NewRtAttrChild(options, nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
+ nl.NewRtAttrChild(options, nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
}
req.AddData(options)
return nil
@@ -315,11 +318,11 @@ func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, err
m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs()
switch datum.Attr.Type {
case nl.TCA_HFSC_RSC:
- hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ hfsc.Rsc = ServiceCurve{m1: m1 * 8, d: d, m2: m2 * 8}
case nl.TCA_HFSC_FSC:
- hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ hfsc.Fsc = ServiceCurve{m1: m1 * 8, d: d, m2: m2 * 8}
case nl.TCA_HFSC_USC:
- hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
+ hfsc.Usc = ServiceCurve{m1: m1 * 8, d: d, m2: m2 * 8}
}
}
return detailed, nil
diff --git a/vendor/github.com/vishvananda/netlink/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
index 4bff0dcba..ab91f4e55 100644
--- a/vendor/github.com/vishvananda/netlink/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
@@ -318,18 +318,25 @@ func parseRawData(data []byte) *ConntrackFlow {
// --mask-src ip Source mask address
// --mask-dst ip Destination mask address
+// Layer 4 Protocol common parameters and options:
+// TCP, UDP, SCTP, UDPLite and DCCP
+// --sport, --orig-port-src port Source port in original direction
+// --dport, --orig-port-dst port Destination port in original direction
+
// Filter types
type ConntrackFilterType uint8
const (
- ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
- ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
- ConntrackReplySrcIP // --reply-src ip Reply Source IP
- ConntrackReplyDstIP // --reply-dst ip Reply Destination IP
- ConntrackReplyAnyIP // Match source or destination reply IP
- ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
- ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
- ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instaed ConntrackReplyAnyIP
+ ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
+ ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
+ ConntrackReplySrcIP // --reply-src ip Reply Source IP
+ ConntrackReplyDstIP // --reply-dst ip Reply Destination IP
+ ConntrackReplyAnyIP // Match source or destination reply IP
+ ConntrackOrigSrcPort // --orig-port-src port Source port in original direction
+ ConntrackOrigDstPort // --orig-port-dst port Destination port in original direction
+ ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
+ ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
+ ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instead ConntrackReplyAnyIP
)
type CustomConntrackFilter interface {
@@ -339,7 +346,9 @@ type CustomConntrackFilter interface {
}
type ConntrackFilter struct {
- ipFilter map[ConntrackFilterType]net.IP
+ ipFilter map[ConntrackFilterType]net.IP
+ portFilter map[ConntrackFilterType]uint16
+ protoFilter uint8
}
// AddIP adds an IP to the conntrack filter
@@ -354,38 +363,89 @@ func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
return nil
}
+// AddPort adds a Port to the conntrack filter if the Layer 4 protocol allows it
+func (f *ConntrackFilter) AddPort(tp ConntrackFilterType, port uint16) error {
+ switch f.protoFilter {
+ // TCP, UDP, DCCP, SCTP, UDPLite
+ case 6, 17, 33, 132, 136:
+ default:
+ return fmt.Errorf("Filter attribute not available without a valid Layer 4 protocol: %d", f.protoFilter)
+ }
+
+ if f.portFilter == nil {
+ f.portFilter = make(map[ConntrackFilterType]uint16)
+ }
+ if _, ok := f.portFilter[tp]; ok {
+ return errors.New("Filter attribute already present")
+ }
+ f.portFilter[tp] = port
+ return nil
+}
+
+// AddProtocol adds the Layer 4 protocol to the conntrack filter
+func (f *ConntrackFilter) AddProtocol(proto uint8) error {
+ if f.protoFilter != 0 {
+ return errors.New("Filter attribute already present")
+ }
+ f.protoFilter = proto
+ return nil
+}
+
// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
// false otherwise
func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
- if len(f.ipFilter) == 0 {
+ if len(f.ipFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 {
// empty filter always not match
return false
}
- match := true
- // -orig-src ip Source address from original direction
- if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found {
- match = match && elem.Equal(flow.Forward.SrcIP)
+ // -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
+ if f.protoFilter != 0 && flow.Forward.Protocol != f.protoFilter {
+ // different Layer 4 protocol always not match
+ return false
}
- // -orig-dst ip Destination address from original direction
- if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found {
- match = match && elem.Equal(flow.Forward.DstIP)
- }
+ match := true
- // -src-nat ip Source NAT ip
- if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
- match = match && elem.Equal(flow.Reverse.SrcIP)
- }
+ // IP conntrack filter
+ if len(f.ipFilter) > 0 {
+ // -orig-src ip Source address from original direction
+ if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found {
+ match = match && elem.Equal(flow.Forward.SrcIP)
+ }
+
+ // -orig-dst ip Destination address from original direction
+ if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found {
+ match = match && elem.Equal(flow.Forward.DstIP)
+ }
- // -dst-nat ip Destination NAT ip
- if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
- match = match && elem.Equal(flow.Reverse.DstIP)
+ // -src-nat ip Source NAT ip
+ if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
+ match = match && elem.Equal(flow.Reverse.SrcIP)
+ }
+
+ // -dst-nat ip Destination NAT ip
+ if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
+ match = match && elem.Equal(flow.Reverse.DstIP)
+ }
+
+ // Match source or destination reply IP
+ if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
+ match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
+ }
}
- // Match source or destination reply IP
- if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
- match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
+ // Layer 4 Port filter
+ if len(f.portFilter) > 0 {
+ // -orig-port-src port Source port from original direction
+ if elem, found := f.portFilter[ConntrackOrigSrcPort]; match && found {
+ match = match && elem == flow.Forward.SrcPort
+ }
+
+ // -orig-port-dst port Destination port from original direction
+ if elem, found := f.portFilter[ConntrackOrigDstPort]; match && found {
+ match = match && elem == flow.Forward.DstPort
+ }
}
return match
diff --git a/vendor/github.com/vishvananda/netlink/filter.go b/vendor/github.com/vishvananda/netlink/filter.go
index 88792eab0..2dc34b995 100644
--- a/vendor/github.com/vishvananda/netlink/filter.go
+++ b/vendor/github.com/vishvananda/netlink/filter.go
@@ -213,10 +213,11 @@ const (
type TunnelKeyAction struct {
ActionAttrs
- Action TunnelKeyAct
- SrcAddr net.IP
- DstAddr net.IP
- KeyID uint32
+ Action TunnelKeyAct
+ SrcAddr net.IP
+ DstAddr net.IP
+ KeyID uint32
+ DestPort uint16
}
func (action *TunnelKeyAction) Type() string {
diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go
index c56f314cd..ef6fabe81 100644
--- a/vendor/github.com/vishvananda/netlink/filter_linux.go
+++ b/vendor/github.com/vishvananda/netlink/filter_linux.go
@@ -6,7 +6,6 @@ import (
"encoding/hex"
"errors"
"fmt"
- "net"
"syscall"
"github.com/vishvananda/netlink/nl"
@@ -89,7 +88,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("TBF: failed to calculate rate table")
}
- police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
+ police.Burst = Xmittime(uint64(police.Rate.Rate), uint32(buffer))
}
police.Mtu = fattrs.Mtu
if police.PeakRate.Rate != 0 {
@@ -456,6 +455,9 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
} else {
return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr)
}
+ if action.DestPort != 0 {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_DST_PORT, htons(action.DestPort))
+ }
}
case *SkbEditAction:
table := attr.AddRtAttr(tabIndex, nil)
@@ -566,12 +568,12 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action)
case nl.TCA_TUNNEL_KEY_ENC_KEY_ID:
action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4])
- case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC:
- case nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC:
- action.(*TunnelKeyAction).SrcAddr = net.IP(adatum.Value[:])
- case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST:
- case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
- action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:])
+ case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC:
+ action.(*TunnelKeyAction).SrcAddr = adatum.Value[:]
+ case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
+ action.(*TunnelKeyAction).DstAddr = adatum.Value[:]
+ case nl.TCA_TUNNEL_KEY_ENC_DST_PORT:
+ action.(*TunnelKeyAction).DestPort = ntohs(adatum.Value)
}
case "skbedit":
switch adatum.Attr.Type {
@@ -783,7 +785,7 @@ func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, lin
}
for i := 0; i < 256; i++ {
sz = AdjustSize(uint((i+1)<<uint32(cellLog)), uint(mpu), linklayer)
- rtab[i] = uint32(Xmittime(uint64(bps), uint32(sz)))
+ rtab[i] = Xmittime(uint64(bps), uint32(sz))
}
rate.CellAlign = -1
rate.CellLog = uint8(cellLog)
diff --git a/vendor/github.com/vishvananda/netlink/go.mod b/vendor/github.com/vishvananda/netlink/go.mod
index 09ee60e77..9d8455ee7 100644
--- a/vendor/github.com/vishvananda/netlink/go.mod
+++ b/vendor/github.com/vishvananda/netlink/go.mod
@@ -3,6 +3,6 @@ module github.com/vishvananda/netlink
go 1.12
require (
- github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
- golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444
+ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae
+ golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1
)
diff --git a/vendor/github.com/vishvananda/netlink/go.sum b/vendor/github.com/vishvananda/netlink/go.sum
index 402d14ec5..ed5d30891 100644
--- a/vendor/github.com/vishvananda/netlink/go.sum
+++ b/vendor/github.com/vishvananda/netlink/go.sum
@@ -1,4 +1,6 @@
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
-golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444 h1:/d2cWp6PSamH4jDPFLyO150psQdqvtoNX8Zjg3AQ31g=
-golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867 h1:JoRuNIf+rpHl+VhScRQQvzbHed86tKkqwPMV34T8myw=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/vishvananda/netlink/handle_unspecified.go b/vendor/github.com/vishvananda/netlink/handle_unspecified.go
index ef914dcb8..df341f706 100644
--- a/vendor/github.com/vishvananda/netlink/handle_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/handle_unspecified.go
@@ -85,7 +85,7 @@ func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
return ErrNotImplemented
}
-func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
+func (h *Handle) LinkSetMaster(link Link, master Link) error {
return ErrNotImplemented
}
diff --git a/vendor/github.com/vishvananda/netlink/inet_diag.go b/vendor/github.com/vishvananda/netlink/inet_diag.go
new file mode 100644
index 000000000..72c1fcb59
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/inet_diag.go
@@ -0,0 +1,30 @@
+package netlink
+
+// INET_DIAG constatns
+const (
+ INET_DIAG_NONE = iota
+ INET_DIAG_MEMINFO
+ INET_DIAG_INFO
+ INET_DIAG_VEGASINFO
+ INET_DIAG_CONG
+ INET_DIAG_TOS
+ INET_DIAG_TCLASS
+ INET_DIAG_SKMEMINFO
+ INET_DIAG_SHUTDOWN
+ INET_DIAG_DCTCPINFO
+ INET_DIAG_PROTOCOL
+ INET_DIAG_SKV6ONLY
+ INET_DIAG_LOCALS
+ INET_DIAG_PEERS
+ INET_DIAG_PAD
+ INET_DIAG_MARK
+ INET_DIAG_BBRINFO
+ INET_DIAG_CLASS_ID
+ INET_DIAG_MD5SIG
+ INET_DIAG_MAX
+)
+
+type InetDiagTCPInfoResp struct {
+ InetDiagMsg *Socket
+ TCPInfo *TCPInfo
+}
diff --git a/vendor/github.com/vishvananda/netlink/ipset_linux.go b/vendor/github.com/vishvananda/netlink/ipset_linux.go
new file mode 100644
index 000000000..5487fc1cc
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/ipset_linux.go
@@ -0,0 +1,335 @@
+package netlink
+
+import (
+ "log"
+ "net"
+ "syscall"
+
+ "github.com/vishvananda/netlink/nl"
+ "golang.org/x/sys/unix"
+)
+
+// IPSetEntry is used for adding, updating, retreiving and deleting entries
+type IPSetEntry struct {
+ Comment string
+ MAC net.HardwareAddr
+ IP net.IP
+ Timeout *uint32
+ Packets *uint64
+ Bytes *uint64
+
+ Replace bool // replace existing entry
+}
+
+// IPSetResult is the result of a dump request for a set
+type IPSetResult struct {
+ Nfgenmsg *nl.Nfgenmsg
+ Protocol uint8
+ Revision uint8
+ Family uint8
+ Flags uint8
+ SetName string
+ TypeName string
+
+ HashSize uint32
+ NumEntries uint32
+ MaxElements uint32
+ References uint32
+ SizeInMemory uint32
+ CadtFlags uint32
+ Timeout *uint32
+
+ Entries []IPSetEntry
+}
+
+// IpsetCreateOptions is the options struct for creating a new ipset
+type IpsetCreateOptions struct {
+ Replace bool // replace existing ipset
+ Timeout *uint32
+ Counters bool
+ Comments bool
+ Skbinfo bool
+}
+
+// IpsetProtocol returns the ipset protocol version from the kernel
+func IpsetProtocol() (uint8, error) {
+ return pkgHandle.IpsetProtocol()
+}
+
+// IpsetCreate creates a new ipset
+func IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
+ return pkgHandle.IpsetCreate(setname, typename, options)
+}
+
+// IpsetDestroy destroys an existing ipset
+func IpsetDestroy(setname string) error {
+ return pkgHandle.IpsetDestroy(setname)
+}
+
+// IpsetFlush flushes an existing ipset
+func IpsetFlush(setname string) error {
+ return pkgHandle.IpsetFlush(setname)
+}
+
+// IpsetList dumps an specific ipset.
+func IpsetList(setname string) (*IPSetResult, error) {
+ return pkgHandle.IpsetList(setname)
+}
+
+// IpsetListAll dumps all ipsets.
+func IpsetListAll() ([]IPSetResult, error) {
+ return pkgHandle.IpsetListAll()
+}
+
+// IpsetAdd adds an entry to an existing ipset.
+func IpsetAdd(setname string, entry *IPSetEntry) error {
+ return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
+}
+
+// IpsetDele deletes an entry from an existing ipset.
+func IpsetDel(setname string, entry *IPSetEntry) error {
+ return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
+}
+
+func (h *Handle) IpsetProtocol() (uint8, error) {
+ req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
+ msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
+
+ if err != nil {
+ return 0, err
+ }
+
+ return ipsetUnserialize(msgs).Protocol, nil
+}
+
+func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
+ req := h.newIpsetRequest(nl.IPSET_CMD_CREATE)
+
+ if !options.Replace {
+ req.Flags |= unix.NLM_F_EXCL
+ }
+
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(0)))
+
+ data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
+
+ if timeout := options.Timeout; timeout != nil {
+ data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
+ }
+
+ var cadtFlags uint32
+
+ if options.Comments {
+ cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
+ }
+ if options.Counters {
+ cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
+ }
+ if options.Skbinfo {
+ cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
+ }
+
+ if cadtFlags != 0 {
+ data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
+ }
+
+ req.AddData(data)
+ _, err := ipsetExecute(req)
+ return err
+}
+
+func (h *Handle) IpsetDestroy(setname string) error {
+ req := h.newIpsetRequest(nl.IPSET_CMD_DESTROY)
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
+ _, err := ipsetExecute(req)
+ return err
+}
+
+func (h *Handle) IpsetFlush(setname string) error {
+ req := h.newIpsetRequest(nl.IPSET_CMD_FLUSH)
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
+ _, err := ipsetExecute(req)
+ return err
+}
+
+func (h *Handle) IpsetList(name string) (*IPSetResult, error) {
+ req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(name)))
+
+ msgs, err := ipsetExecute(req)
+ if err != nil {
+ return nil, err
+ }
+
+ result := ipsetUnserialize(msgs)
+ return &result, nil
+}
+
+func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
+ req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
+
+ msgs, err := ipsetExecute(req)
+ if err != nil {
+ return nil, err
+ }
+
+ result := make([]IPSetResult, len(msgs))
+ for i, msg := range msgs {
+ result[i].unserialize(msg)
+ }
+
+ return result, nil
+}
+
+func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
+ req := h.newIpsetRequest(nlCmd)
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
+ data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
+
+ if !entry.Replace {
+ req.Flags |= unix.NLM_F_EXCL
+ }
+
+ if entry.Timeout != nil {
+ data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
+ }
+ if entry.MAC != nil {
+ data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC))
+ }
+
+ data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
+ req.AddData(data)
+
+ _, err := ipsetExecute(req)
+ return err
+}
+
+func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
+ req := h.newNetlinkRequest(cmd|(unix.NFNL_SUBSYS_IPSET<<8), nl.GetIpsetFlags(cmd))
+
+ // Add the netfilter header
+ msg := &nl.Nfgenmsg{
+ NfgenFamily: uint8(unix.AF_NETLINK),
+ Version: nl.NFNETLINK_V0,
+ ResId: 0,
+ }
+ req.AddData(msg)
+ req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_PROTOCOL, nl.Uint8Attr(nl.IPSET_PROTOCOL)))
+
+ return req
+}
+
+func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
+ msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
+
+ if err != nil {
+ if errno := int(err.(syscall.Errno)); errno >= nl.IPSET_ERR_PRIVATE {
+ err = nl.IPSetError(uintptr(errno))
+ }
+ }
+ return
+}
+
+func ipsetUnserialize(msgs [][]byte) (result IPSetResult) {
+ for _, msg := range msgs {
+ result.unserialize(msg)
+ }
+ return result
+}
+
+func (result *IPSetResult) unserialize(msg []byte) {
+ result.Nfgenmsg = nl.DeserializeNfgenmsg(msg)
+
+ for attr := range nl.ParseAttributes(msg[4:]) {
+ switch attr.Type {
+ case nl.IPSET_ATTR_PROTOCOL:
+ result.Protocol = attr.Value[0]
+ case nl.IPSET_ATTR_SETNAME:
+ result.SetName = nl.BytesToString(attr.Value)
+ case nl.IPSET_ATTR_TYPENAME:
+ result.TypeName = nl.BytesToString(attr.Value)
+ case nl.IPSET_ATTR_REVISION:
+ result.Revision = attr.Value[0]
+ case nl.IPSET_ATTR_FAMILY:
+ result.Family = attr.Value[0]
+ case nl.IPSET_ATTR_FLAGS:
+ result.Flags = attr.Value[0]
+ case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
+ result.parseAttrData(attr.Value)
+ case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
+ result.parseAttrADT(attr.Value)
+ default:
+ log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
+ }
+ }
+}
+
+func (result *IPSetResult) parseAttrData(data []byte) {
+ for attr := range nl.ParseAttributes(data) {
+ switch attr.Type {
+ case nl.IPSET_ATTR_HASHSIZE | nl.NLA_F_NET_BYTEORDER:
+ result.HashSize = attr.Uint32()
+ case nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER:
+ result.MaxElements = attr.Uint32()
+ case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
+ val := attr.Uint32()
+ result.Timeout = &val
+ case nl.IPSET_ATTR_ELEMENTS | nl.NLA_F_NET_BYTEORDER:
+ result.NumEntries = attr.Uint32()
+ case nl.IPSET_ATTR_REFERENCES | nl.NLA_F_NET_BYTEORDER:
+ result.References = attr.Uint32()
+ case nl.IPSET_ATTR_MEMSIZE | nl.NLA_F_NET_BYTEORDER:
+ result.SizeInMemory = attr.Uint32()
+ case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
+ result.CadtFlags = attr.Uint32()
+ default:
+ log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
+ }
+ }
+}
+
+func (result *IPSetResult) parseAttrADT(data []byte) {
+ for attr := range nl.ParseAttributes(data) {
+ switch attr.Type {
+ case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
+ result.Entries = append(result.Entries, parseIPSetEntry(attr.Value))
+ default:
+ log.Printf("unknown ADT attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
+ }
+ }
+}
+
+func parseIPSetEntry(data []byte) (entry IPSetEntry) {
+ for attr := range nl.ParseAttributes(data) {
+ switch attr.Type {
+ case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
+ val := attr.Uint32()
+ entry.Timeout = &val
+ case nl.IPSET_ATTR_BYTES | nl.NLA_F_NET_BYTEORDER:
+ val := attr.Uint64()
+ entry.Bytes = &val
+ case nl.IPSET_ATTR_PACKETS | nl.NLA_F_NET_BYTEORDER:
+ val := attr.Uint64()
+ entry.Packets = &val
+ case nl.IPSET_ATTR_ETHER:
+ entry.MAC = net.HardwareAddr(attr.Value)
+ case nl.IPSET_ATTR_COMMENT:
+ entry.Comment = nl.BytesToString(attr.Value)
+ case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
+ for attr := range nl.ParseAttributes(attr.Value) {
+ switch attr.Type {
+ case nl.IPSET_ATTR_IP:
+ entry.IP = net.IP(attr.Value)
+ default:
+ log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
+ }
+ }
+ default:
+ log.Printf("unknown ADT attribute from kernel: %+v", attr)
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go
index 886d88d1b..e2441bd71 100644
--- a/vendor/github.com/vishvananda/netlink/link.go
+++ b/vendor/github.com/vishvananda/netlink/link.go
@@ -65,6 +65,17 @@ type VfInfo struct {
LinkState uint32
MaxTxRate uint32 // IFLA_VF_RATE Max TxRate
MinTxRate uint32 // IFLA_VF_RATE Min TxRate
+ RxPackets uint64
+ TxPackets uint64
+ RxBytes uint64
+ TxBytes uint64
+ Multicast uint64
+ Broadcast uint64
+ RxDropped uint64
+ TxDropped uint64
+
+ RssQuery uint32
+ Trust uint32
}
// LinkOperState represents the values of the IFLA_OPERSTATE link
@@ -103,7 +114,8 @@ func (s LinkOperState) String() string {
// NewLinkAttrs returns LinkAttrs structure filled with default values
func NewLinkAttrs() LinkAttrs {
return LinkAttrs{
- TxQLen: -1,
+ NetNsID: -1,
+ TxQLen: -1,
}
}
@@ -196,10 +208,11 @@ type LinkStatistics64 struct {
}
type LinkXdp struct {
- Fd int
- Attached bool
- Flags uint32
- ProgId uint32
+ Fd int
+ Attached bool
+ AttachMode uint32
+ Flags uint32
+ ProgId uint32
}
// Device links cannot be created via netlink. These links
@@ -246,6 +259,7 @@ func (ifb *Ifb) Type() string {
type Bridge struct {
LinkAttrs
MulticastSnooping *bool
+ AgeingTime *uint32
HelloTime *uint32
VlanFiltering *bool
}
@@ -338,6 +352,7 @@ type Veth struct {
LinkAttrs
PeerName string // veth on create only
PeerHardwareAddr net.HardwareAddr
+ PeerNamespace interface{}
}
func (veth *Veth) Attrs() *LinkAttrs {
@@ -348,6 +363,19 @@ func (veth *Veth) Type() string {
return "veth"
}
+// Wireguard represent links of type "wireguard", see https://www.wireguard.com/
+type Wireguard struct {
+ LinkAttrs
+}
+
+func (wg *Wireguard) Attrs() *LinkAttrs {
+ return &wg.LinkAttrs
+}
+
+func (wg *Wireguard) Type() string {
+ return "wireguard"
+}
+
// GenericLink links represent types that are not currently understood
// by this netlink library.
type GenericLink struct {
@@ -878,10 +906,14 @@ type Ip6tnl struct {
Remote net.IP
Ttl uint8
Tos uint8
- EncapLimit uint8
Flags uint32
Proto uint8
FlowInfo uint32
+ EncapLimit uint8
+ EncapType uint16
+ EncapFlags uint16
+ EncapSport uint16
+ EncapDport uint16
}
func (ip6tnl *Ip6tnl) Attrs() *LinkAttrs {
@@ -895,11 +927,13 @@ func (ip6tnl *Ip6tnl) Type() string {
type Sittun struct {
LinkAttrs
Link uint32
- Local net.IP
- Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
+ Proto uint8
+ Local net.IP
+ Remote net.IP
+ EncapLimit uint8
EncapType uint16
EncapFlags uint16
EncapSport uint16
diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go
index ec915a0b9..c02fa63b8 100644
--- a/vendor/github.com/vishvananda/netlink/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/link_linux.go
@@ -237,6 +237,37 @@ func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode
return err
}
+// LinkSetMacvlanMode sets the mode of a macvlan or macvtap link device.
+// Note that passthrough mode cannot be set to and from and will fail.
+// Equivalent to: `ip link set $link type (macvlan|macvtap) mode $mode
+func LinkSetMacvlanMode(link Link, mode MacvlanMode) error {
+ return pkgHandle.LinkSetMacvlanMode(link, mode)
+}
+
+// LinkSetMacvlanMode sets the mode of the macvlan or macvtap link device.
+// Note that passthrough mode cannot be set to and from and will fail.
+// Equivalent to: `ip link set $link type (macvlan|macvtap) mode $mode
+func (h *Handle) LinkSetMacvlanMode(link Link, mode MacvlanMode) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
+ linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
+
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[mode]))
+
+ req.AddData(linkInfo)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
func BridgeSetMcastSnoop(link Link, on bool) error {
return pkgHandle.BridgeSetMcastSnoop(link, on)
}
@@ -247,6 +278,16 @@ func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
return h.linkModify(bridge, unix.NLM_F_ACK)
}
+func BridgeSetVlanFiltering(link Link, on bool) error {
+ return pkgHandle.BridgeSetVlanFiltering(link, on)
+}
+
+func (h *Handle) BridgeSetVlanFiltering(link Link, on bool) error {
+ bridge := link.(*Bridge)
+ bridge.VlanFiltering = &on
+ return h.linkModify(bridge, unix.NLM_F_ACK)
+}
+
func SetPromiscOn(link Link) error {
return pkgHandle.SetPromiscOn(link)
}
@@ -1048,6 +1089,10 @@ func (h *Handle) LinkAdd(link Link) error {
return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
}
+func (h *Handle) LinkModify(link Link) error {
+ return h.linkModify(link, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+}
+
func (h *Handle) linkModify(link Link, flags int) error {
// TODO: support extra data for macvlan
base := link.Attrs()
@@ -1060,8 +1105,6 @@ func (h *Handle) linkModify(link Link, flags int) error {
}
if isTuntap {
- // TODO: support user
- // TODO: support group
if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
return fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode)
}
@@ -1089,21 +1132,64 @@ func (h *Handle) linkModify(link Link, flags int) error {
}
req.Flags |= uint16(tuntap.Mode)
-
+ const TUN = "/dev/net/tun"
for i := 0; i < queues; i++ {
localReq := req
- file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
+ fd, err := unix.Open(TUN, os.O_RDWR|syscall.O_CLOEXEC, 0)
if err != nil {
cleanupFds(fds)
return err
}
- fds = append(fds, file)
- _, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq)))
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq)))
if errno != 0 {
+ // close the new fd
+ unix.Close(fd)
+ // and the already opened ones
cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
}
+
+ _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TUNSETOWNER, uintptr(tuntap.Owner))
+ if errno != 0 {
+ cleanupFds(fds)
+ return fmt.Errorf("Tuntap IOCTL TUNSETOWNER failed [%d], errno %v", i, errno)
+ }
+
+ _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TUNSETGROUP, uintptr(tuntap.Group))
+ if errno != 0 {
+ cleanupFds(fds)
+ return fmt.Errorf("Tuntap IOCTL TUNSETGROUP failed [%d], errno %v", i, errno)
+ }
+
+ // Set the tun device to non-blocking before use. The below comment
+ // taken from:
+ //
+ // https://github.com/mistsys/tuntap/commit/161418c25003bbee77d085a34af64d189df62bea
+ //
+ // Note there is a complication because in go, if a device node is
+ // opened, go sets it to use nonblocking I/O. However a /dev/net/tun
+ // doesn't work with epoll until after the TUNSETIFF ioctl has been
+ // done. So we open the unix fd directly, do the ioctl, then put the
+ // fd in nonblocking mode, an then finally wrap it in a os.File,
+ // which will see the nonblocking mode and add the fd to the
+ // pollable set, so later on when we Read() from it blocked the
+ // calling thread in the kernel.
+ //
+ // See
+ // https://github.com/golang/go/issues/30426
+ // which got exposed in go 1.13 by the fix to
+ // https://github.com/golang/go/issues/30624
+ err = unix.SetNonblock(fd, true)
+ if err != nil {
+ cleanupFds(fds)
+ return fmt.Errorf("Tuntap set to non-blocking failed [%d], err %v", i, err)
+ }
+
+ // create the file from the file descriptor and store it
+ file := os.NewFile(uintptr(fd), TUN)
+ fds = append(fds, file)
+
// 1) we only care for the name of the first tap in the multi queue set
// 2) if the original name was empty, the localReq has now the actual name
//
@@ -1114,6 +1200,7 @@ func (h *Handle) linkModify(link Link, flags int) error {
if i == 0 {
link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00")
}
+
}
// only persist interface if NonPersist is NOT set
@@ -1193,6 +1280,11 @@ func (h *Handle) linkModify(link Link, flags int) error {
nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
req.AddData(nameData)
+ if base.Alias != "" {
+ alias := nl.NewRtAttr(unix.IFLA_IFALIAS, []byte(base.Alias))
+ req.AddData(alias)
+ }
+
if base.MTU > 0 {
mtu := nl.NewRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
req.AddData(mtu)
@@ -1272,12 +1364,28 @@ func (h *Handle) linkModify(link Link, flags int) error {
if base.TxQLen >= 0 {
peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
}
+ if base.NumTxQueues > 0 {
+ peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues)))
+ }
+ if base.NumRxQueues > 0 {
+ peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues)))
+ }
if base.MTU > 0 {
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
}
if link.PeerHardwareAddr != nil {
peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr))
}
+ if link.PeerNamespace != nil {
+ switch ns := link.PeerNamespace.(type) {
+ case NsPid:
+ val := nl.Uint32Attr(uint32(ns))
+ peer.AddRtAttr(unix.IFLA_NET_NS_PID, val)
+ case NsFd:
+ val := nl.Uint32Attr(uint32(ns))
+ peer.AddRtAttr(unix.IFLA_NET_NS_FD, val)
+ }
+ }
case *Vxlan:
addVxlanAttrs(link, linkInfo)
case *Bond:
@@ -1509,7 +1617,11 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
return nil, err
}
- base := LinkAttrs{Index: int(msg.Index), RawFlags: msg.Flags, Flags: linkFlags(msg.Flags), EncapType: msg.EncapType()}
+ base := NewLinkAttrs()
+ base.Index = int(msg.Index)
+ base.RawFlags = msg.Flags
+ base.Flags = linkFlags(msg.Flags)
+ base.EncapType = msg.EncapType()
if msg.Flags&unix.IFF_PROMISC != 0 {
base.Promisc = 1
}
@@ -1543,6 +1655,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Vlan{}
case "veth":
link = &Veth{}
+ case "wireguard":
+ link = &Wireguard{}
case "vxlan":
link = &Vxlan{}
case "bond":
@@ -2080,6 +2194,13 @@ func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
vxlan := link.(*Vxlan)
for _, datum := range data {
+ // NOTE(vish): Apparently some messages can be sent with no value.
+ // We special case GBP here to not change existing
+ // functionality. It appears that GBP sends a datum.Value
+ // of null.
+ if len(datum.Value) == 0 && datum.Attr.Type != nl.IFLA_VXLAN_GBP {
+ continue
+ }
switch datum.Attr.Type {
case nl.IFLA_VXLAN_ID:
vxlan.VxlanId = int(native.Uint32(datum.Value[0:4]))
@@ -2513,7 +2634,8 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
case nl.IFLA_XDP_FD:
xdp.Fd = int(native.Uint32(attr.Value[0:4]))
case nl.IFLA_XDP_ATTACHED:
- xdp.Attached = attr.Value[0] != 0
+ xdp.AttachMode = uint32(attr.Value[0])
+ xdp.Attached = xdp.AttachMode != 0
case nl.IFLA_XDP_FLAGS:
xdp.Flags = native.Uint32(attr.Value[0:4])
case nl.IFLA_XDP_PROG_ID:
@@ -2577,7 +2699,7 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_IPTUN_ENCAP_FLAGS:
iptun.EncapFlags = native.Uint16(datum.Value[0:2])
case nl.IFLA_IPTUN_COLLECT_METADATA:
- iptun.FlowBased = int8(datum.Value[0]) != 0
+ iptun.FlowBased = true
}
}
}
@@ -2601,10 +2723,14 @@ func addIp6tnlAttrs(ip6tnl *Ip6tnl, linkInfo *nl.RtAttr) {
data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(ip6tnl.Ttl))
data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(ip6tnl.Tos))
- data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit))
data.AddRtAttr(nl.IFLA_IPTUN_FLAGS, nl.Uint32Attr(ip6tnl.Flags))
data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(ip6tnl.Proto))
data.AddRtAttr(nl.IFLA_IPTUN_FLOWINFO, nl.Uint32Attr(ip6tnl.FlowInfo))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(ip6tnl.EncapType))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(ip6tnl.EncapFlags))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(ip6tnl.EncapSport))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(ip6tnl.EncapDport))
}
func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -2616,17 +2742,25 @@ func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_IPTUN_REMOTE:
ip6tnl.Remote = net.IP(datum.Value[:16])
case nl.IFLA_IPTUN_TTL:
- ip6tnl.Ttl = uint8(datum.Value[0])
+ ip6tnl.Ttl = datum.Value[0]
case nl.IFLA_IPTUN_TOS:
- ip6tnl.Tos = uint8(datum.Value[0])
- case nl.IFLA_IPTUN_ENCAP_LIMIT:
- ip6tnl.EncapLimit = uint8(datum.Value[0])
+ ip6tnl.Tos = datum.Value[0]
case nl.IFLA_IPTUN_FLAGS:
ip6tnl.Flags = native.Uint32(datum.Value[:4])
case nl.IFLA_IPTUN_PROTO:
- ip6tnl.Proto = uint8(datum.Value[0])
+ ip6tnl.Proto = datum.Value[0]
case nl.IFLA_IPTUN_FLOWINFO:
ip6tnl.FlowInfo = native.Uint32(datum.Value[:4])
+ case nl.IFLA_IPTUN_ENCAP_LIMIT:
+ ip6tnl.EncapLimit = datum.Value[0]
+ case nl.IFLA_IPTUN_ENCAP_TYPE:
+ ip6tnl.EncapType = native.Uint16(datum.Value[0:2])
+ case nl.IFLA_IPTUN_ENCAP_FLAGS:
+ ip6tnl.EncapFlags = native.Uint16(datum.Value[0:2])
+ case nl.IFLA_IPTUN_ENCAP_SPORT:
+ ip6tnl.EncapSport = ntohs(datum.Value[0:2])
+ case nl.IFLA_IPTUN_ENCAP_DPORT:
+ ip6tnl.EncapDport = ntohs(datum.Value[0:2])
}
}
}
@@ -2653,8 +2787,10 @@ func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) {
data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl))
}
+ data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(sittun.Proto))
data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos))
data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(sittun.EncapLimit))
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType))
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags))
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport))
@@ -2670,11 +2806,13 @@ func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_IPTUN_REMOTE:
sittun.Remote = net.IP(datum.Value[0:4])
case nl.IFLA_IPTUN_TTL:
- sittun.Ttl = uint8(datum.Value[0])
+ sittun.Ttl = datum.Value[0]
case nl.IFLA_IPTUN_TOS:
- sittun.Tos = uint8(datum.Value[0])
+ sittun.Tos = datum.Value[0]
case nl.IFLA_IPTUN_PMTUDISC:
- sittun.PMtuDisc = uint8(datum.Value[0])
+ sittun.PMtuDisc = datum.Value[0]
+ case nl.IFLA_IPTUN_PROTO:
+ sittun.Proto = datum.Value[0]
case nl.IFLA_IPTUN_ENCAP_TYPE:
sittun.EncapType = native.Uint16(datum.Value[0:2])
case nl.IFLA_IPTUN_ENCAP_FLAGS:
@@ -2761,6 +2899,9 @@ func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) {
if bridge.MulticastSnooping != nil {
data.AddRtAttr(nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping))
}
+ if bridge.AgeingTime != nil {
+ data.AddRtAttr(nl.IFLA_BR_AGEING_TIME, nl.Uint32Attr(*bridge.AgeingTime))
+ }
if bridge.HelloTime != nil {
data.AddRtAttr(nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime))
}
@@ -2773,6 +2914,9 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
br := bridge.(*Bridge)
for _, datum := range data {
switch datum.Attr.Type {
+ case nl.IFLA_BR_AGEING_TIME:
+ ageingTime := native.Uint32(datum.Value[0:4])
+ br.AgeingTime = &ageingTime
case nl.IFLA_BR_HELLO_TIME:
helloTime := native.Uint32(datum.Value[0:4])
br.HelloTime = &helloTime
@@ -2852,6 +2996,24 @@ func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo {
vfr := nl.DeserializeVfRate(element.Value[:])
vf.MaxTxRate = vfr.MaxTxRate
vf.MinTxRate = vfr.MinTxRate
+ case nl.IFLA_VF_STATS:
+ vfstats := nl.DeserializeVfStats(element.Value[:])
+ vf.RxPackets = vfstats.RxPackets
+ vf.TxPackets = vfstats.TxPackets
+ vf.RxBytes = vfstats.RxBytes
+ vf.TxBytes = vfstats.TxBytes
+ vf.Multicast = vfstats.Multicast
+ vf.Broadcast = vfstats.Broadcast
+ vf.RxDropped = vfstats.RxDropped
+ vf.TxDropped = vfstats.TxDropped
+
+ case nl.IFLA_VF_RSS_QUERY_EN:
+ result := nl.DeserializeVfRssQueryEn(element.Value)
+ vf.RssQuery = result.Setting
+
+ case nl.IFLA_VF_TRUST:
+ result := nl.DeserializeVfTrust(element.Value)
+ vf.Trust = result.Setting
}
}
return vf
diff --git a/vendor/github.com/vishvananda/netlink/neigh_linux.go b/vendor/github.com/vishvananda/netlink/neigh_linux.go
index cb3b55d35..fb220d141 100644
--- a/vendor/github.com/vishvananda/netlink/neigh_linux.go
+++ b/vendor/github.com/vishvananda/netlink/neigh_linux.go
@@ -243,6 +243,18 @@ func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
// Ignore messages from other interfaces
continue
}
+ if msg.Family != 0 && ndm.Family != msg.Family {
+ continue
+ }
+ if msg.State != 0 && ndm.State != msg.State {
+ continue
+ }
+ if msg.Type != 0 && ndm.Type != msg.Type {
+ continue
+ }
+ if msg.Flags != 0 && ndm.Flags != msg.Flags {
+ continue
+ }
neigh, err := NeighDeserialize(m)
if err != nil {
diff --git a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
index 42d3acf91..71436f25c 100644
--- a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
@@ -16,7 +16,7 @@ func LinkSetMTU(link Link, mtu int) error {
return ErrNotImplemented
}
-func LinkSetMaster(link Link, master *Bridge) error {
+func LinkSetMaster(link Link, master Link) error {
return ErrNotImplemented
}
@@ -72,6 +72,10 @@ func LinkSetXdpFd(link Link, fd int) error {
return ErrNotImplemented
}
+func LinkSetXdpFdWithFlags(link Link, fd, flags int) error {
+ return ErrNotImplemented
+}
+
func LinkSetARPOff(link Link) error {
return ErrNotImplemented
}
diff --git a/vendor/github.com/vishvananda/netlink/nl/addr_linux.go b/vendor/github.com/vishvananda/netlink/nl/addr_linux.go
index 50db3b4cd..6bea4ed02 100644
--- a/vendor/github.com/vishvananda/netlink/nl/addr_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/addr_linux.go
@@ -54,24 +54,18 @@ func (msg *IfAddrmsg) Len() int {
// __u32 tstamp; /* updated timestamp, hundredths of seconds */
// };
-const IFA_CACHEINFO = 6
-const SizeofIfaCacheInfo = 0x10
-
type IfaCacheInfo struct {
- IfaPrefered uint32
- IfaValid uint32
- Cstamp uint32
- Tstamp uint32
+ unix.IfaCacheinfo
}
func (msg *IfaCacheInfo) Len() int {
- return SizeofIfaCacheInfo
+ return unix.SizeofIfaCacheinfo
}
func DeserializeIfaCacheInfo(b []byte) *IfaCacheInfo {
- return (*IfaCacheInfo)(unsafe.Pointer(&b[0:SizeofIfaCacheInfo][0]))
+ return (*IfaCacheInfo)(unsafe.Pointer(&b[0:unix.SizeofIfaCacheinfo][0]))
}
func (msg *IfaCacheInfo) Serialize() []byte {
- return (*(*[SizeofIfaCacheInfo]byte)(unsafe.Pointer(msg)))[:]
+ return (*(*[unix.SizeofIfaCacheinfo]byte)(unsafe.Pointer(msg)))[:]
}
diff --git a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
index 79d2b6b89..14924027e 100644
--- a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
@@ -40,9 +40,10 @@ const (
NFNETLINK_V0 = 0
)
-// #define NLA_F_NESTED (1 << 15)
const (
- NLA_F_NESTED = (1 << 15)
+ NLA_F_NESTED uint16 = (1 << 15) // #define NLA_F_NESTED (1 << 15)
+ NLA_F_NET_BYTEORDER uint16 = (1 << 14) // #define NLA_F_NESTED (1 << 14)
+ NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
)
// enum ctattr_type {
diff --git a/vendor/github.com/vishvananda/netlink/nl/ipset_linux.go b/vendor/github.com/vishvananda/netlink/nl/ipset_linux.go
new file mode 100644
index 000000000..a60b4b09d
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/nl/ipset_linux.go
@@ -0,0 +1,222 @@
+package nl
+
+import (
+ "strconv"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ /* The protocol version */
+ IPSET_PROTOCOL = 6
+
+ /* The max length of strings including NUL: set and type identifiers */
+ IPSET_MAXNAMELEN = 32
+
+ /* The maximum permissible comment length we will accept over netlink */
+ IPSET_MAX_COMMENT_SIZE = 255
+)
+
+const (
+ _ = iota
+ IPSET_CMD_PROTOCOL /* 1: Return protocol version */
+ IPSET_CMD_CREATE /* 2: Create a new (empty) set */
+ IPSET_CMD_DESTROY /* 3: Destroy a (empty) set */
+ IPSET_CMD_FLUSH /* 4: Remove all elements from a set */
+ IPSET_CMD_RENAME /* 5: Rename a set */
+ IPSET_CMD_SWAP /* 6: Swap two sets */
+ IPSET_CMD_LIST /* 7: List sets */
+ IPSET_CMD_SAVE /* 8: Save sets */
+ IPSET_CMD_ADD /* 9: Add an element to a set */
+ IPSET_CMD_DEL /* 10: Delete an element from a set */
+ IPSET_CMD_TEST /* 11: Test an element in a set */
+ IPSET_CMD_HEADER /* 12: Get set header data only */
+ IPSET_CMD_TYPE /* 13: Get set type */
+)
+
+/* Attributes at command level */
+const (
+ _ = iota
+ IPSET_ATTR_PROTOCOL /* 1: Protocol version */
+ IPSET_ATTR_SETNAME /* 2: Name of the set */
+ IPSET_ATTR_TYPENAME /* 3: Typename */
+ IPSET_ATTR_REVISION /* 4: Settype revision */
+ IPSET_ATTR_FAMILY /* 5: Settype family */
+ IPSET_ATTR_FLAGS /* 6: Flags at command level */
+ IPSET_ATTR_DATA /* 7: Nested attributes */
+ IPSET_ATTR_ADT /* 8: Multiple data containers */
+ IPSET_ATTR_LINENO /* 9: Restore lineno */
+ IPSET_ATTR_PROTOCOL_MIN /* 10: Minimal supported version number */
+
+ IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME /* Setname at rename/swap */
+ IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN /* type rev min */
+)
+
+/* CADT specific attributes */
+const (
+ IPSET_ATTR_IP = 1
+ IPSET_ATTR_IP_FROM = 1
+ IPSET_ATTR_IP_TO = 2
+ IPSET_ATTR_CIDR = 3
+ IPSET_ATTR_PORT = 4
+ IPSET_ATTR_PORT_FROM = 4
+ IPSET_ATTR_PORT_TO = 5
+ IPSET_ATTR_TIMEOUT = 6
+ IPSET_ATTR_PROTO = 7
+ IPSET_ATTR_CADT_FLAGS = 8
+ IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO /* 9 */
+ IPSET_ATTR_MARK = 10
+ IPSET_ATTR_MARKMASK = 11
+
+ /* Reserve empty slots */
+ IPSET_ATTR_CADT_MAX = 16
+
+ /* Create-only specific attributes */
+ IPSET_ATTR_GC = 3 + iota
+ IPSET_ATTR_HASHSIZE
+ IPSET_ATTR_MAXELEM
+ IPSET_ATTR_NETMASK
+ IPSET_ATTR_PROBES
+ IPSET_ATTR_RESIZE
+ IPSET_ATTR_SIZE
+
+ /* Kernel-only */
+ IPSET_ATTR_ELEMENTS
+ IPSET_ATTR_REFERENCES
+ IPSET_ATTR_MEMSIZE
+
+ SET_ATTR_CREATE_MAX
+)
+
+/* ADT specific attributes */
+const (
+ IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + iota + 1
+ IPSET_ATTR_NAME
+ IPSET_ATTR_NAMEREF
+ IPSET_ATTR_IP2
+ IPSET_ATTR_CIDR2
+ IPSET_ATTR_IP2_TO
+ IPSET_ATTR_IFACE
+ IPSET_ATTR_BYTES
+ IPSET_ATTR_PACKETS
+ IPSET_ATTR_COMMENT
+ IPSET_ATTR_SKBMARK
+ IPSET_ATTR_SKBPRIO
+ IPSET_ATTR_SKBQUEUE
+)
+
+/* Flags at CADT attribute level, upper half of cmdattrs */
+const (
+ IPSET_FLAG_BIT_BEFORE = 0
+ IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE)
+ IPSET_FLAG_BIT_PHYSDEV = 1
+ IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV)
+ IPSET_FLAG_BIT_NOMATCH = 2
+ IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH)
+ IPSET_FLAG_BIT_WITH_COUNTERS = 3
+ IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS)
+ IPSET_FLAG_BIT_WITH_COMMENT = 4
+ IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT)
+ IPSET_FLAG_BIT_WITH_FORCEADD = 5
+ IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD)
+ IPSET_FLAG_BIT_WITH_SKBINFO = 6
+ IPSET_FLAG_WITH_SKBINFO = (1 << IPSET_FLAG_BIT_WITH_SKBINFO)
+ IPSET_FLAG_CADT_MAX = 15
+)
+
+const (
+ IPSET_ERR_PRIVATE = 4096 + iota
+ IPSET_ERR_PROTOCOL
+ IPSET_ERR_FIND_TYPE
+ IPSET_ERR_MAX_SETS
+ IPSET_ERR_BUSY
+ IPSET_ERR_EXIST_SETNAME2
+ IPSET_ERR_TYPE_MISMATCH
+ IPSET_ERR_EXIST
+ IPSET_ERR_INVALID_CIDR
+ IPSET_ERR_INVALID_NETMASK
+ IPSET_ERR_INVALID_FAMILY
+ IPSET_ERR_TIMEOUT
+ IPSET_ERR_REFERENCED
+ IPSET_ERR_IPADDR_IPV4
+ IPSET_ERR_IPADDR_IPV6
+ IPSET_ERR_COUNTER
+ IPSET_ERR_COMMENT
+ IPSET_ERR_INVALID_MARKMASK
+ IPSET_ERR_SKBINFO
+
+ /* Type specific error codes */
+ IPSET_ERR_TYPE_SPECIFIC = 4352
+)
+
+type IPSetError uintptr
+
+func (e IPSetError) Error() string {
+ switch int(e) {
+ case IPSET_ERR_PRIVATE:
+ return "private"
+ case IPSET_ERR_PROTOCOL:
+ return "invalid protocol"
+ case IPSET_ERR_FIND_TYPE:
+ return "invalid type"
+ case IPSET_ERR_MAX_SETS:
+ return "max sets reached"
+ case IPSET_ERR_BUSY:
+ return "busy"
+ case IPSET_ERR_EXIST_SETNAME2:
+ return "exist_setname2"
+ case IPSET_ERR_TYPE_MISMATCH:
+ return "type mismatch"
+ case IPSET_ERR_EXIST:
+ return "exist"
+ case IPSET_ERR_INVALID_CIDR:
+ return "invalid cidr"
+ case IPSET_ERR_INVALID_NETMASK:
+ return "invalid netmask"
+ case IPSET_ERR_INVALID_FAMILY:
+ return "invalid family"
+ case IPSET_ERR_TIMEOUT:
+ return "timeout"
+ case IPSET_ERR_REFERENCED:
+ return "referenced"
+ case IPSET_ERR_IPADDR_IPV4:
+ return "invalid ipv4 address"
+ case IPSET_ERR_IPADDR_IPV6:
+ return "invalid ipv6 address"
+ case IPSET_ERR_COUNTER:
+ return "invalid counter"
+ case IPSET_ERR_COMMENT:
+ return "invalid comment"
+ case IPSET_ERR_INVALID_MARKMASK:
+ return "invalid markmask"
+ case IPSET_ERR_SKBINFO:
+ return "skbinfo"
+ default:
+ return "errno " + strconv.Itoa(int(e))
+ }
+}
+
+func GetIpsetFlags(cmd int) int {
+ switch cmd {
+ case IPSET_CMD_CREATE:
+ return unix.NLM_F_REQUEST | unix.NLM_F_ACK | unix.NLM_F_CREATE
+ case IPSET_CMD_DESTROY,
+ IPSET_CMD_FLUSH,
+ IPSET_CMD_RENAME,
+ IPSET_CMD_SWAP,
+ IPSET_CMD_TEST:
+ return unix.NLM_F_REQUEST | unix.NLM_F_ACK
+ case IPSET_CMD_LIST,
+ IPSET_CMD_SAVE:
+ return unix.NLM_F_REQUEST | unix.NLM_F_ACK | unix.NLM_F_ROOT | unix.NLM_F_MATCH | unix.NLM_F_DUMP
+ case IPSET_CMD_ADD,
+ IPSET_CMD_DEL:
+ return unix.NLM_F_REQUEST | unix.NLM_F_ACK
+ case IPSET_CMD_HEADER,
+ IPSET_CMD_TYPE,
+ IPSET_CMD_PROTOCOL:
+ return unix.NLM_F_REQUEST
+ default:
+ return 0
+ }
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
index afb16a9c1..faee2fa03 100644
--- a/vendor/github.com/vishvananda/netlink/nl/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
@@ -1,6 +1,8 @@
package nl
import (
+ "bytes"
+ "encoding/binary"
"unsafe"
)
@@ -243,7 +245,9 @@ const (
IFLA_VF_STATS_TX_BYTES
IFLA_VF_STATS_BROADCAST
IFLA_VF_STATS_MULTICAST
- IFLA_VF_STATS_MAX = IFLA_VF_STATS_MULTICAST
+ IFLA_VF_STATS_RX_DROPPED
+ IFLA_VF_STATS_TX_DROPPED
+ IFLA_VF_STATS_MAX = IFLA_VF_STATS_TX_DROPPED
)
const (
@@ -326,6 +330,59 @@ func (msg *VfTxRate) Serialize() []byte {
return (*(*[SizeofVfTxRate]byte)(unsafe.Pointer(msg)))[:]
}
+//struct ifla_vf_stats {
+// __u64 rx_packets;
+// __u64 tx_packets;
+// __u64 rx_bytes;
+// __u64 tx_bytes;
+// __u64 broadcast;
+// __u64 multicast;
+//};
+
+type VfStats struct {
+ RxPackets uint64
+ TxPackets uint64
+ RxBytes uint64
+ TxBytes uint64
+ Multicast uint64
+ Broadcast uint64
+ RxDropped uint64
+ TxDropped uint64
+}
+
+func DeserializeVfStats(b []byte) VfStats {
+ var vfstat VfStats
+ stats, err := ParseRouteAttr(b)
+ if err != nil {
+ return vfstat
+ }
+ var valueVar uint64
+ for _, stat := range stats {
+ if err := binary.Read(bytes.NewBuffer(stat.Value), NativeEndian(), &valueVar); err != nil {
+ break
+ }
+ switch stat.Attr.Type {
+ case IFLA_VF_STATS_RX_PACKETS:
+ vfstat.RxPackets = valueVar
+ case IFLA_VF_STATS_TX_PACKETS:
+ vfstat.TxPackets = valueVar
+ case IFLA_VF_STATS_RX_BYTES:
+ vfstat.RxBytes = valueVar
+ case IFLA_VF_STATS_TX_BYTES:
+ vfstat.TxBytes = valueVar
+ case IFLA_VF_STATS_MULTICAST:
+ vfstat.Multicast = valueVar
+ case IFLA_VF_STATS_BROADCAST:
+ vfstat.Broadcast = valueVar
+ case IFLA_VF_STATS_RX_DROPPED:
+ vfstat.RxDropped = valueVar
+ case IFLA_VF_STATS_TX_DROPPED:
+ vfstat.TxDropped = valueVar
+ }
+ }
+ return vfstat
+}
+
// struct ifla_vf_rate {
// __u32 vf;
// __u32 min_tx_rate; /* Min Bandwidth in Mbps */
@@ -478,6 +535,14 @@ const (
IFLA_XDP_MAX = IFLA_XDP_PROG_ID
)
+// XDP program attach mode (used as dump value for IFLA_XDP_ATTACHED)
+const (
+ XDP_ATTACHED_NONE = iota
+ XDP_ATTACHED_DRV
+ XDP_ATTACHED_SKB
+ XDP_ATTACHED_HW
+)
+
const (
IFLA_IPTUN_UNSPEC = iota
IFLA_IPTUN_LINK
diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
index aaf56c671..cef64b82e 100644
--- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
@@ -259,6 +259,29 @@ func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
return msg
}
+type Uint32Attribute struct {
+ Type uint16
+ Value uint32
+}
+
+func (a *Uint32Attribute) Serialize() []byte {
+ native := NativeEndian()
+ buf := make([]byte, rtaAlignOf(8))
+ native.PutUint16(buf[0:2], 8)
+ native.PutUint16(buf[2:4], a.Type)
+
+ if a.Type&NLA_F_NET_BYTEORDER != 0 {
+ binary.BigEndian.PutUint32(buf[4:], a.Value)
+ } else {
+ native.PutUint32(buf[4:], a.Value)
+ }
+ return buf
+}
+
+func (a *Uint32Attribute) Len() int {
+ return 8
+}
+
// Extend RtAttr to handle data and children
type RtAttr struct {
unix.RtAttr
@@ -439,10 +462,7 @@ done:
if m.Header.Pid != pid {
continue
}
- if m.Header.Type == unix.NLMSG_DONE {
- break done
- }
- if m.Header.Type == unix.NLMSG_ERROR {
+ if m.Header.Type == unix.NLMSG_DONE || m.Header.Type == unix.NLMSG_ERROR {
native := NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
diff --git a/vendor/github.com/vishvananda/netlink/nl/parse_attr.go b/vendor/github.com/vishvananda/netlink/nl/parse_attr.go
new file mode 100644
index 000000000..19eb8f28e
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/nl/parse_attr.go
@@ -0,0 +1,67 @@
+package nl
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+type Attribute struct {
+ Type uint16
+ Value []byte
+}
+
+func ParseAttributes(data []byte) <-chan Attribute {
+ native := NativeEndian()
+ result := make(chan Attribute)
+
+ go func() {
+ i := 0
+ for i+4 < len(data) {
+ length := int(native.Uint16(data[i : i+2]))
+
+ result <- Attribute{
+ Type: native.Uint16(data[i+2 : i+4]),
+ Value: data[i+4 : i+length],
+ }
+ i += rtaAlignOf(length)
+ }
+ close(result)
+ }()
+
+ return result
+}
+
+func PrintAttributes(data []byte) {
+ printAttributes(data, 0)
+}
+
+func printAttributes(data []byte, level int) {
+ for attr := range ParseAttributes(data) {
+ for i := 0; i < level; i++ {
+ print("> ")
+ }
+ nested := attr.Type&NLA_F_NESTED != 0
+ fmt.Printf("type=%d nested=%v len=%v %v\n", attr.Type&NLA_TYPE_MASK, nested, len(attr.Value), attr.Value)
+ if nested {
+ printAttributes(attr.Value, level+1)
+ }
+ }
+}
+
+// Uint32 returns the uint32 value respecting the NET_BYTEORDER flag
+func (attr *Attribute) Uint32() uint32 {
+ if attr.Type&NLA_F_NET_BYTEORDER != 0 {
+ return binary.BigEndian.Uint32(attr.Value)
+ } else {
+ return NativeEndian().Uint32(attr.Value)
+ }
+}
+
+// Uint64 returns the uint64 value respecting the NET_BYTEORDER flag
+func (attr *Attribute) Uint64() uint64 {
+ if attr.Type&NLA_F_NET_BYTEORDER != 0 {
+ return binary.BigEndian.Uint64(attr.Value)
+ } else {
+ return NativeEndian().Uint64(attr.Value)
+ }
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/syscall.go b/vendor/github.com/vishvananda/netlink/nl/syscall.go
index f7f7f92e6..4a01e6e59 100644
--- a/vendor/github.com/vishvananda/netlink/nl/syscall.go
+++ b/vendor/github.com/vishvananda/netlink/nl/syscall.go
@@ -21,6 +21,13 @@ const (
FRA_TABLE /* Extended table id */
FRA_FWMASK /* mask for netfilter mark */
FRA_OIFNAME
+ FRA_PAD
+ FRA_L3MDEV /* iif or oif is l3mdev goto its table */
+ FRA_UID_RANGE /* UID range */
+ FRA_PROTOCOL /* Originator of the rule */
+ FRA_IP_PROTO /* ip proto */
+ FRA_SPORT_RANGE /* sport */
+ FRA_DPORT_RANGE /* dport */
)
// ip rule netlink request types
diff --git a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
index 501f554b2..c24d53eb7 100644
--- a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
@@ -94,6 +94,9 @@ const (
SizeofTcTunnelKey = SizeofTcGen + 0x04
SizeofTcSkbEdit = SizeofTcGen
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
+ SizeofTcSfqQopt = 0x0b
+ SizeofTcSfqRedStats = 0x18
+ SizeofTcSfqQoptV1 = SizeofTcSfqQopt + SizeofTcSfqRedStats + 0x1c
)
// struct tcmsg {
@@ -735,7 +738,13 @@ const (
TCA_TUNNEL_KEY_ENC_IPV6_SRC
TCA_TUNNEL_KEY_ENC_IPV6_DST
TCA_TUNNEL_KEY_ENC_KEY_ID
- TCA_TUNNEL_KEY_MAX = TCA_TUNNEL_KEY_ENC_KEY_ID
+ TCA_TUNNEL_KEY_PAD
+ TCA_TUNNEL_KEY_ENC_DST_PORT
+ TCA_TUNNEL_KEY_NO_CSUM
+ TCA_TUNNEL_KEY_ENC_OPTS
+ TCA_TUNNEL_KEY_ENC_TOS
+ TCA_TUNNEL_KEY_ENC_TTL
+ TCA_TUNNEL_KEY_MAX
)
type TcTunnelKey struct {
@@ -872,3 +881,103 @@ const (
TCA_HFSC_FSC
TCA_HFSC_USC
)
+
+// struct tc_sfq_qopt {
+// unsigned quantum; /* Bytes per round allocated to flow */
+// int perturb_period; /* Period of hash perturbation */
+// __u32 limit; /* Maximal packets in queue */
+// unsigned divisor; /* Hash divisor */
+// unsigned flows; /* Maximal number of flows */
+// };
+
+type TcSfqQopt struct {
+ Quantum uint8
+ Perturb int32
+ Limit uint32
+ Divisor uint8
+ Flows uint8
+}
+
+func (x *TcSfqQopt) Len() int {
+ return SizeofTcSfqQopt
+}
+
+func DeserializeTcSfqQopt(b []byte) *TcSfqQopt {
+ return (*TcSfqQopt)(unsafe.Pointer(&b[0:SizeofTcSfqQopt][0]))
+}
+
+func (x *TcSfqQopt) Serialize() []byte {
+ return (*(*[SizeofTcSfqQopt]byte)(unsafe.Pointer(x)))[:]
+}
+
+// struct tc_sfqred_stats {
+// __u32 prob_drop; /* Early drops, below max threshold */
+// __u32 forced_drop; /* Early drops, after max threshold */
+// __u32 prob_mark; /* Marked packets, below max threshold */
+// __u32 forced_mark; /* Marked packets, after max threshold */
+// __u32 prob_mark_head; /* Marked packets, below max threshold */
+// __u32 forced_mark_head;/* Marked packets, after max threshold */
+// };
+type TcSfqRedStats struct {
+ ProbDrop uint32
+ ForcedDrop uint32
+ ProbMark uint32
+ ForcedMark uint32
+ ProbMarkHead uint32
+ ForcedMarkHead uint32
+}
+
+func (x *TcSfqRedStats) Len() int {
+ return SizeofTcSfqRedStats
+}
+
+func DeserializeTcSfqRedStats(b []byte) *TcSfqRedStats {
+ return (*TcSfqRedStats)(unsafe.Pointer(&b[0:SizeofTcSfqRedStats][0]))
+}
+
+func (x *TcSfqRedStats) Serialize() []byte {
+ return (*(*[SizeofTcSfqRedStats]byte)(unsafe.Pointer(x)))[:]
+}
+
+// struct tc_sfq_qopt_v1 {
+// struct tc_sfq_qopt v0;
+// unsigned int depth; /* max number of packets per flow */
+// unsigned int headdrop;
+// /* SFQRED parameters */
+// __u32 limit; /* HARD maximal flow queue length (bytes) */
+// __u32 qth_min; /* Min average length threshold (bytes) */
+// __u32 qth_max; /* Max average length threshold (bytes) */
+// unsigned char Wlog; /* log(W) */
+// unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
+// unsigned char Scell_log; /* cell size for idle damping */
+// unsigned char flags;
+// __u32 max_P; /* probability, high resolution */
+// /* SFQRED stats */
+// struct tc_sfqred_stats stats;
+// };
+type TcSfqQoptV1 struct {
+ TcSfqQopt
+ Depth uint32
+ HeadDrop uint32
+ Limit uint32
+ QthMin uint32
+ QthMax uint32
+ Wlog byte
+ Plog byte
+ ScellLog byte
+ Flags byte
+ MaxP uint32
+ TcSfqRedStats
+}
+
+func (x *TcSfqQoptV1) Len() int {
+ return SizeofTcSfqQoptV1
+}
+
+func DeserializeTcSfqQoptV1(b []byte) *TcSfqQoptV1 {
+ return (*TcSfqQoptV1)(unsafe.Pointer(&b[0:SizeofTcSfqQoptV1][0]))
+}
+
+func (x *TcSfqQoptV1) Serialize() []byte {
+ return (*(*[SizeofTcSfqQoptV1]byte)(unsafe.Pointer(x)))[:]
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
index b6290fd54..43a947f22 100644
--- a/vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
@@ -13,7 +13,7 @@ const (
SizeofXfrmAlgoAuth = 0x48
SizeofXfrmAlgoAEAD = 0x48
SizeofXfrmEncapTmpl = 0x18
- SizeofXfrmUsersaFlush = 0x8
+ SizeofXfrmUsersaFlush = 0x1
SizeofXfrmReplayStateEsn = 0x18
)
diff --git a/vendor/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/vishvananda/netlink/qdisc.go
index af78305ac..8418569ee 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc.go
@@ -338,3 +338,27 @@ func (qdisc *FqCodel) Attrs() *QdiscAttrs {
func (qdisc *FqCodel) Type() string {
return "fq_codel"
}
+
+type Sfq struct {
+ QdiscAttrs
+ // TODO: Only the simplified options for SFQ are handled here. Support for the extended one can be added later.
+ Quantum uint8
+ Perturb uint8
+ Limit uint32
+ Divisor uint8
+}
+
+func (sfq *Sfq) String() string {
+ return fmt.Sprintf(
+ "{%v -- Quantum: %v, Perturb: %v, Limit: %v, Divisor: %v}",
+ sfq.Attrs(), sfq.Quantum, sfq.Perturb, sfq.Limit, sfq.Divisor,
+ )
+}
+
+func (qdisc *Sfq) Attrs() *QdiscAttrs {
+ return &qdisc.QdiscAttrs
+}
+
+func (qdisc *Sfq) Type() string {
+ return "sfq"
+}
diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
index e9eee5908..d0e1ca194 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
@@ -278,6 +278,14 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
if qdisc.FlowDefaultRate > 0 {
options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
}
+ case *Sfq:
+ opt := nl.TcSfqQoptV1{}
+ opt.TcSfqQopt.Quantum = qdisc.Quantum
+ opt.TcSfqQopt.Perturb = int32(qdisc.Perturb)
+ opt.TcSfqQopt.Limit = qdisc.Limit
+ opt.TcSfqQopt.Divisor = qdisc.Divisor
+
+ options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
default:
options = nil
}
@@ -362,6 +370,8 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
qdisc = &FqCodel{}
case "netem":
qdisc = &Netem{}
+ case "sfq":
+ qdisc = &Sfq{}
default:
qdisc = &GenericQdisc{QdiscType: qdiscType}
}
@@ -417,6 +427,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
if err := parseNetemData(qdisc, attr.Value); err != nil {
return nil, err
}
+ case "sfq":
+ if err := parseSfqData(qdisc, attr.Value); err != nil {
+ return nil, err
+ }
// no options for ingress
}
@@ -582,6 +596,17 @@ func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
return nil
}
+func parseSfqData(qdisc Qdisc, value []byte) error {
+ sfq := qdisc.(*Sfq)
+ opt := nl.DeserializeTcSfqQoptV1(value)
+ sfq.Quantum = opt.TcSfqQopt.Quantum
+ sfq.Perturb = uint8(opt.TcSfqQopt.Perturb)
+ sfq.Limit = opt.TcSfqQopt.Limit
+ sfq.Divisor = opt.TcSfqQopt.Divisor
+
+ return nil
+}
+
const (
TIME_UNITS_PER_SEC = 1000000
)
@@ -598,10 +623,10 @@ func initClock() {
return
}
parts := strings.Split(strings.TrimSpace(string(data)), " ")
- if len(parts) < 3 {
+ if len(parts) < 4 {
return
}
- var vals [3]uint64
+ var vals [4]uint64
for i := range vals {
val, err := strconv.ParseUint(parts[i], 16, 32)
if err != nil {
@@ -615,7 +640,12 @@ func initClock() {
}
clockFactor = float64(vals[2]) / TIME_UNITS_PER_SEC
tickInUsec = float64(vals[0]) / float64(vals[1]) * clockFactor
- hz = float64(vals[0])
+ if vals[2] == 1000000 {
+ // ref https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c#n963
+ hz = float64(vals[3])
+ } else {
+ hz = 100
+ }
}
func TickInUsec() float64 {
@@ -663,6 +693,7 @@ func latency(rate uint64, limit, buffer uint32) float64 {
return TIME_UNITS_PER_SEC*(float64(limit)/float64(rate)) - float64(tick2Time(buffer))
}
-func Xmittime(rate uint64, size uint32) float64 {
- return TickInUsec() * TIME_UNITS_PER_SEC * (float64(size) / float64(rate))
+func Xmittime(rate uint64, size uint32) uint32 {
+ // https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/tc/tc_core.c#n62
+ return time2Tick(uint32(TIME_UNITS_PER_SEC * (float64(size) / float64(rate))))
}
diff --git a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
index 2d0bdc8c3..ff014ca4c 100644
--- a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
@@ -77,28 +77,39 @@ func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
return &link, nil
}
-func execRdmaGetLink(req *nl.NetlinkRequest, name string) (*RdmaLink, error) {
+func execRdmaSetLink(req *nl.NetlinkRequest) error {
+
+ _, err := req.Execute(unix.NETLINK_RDMA, 0)
+ return err
+}
+
+// RdmaLinkList gets a list of RDMA link devices.
+// Equivalent to: `rdma dev show`
+func RdmaLinkList() ([]*RdmaLink, error) {
+ return pkgHandle.RdmaLinkList()
+}
+
+// RdmaLinkList gets a list of RDMA link devices.
+// Equivalent to: `rdma dev show`
+func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
if err != nil {
return nil, err
}
+
+ var res []*RdmaLink
for _, m := range msgs {
link, err := executeOneGetRdmaLink(m)
if err != nil {
return nil, err
}
- if link.Attrs.Name == name {
- return link, nil
- }
+ res = append(res, link)
}
- return nil, fmt.Errorf("Rdma device %v not found", name)
-}
-func execRdmaSetLink(req *nl.NetlinkRequest) error {
-
- _, err := req.Execute(unix.NETLINK_RDMA, 0)
- return err
+ return res, nil
}
// RdmaLinkByName finds a link by name and returns a pointer to the object if
@@ -110,11 +121,16 @@ func RdmaLinkByName(name string) (*RdmaLink, error) {
// RdmaLinkByName finds a link by name and returns a pointer to the object if
// found and nil error, otherwise returns error code.
func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
-
- proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
- req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
-
- return execRdmaGetLink(req, name)
+ links, err := h.RdmaLinkList()
+ if err != nil {
+ return nil, err
+ }
+ for _, link := range links {
+ if link.Attrs.Name == name {
+ return link, nil
+ }
+ }
+ return nil, fmt.Errorf("Rdma device %v not found", name)
}
// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
diff --git a/vendor/github.com/vishvananda/netlink/route.go b/vendor/github.com/vishvananda/netlink/route.go
index 58ff1af60..b16254174 100644
--- a/vendor/github.com/vishvananda/netlink/route.go
+++ b/vendor/github.com/vishvananda/netlink/route.go
@@ -29,25 +29,38 @@ type Encap interface {
// Route represents a netlink route.
type Route struct {
- LinkIndex int
- ILinkIndex int
- Scope Scope
- Dst *net.IPNet
- Src net.IP
- Gw net.IP
- MultiPath []*NexthopInfo
- Protocol int
- Priority int
- Table int
- Type int
- Tos int
- Flags int
- MPLSDst *int
- NewDst Destination
- Encap Encap
- MTU int
- AdvMSS int
- Hoplimit int
+ LinkIndex int
+ ILinkIndex int
+ Scope Scope
+ Dst *net.IPNet
+ Src net.IP
+ Gw net.IP
+ MultiPath []*NexthopInfo
+ Protocol int
+ Priority int
+ Table int
+ Type int
+ Tos int
+ Flags int
+ MPLSDst *int
+ NewDst Destination
+ Encap Encap
+ MTU int
+ Window int
+ Rtt int
+ RttVar int
+ Ssthresh int
+ Cwnd int
+ AdvMSS int
+ Reordering int
+ Hoplimit int
+ InitCwnd int
+ Features int
+ RtoMin int
+ InitRwnd int
+ QuickACK int
+ Congctl string
+ FastOpenNoCookie int
}
func (r Route) String() string {
diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go
index c69c595ed..4e778a417 100644
--- a/vendor/github.com/vishvananda/netlink/route_linux.go
+++ b/vendor/github.com/vishvananda/netlink/route_linux.go
@@ -33,6 +33,9 @@ const (
RT_FILTER_GW
RT_FILTER_TABLE
RT_FILTER_HOPLIMIT
+ RT_FILTER_PRIORITY
+ RT_FILTER_MARK
+ RT_FILTER_MASK
)
const (
@@ -639,19 +642,70 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
}
var metrics []*nl.RtAttr
- // TODO: support other rta_metric values
if route.MTU > 0 {
b := nl.Uint32Attr(uint32(route.MTU))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
}
+ if route.Window > 0 {
+ b := nl.Uint32Attr(uint32(route.Window))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_WINDOW, b))
+ }
+ if route.Rtt > 0 {
+ b := nl.Uint32Attr(uint32(route.Rtt))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTT, b))
+ }
+ if route.RttVar > 0 {
+ b := nl.Uint32Attr(uint32(route.RttVar))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTTVAR, b))
+ }
+ if route.Ssthresh > 0 {
+ b := nl.Uint32Attr(uint32(route.Ssthresh))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_SSTHRESH, b))
+ }
+ if route.Cwnd > 0 {
+ b := nl.Uint32Attr(uint32(route.Cwnd))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_CWND, b))
+ }
if route.AdvMSS > 0 {
b := nl.Uint32Attr(uint32(route.AdvMSS))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
}
+ if route.Reordering > 0 {
+ b := nl.Uint32Attr(uint32(route.Reordering))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_REORDERING, b))
+ }
if route.Hoplimit > 0 {
b := nl.Uint32Attr(uint32(route.Hoplimit))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b))
}
+ if route.InitCwnd > 0 {
+ b := nl.Uint32Attr(uint32(route.InitCwnd))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_INITCWND, b))
+ }
+ if route.Features > 0 {
+ b := nl.Uint32Attr(uint32(route.Features))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_FEATURES, b))
+ }
+ if route.RtoMin > 0 {
+ b := nl.Uint32Attr(uint32(route.RtoMin))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTO_MIN, b))
+ }
+ if route.InitRwnd > 0 {
+ b := nl.Uint32Attr(uint32(route.InitRwnd))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_INITRWND, b))
+ }
+ if route.QuickACK > 0 {
+ b := nl.Uint32Attr(uint32(route.QuickACK))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_QUICKACK, b))
+ }
+ if route.Congctl != "" {
+ b := nl.ZeroTerminated(route.Congctl)
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_CC_ALGO, b))
+ }
+ if route.FastOpenNoCookie > 0 {
+ b := nl.Uint32Attr(uint32(route.FastOpenNoCookie))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_FASTOPEN_NO_COOKIE, b))
+ }
if metrics != nil {
attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
@@ -903,10 +957,36 @@ func deserializeRoute(m []byte) (Route, error) {
switch metric.Attr.Type {
case unix.RTAX_MTU:
route.MTU = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_WINDOW:
+ route.Window = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_RTT:
+ route.Rtt = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_RTTVAR:
+ route.RttVar = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_SSTHRESH:
+ route.Ssthresh = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_CWND:
+ route.Cwnd = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_ADVMSS:
route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_REORDERING:
+ route.Reordering = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_HOPLIMIT:
route.Hoplimit = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_INITCWND:
+ route.InitCwnd = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_FEATURES:
+ route.Features = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_RTO_MIN:
+ route.RtoMin = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_INITRWND:
+ route.InitRwnd = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_QUICKACK:
+ route.QuickACK = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_CC_ALGO:
+ route.Congctl = nl.BytesToString(metric.Value)
+ case unix.RTAX_FASTOPEN_NO_COOKIE:
+ route.FastOpenNoCookie = int(native.Uint32(metric.Value[0:4]))
}
}
}
@@ -938,15 +1018,27 @@ func deserializeRoute(m []byte) (Route, error) {
return route, nil
}
+// RouteGetOptions contains a set of options to use with
+// RouteGetWithOptions
+type RouteGetOptions struct {
+ VrfName string
+}
+
+// RouteGetWithOptions gets a route to a specific destination from the host system.
+// Equivalent to: 'ip route get <> vrf <VrfName>'.
+func RouteGetWithOptions(destination net.IP, options *RouteGetOptions) ([]Route, error) {
+ return pkgHandle.RouteGetWithOptions(destination, options)
+}
+
// RouteGet gets a route to a specific destination from the host system.
// Equivalent to: 'ip route get'.
func RouteGet(destination net.IP) ([]Route, error) {
return pkgHandle.RouteGet(destination)
}
-// RouteGet gets a route to a specific destination from the host system.
-// Equivalent to: 'ip route get'.
-func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
+// RouteGetWithOptions gets a route to a specific destination from the host system.
+// Equivalent to: 'ip route get <> vrf <VrfName>'.
+func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOptions) ([]Route, error) {
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST)
family := nl.GetIPFamily(destination)
var destinationData []byte
@@ -966,6 +1058,20 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst)
+ if options != nil {
+ link, err := LinkByName(options.VrfName)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ b = make([]byte, 4)
+ native = nl.NativeEndian()
+ )
+ native.PutUint32(b, uint32(link.Attrs().Index))
+
+ req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
+ }
+
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
return nil, err
@@ -980,7 +1086,12 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
res = append(res, route)
}
return res, nil
+}
+// RouteGet gets a route to a specific destination from the host system.
+// Equivalent to: 'ip route get'.
+func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
+ return h.RouteGetWithOptions(destination, nil)
}
// RouteSubscribe takes a chan down which notifications will be sent
diff --git a/vendor/github.com/vishvananda/netlink/rule.go b/vendor/github.com/vishvananda/netlink/rule.go
index 7fc8ae5df..95f2facfb 100644
--- a/vendor/github.com/vishvananda/netlink/rule.go
+++ b/vendor/github.com/vishvananda/netlink/rule.go
@@ -12,6 +12,7 @@ type Rule struct {
Table int
Mark int
Mask int
+ Tos uint
TunID uint
Goto int
Src *net.IPNet
@@ -22,6 +23,8 @@ type Rule struct {
SuppressIfgroup int
SuppressPrefixlen int
Invert bool
+ Dport *RulePortRange
+ Sport *RulePortRange
}
func (r Rule) String() string {
@@ -40,3 +43,14 @@ func NewRule() *Rule {
Flow: -1,
}
}
+
+// NewRulePortRange creates rule sport/dport range.
+func NewRulePortRange(start, end uint16) *RulePortRange {
+ return &RulePortRange{Start: start, End: end}
+}
+
+// RulePortRange represents rule sport/dport range.
+type RulePortRange struct {
+ Start uint16
+ End uint16
+}
diff --git a/vendor/github.com/vishvananda/netlink/rule_linux.go b/vendor/github.com/vishvananda/netlink/rule_linux.go
index e12569fe4..40474f30e 100644
--- a/vendor/github.com/vishvananda/netlink/rule_linux.go
+++ b/vendor/github.com/vishvananda/netlink/rule_linux.go
@@ -1,6 +1,7 @@
package netlink
import (
+ "bytes"
"fmt"
"net"
@@ -55,6 +56,9 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
if rule.Table >= 0 && rule.Table < 256 {
msg.Table = uint8(rule.Table)
}
+ if rule.Tos != 0 {
+ msg.Tos = uint8(rule.Tos)
+ }
var dstFamily uint8
var rtAttrs []*nl.RtAttr
@@ -138,10 +142,10 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
}
}
if rule.IifName != "" {
- req.AddData(nl.NewRtAttr(nl.FRA_IIFNAME, []byte(rule.IifName)))
+ req.AddData(nl.NewRtAttr(nl.FRA_IIFNAME, []byte(rule.IifName+"\x00")))
}
if rule.OifName != "" {
- req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName)))
+ req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName+"\x00")))
}
if rule.Goto >= 0 {
msg.Type = nl.FR_ACT_GOTO
@@ -150,6 +154,16 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
}
+ if rule.Dport != nil {
+ b := rule.Dport.toRtAttrData()
+ req.AddData(nl.NewRtAttr(nl.FRA_DPORT_RANGE, b))
+ }
+
+ if rule.Sport != nil {
+ b := rule.Sport.toRtAttrData()
+ req.AddData(nl.NewRtAttr(nl.FRA_SPORT_RANGE, b))
+ }
+
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@@ -163,6 +177,19 @@ func RuleList(family int) ([]Rule, error) {
// RuleList lists rules in the system.
// Equivalent to: ip rule list
func (h *Handle) RuleList(family int) ([]Rule, error) {
+ return h.RuleListFiltered(family, nil, 0)
+}
+
+// RuleListFiltered gets a list of rules in the system filtered by the
+// specified rule template `filter`.
+// Equivalent to: ip rule list
+func RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
+ return pkgHandle.RuleListFiltered(family, filter, filterMask)
+}
+
+// RuleListFiltered lists rules in the system.
+// Equivalent to: ip rule list
+func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
@@ -184,6 +211,7 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
rule := NewRule()
rule.Invert = msg.Flags&FibRuleInvert > 0
+ rule.Tos = uint(msg.Tos)
for j := range attrs {
switch attrs[j].Attr.Type {
@@ -225,10 +253,44 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
rule.Goto = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_PRIORITY:
rule.Priority = int(native.Uint32(attrs[j].Value[0:4]))
+ case nl.FRA_DPORT_RANGE:
+ rule.Dport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4]))
+ case nl.FRA_SPORT_RANGE:
+ rule.Sport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4]))
+ }
+ }
+
+ if filter != nil {
+ switch {
+ case filterMask&RT_FILTER_SRC != 0 &&
+ (rule.Src == nil || rule.Src.String() != filter.Src.String()):
+ continue
+ case filterMask&RT_FILTER_DST != 0 &&
+ (rule.Dst == nil || rule.Dst.String() != filter.Dst.String()):
+ continue
+ case filterMask&RT_FILTER_TABLE != 0 &&
+ filter.Table != unix.RT_TABLE_UNSPEC && rule.Table != filter.Table:
+ continue
+ case filterMask&RT_FILTER_TOS != 0 && rule.Tos != filter.Tos:
+ continue
+ case filterMask&RT_FILTER_PRIORITY != 0 && rule.Priority != filter.Priority:
+ continue
+ case filterMask&RT_FILTER_MARK != 0 && rule.Mark != filter.Mark:
+ continue
+ case filterMask&RT_FILTER_MASK != 0 && rule.Mask != filter.Mask:
+ continue
}
}
+
res = append(res, *rule)
}
return res, nil
}
+
+func (pr *RulePortRange) toRtAttrData() []byte {
+ b := [][]byte{make([]byte, 2), make([]byte, 2)}
+ native.PutUint16(b[0], pr.Start)
+ native.PutUint16(b[1], pr.End)
+ return bytes.Join(b, []byte{})
+}
diff --git a/vendor/github.com/vishvananda/netlink/socket_linux.go b/vendor/github.com/vishvananda/netlink/socket_linux.go
index c4d89c17e..e4e7f7ac3 100644
--- a/vendor/github.com/vishvananda/netlink/socket_linux.go
+++ b/vendor/github.com/vishvananda/netlink/socket_linux.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net"
+ "syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
@@ -49,10 +50,15 @@ func (r *socketRequest) Serialize() []byte {
native.PutUint32(b.Next(4), r.States)
networkOrder.PutUint16(b.Next(2), r.ID.SourcePort)
networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort)
- copy(b.Next(4), r.ID.Source.To4())
- b.Next(12)
- copy(b.Next(4), r.ID.Destination.To4())
- b.Next(12)
+ if r.Family == unix.AF_INET6 {
+ copy(b.Next(16), r.ID.Source)
+ copy(b.Next(16), r.ID.Destination)
+ } else {
+ copy(b.Next(4), r.ID.Source.To4())
+ b.Next(12)
+ copy(b.Next(4), r.ID.Destination.To4())
+ b.Next(12)
+ }
native.PutUint32(b.Next(4), r.ID.Interface)
native.PutUint32(b.Next(4), r.ID.Cookie[0])
native.PutUint32(b.Next(4), r.ID.Cookie[1])
@@ -89,10 +95,15 @@ func (s *Socket) deserialize(b []byte) error {
s.Retrans = rb.Read()
s.ID.SourcePort = networkOrder.Uint16(rb.Next(2))
s.ID.DestinationPort = networkOrder.Uint16(rb.Next(2))
- s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
- rb.Next(12)
- s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
- rb.Next(12)
+ if s.Family == unix.AF_INET6 {
+ s.ID.Source = net.IP(rb.Next(16))
+ s.ID.Destination = net.IP(rb.Next(16))
+ } else {
+ s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
+ rb.Next(12)
+ s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
+ rb.Next(12)
+ }
s.ID.Interface = native.Uint32(rb.Next(4))
s.ID.Cookie[0] = native.Uint32(rb.Next(4))
s.ID.Cookie[1] = native.Uint32(rb.Next(4))
@@ -160,3 +171,68 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
}
return sock, nil
}
+
+// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type.
+func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
+ s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
+ if err != nil {
+ return nil, err
+ }
+ defer s.Close()
+
+ req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+ req.AddData(&socketRequest{
+ Family: family,
+ Protocol: unix.IPPROTO_TCP,
+ Ext: INET_DIAG_INFO,
+ States: uint32(0xfff), // All TCP states
+ })
+ s.Send(req)
+
+ var result []*InetDiagTCPInfoResp
+loop:
+ for {
+ msgs, from, err := s.Receive()
+ if err != nil {
+ return nil, err
+ }
+ if from.Pid != nl.PidKernel {
+ return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+ }
+ if len(msgs) == 0 {
+ return nil, errors.New("no message nor error from netlink")
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case unix.NLMSG_DONE:
+ break loop
+ case unix.NLMSG_ERROR:
+ native := nl.NativeEndian()
+ error := int32(native.Uint32(m.Data[0:4]))
+ return nil, syscall.Errno(-error)
+ }
+ sockInfo := &Socket{}
+ if err := sockInfo.deserialize(m.Data); err != nil {
+ return nil, err
+ }
+ attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
+ if err != nil {
+ return nil, err
+ }
+ var tcpInfo *TCPInfo
+ for _, a := range attrs {
+ if a.Attr.Type == INET_DIAG_INFO {
+ tcpInfo = &TCPInfo{}
+ if err := tcpInfo.deserialize(a.Value); err != nil {
+ return nil, err
+ }
+ break
+ }
+ }
+ r := &InetDiagTCPInfoResp{InetDiagMsg: sockInfo, TCPInfo: tcpInfo}
+ result = append(result, r)
+ }
+ }
+ return result, nil
+}
diff --git a/vendor/github.com/vishvananda/netlink/tcp.go b/vendor/github.com/vishvananda/netlink/tcp.go
new file mode 100644
index 000000000..4a42ee5a6
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/tcp.go
@@ -0,0 +1,18 @@
+package netlink
+
+// TCP States
+const (
+ TCP_ESTABLISHED = iota + 0x01
+ TCP_SYN_SENT
+ TCP_SYN_RECV
+ TCP_FIN_WAIT1
+ TCP_FIN_WAIT2
+ TCP_TIME_WAIT
+ TCP_CLOSE
+ TCP_CLOSE_WAIT
+ TCP_LAST_ACK
+ TCP_LISTEN
+ TCP_CLOSING
+ TCP_NEW_SYN_REC
+ TCP_MAX_STATES
+)
diff --git a/vendor/github.com/vishvananda/netlink/tcp_linux.go b/vendor/github.com/vishvananda/netlink/tcp_linux.go
new file mode 100644
index 000000000..741ea1655
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/tcp_linux.go
@@ -0,0 +1,393 @@
+package netlink
+
+import (
+ "bytes"
+ "io"
+)
+
+type TCPInfo struct {
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Snd_wscale uint8 // no uint4
+ Rcv_wscale uint8
+ Delivery_rate_app_limited uint8
+ Fastopen_client_fail uint8
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+ Pacing_rate uint64
+ Max_pacing_rate uint64
+ Bytes_acked uint64 /* RFC4898 tcpEStatsAppHCThruOctetsAcked */
+ Bytes_received uint64 /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
+ Segs_out uint32 /* RFC4898 tcpEStatsPerfSegsOut */
+ Segs_in uint32 /* RFC4898 tcpEStatsPerfSegsIn */
+ Notsent_bytes uint32
+ Min_rtt uint32
+ Data_segs_in uint32 /* RFC4898 tcpEStatsDataSegsIn */
+ Data_segs_out uint32 /* RFC4898 tcpEStatsDataSegsOut */
+ Delivery_rate uint64
+ Busy_time uint64 /* Time (usec) busy sending data */
+ Rwnd_limited uint64 /* Time (usec) limited by receive window */
+ Sndbuf_limited uint64 /* Time (usec) limited by send buffer */
+ Delivered uint32
+ Delivered_ce uint32
+ Bytes_sent uint64 /* RFC4898 tcpEStatsPerfHCDataOctetsOut */
+ Bytes_retrans uint64 /* RFC4898 tcpEStatsPerfOctetsRetrans */
+ Dsack_dups uint32 /* RFC4898 tcpEStatsStackDSACKDups */
+ Reord_seen uint32 /* reordering events seen */
+ Rcv_ooopack uint32 /* Out-of-order packets received */
+ Snd_wnd uint32 /* peer's advertised receive window after * scaling (bytes) */
+}
+
+func checkDeserErr(err error) error {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+}
+
+func (t *TCPInfo) deserialize(b []byte) error {
+ var err error
+ rb := bytes.NewBuffer(b)
+
+ t.State, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+
+ t.Ca_state, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+
+ t.Retransmits, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+
+ t.Probes, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+
+ t.Backoff, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+ t.Options, err = rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+
+ scales, err := rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+ t.Snd_wscale = scales >> 4 // first 4 bits
+ t.Rcv_wscale = scales & 0xf // last 4 bits
+
+ rateLimAndFastOpen, err := rb.ReadByte()
+ if err != nil {
+ return checkDeserErr(err)
+ }
+ t.Delivery_rate_app_limited = rateLimAndFastOpen >> 7 // get first bit
+ t.Fastopen_client_fail = rateLimAndFastOpen >> 5 & 3 // get next two bits
+
+ next := rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rto = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Ato = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Snd_mss = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rcv_mss = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Unacked = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Sacked = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Lost = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Retrans = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Fackets = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Last_data_sent = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Last_ack_sent = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Last_data_recv = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Last_ack_recv = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Pmtu = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rcv_ssthresh = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rtt = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rttvar = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Snd_ssthresh = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Snd_cwnd = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Advmss = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Reordering = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rcv_rtt = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rcv_space = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Total_retrans = native.Uint32(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Pacing_rate = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Max_pacing_rate = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Bytes_acked = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Bytes_received = native.Uint64(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Segs_out = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Segs_in = native.Uint32(next)
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Notsent_bytes = native.Uint32(next)
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Min_rtt = native.Uint32(next)
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Data_segs_in = native.Uint32(next)
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Data_segs_out = native.Uint32(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Delivery_rate = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Busy_time = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rwnd_limited = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Sndbuf_limited = native.Uint64(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Delivered = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Delivered_ce = native.Uint32(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Bytes_sent = native.Uint64(next)
+
+ next = rb.Next(8)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Bytes_retrans = native.Uint64(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Dsack_dups = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Reord_seen = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Rcv_ooopack = native.Uint32(next)
+
+ next = rb.Next(4)
+ if len(next) == 0 {
+ return nil
+ }
+ t.Snd_wnd = native.Uint32(next)
+ return nil
+}
diff --git a/vendor/github.com/vishvananda/netns/go.mod b/vendor/github.com/vishvananda/netns/go.mod
index 8221f782c..9cdf577ad 100644
--- a/vendor/github.com/vishvananda/netns/go.mod
+++ b/vendor/github.com/vishvananda/netns/go.mod
@@ -1,3 +1,5 @@
module github.com/vishvananda/netns
go 1.12
+
+require golang.org/x/sys v0.0.0-20200217220822-9197077df867
diff --git a/vendor/github.com/vishvananda/netns/go.sum b/vendor/github.com/vishvananda/netns/go.sum
index e69de29bb..1d4adf451 100644
--- a/vendor/github.com/vishvananda/netns/go.sum
+++ b/vendor/github.com/vishvananda/netns/go.sum
@@ -0,0 +1,2 @@
+golang.org/x/sys v0.0.0-20200217220822-9197077df867 h1:JoRuNIf+rpHl+VhScRQQvzbHed86tKkqwPMV34T8myw=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/vishvananda/netns/netns.go b/vendor/github.com/vishvananda/netns/netns.go
index dd2f21570..116befd54 100644
--- a/vendor/github.com/vishvananda/netns/netns.go
+++ b/vendor/github.com/vishvananda/netns/netns.go
@@ -10,7 +10,8 @@ package netns
import (
"fmt"
- "syscall"
+
+ "golang.org/x/sys/unix"
)
// NsHandle is a handle to a network namespace. It can be cast directly
@@ -24,11 +25,11 @@ func (ns NsHandle) Equal(other NsHandle) bool {
if ns == other {
return true
}
- var s1, s2 syscall.Stat_t
- if err := syscall.Fstat(int(ns), &s1); err != nil {
+ var s1, s2 unix.Stat_t
+ if err := unix.Fstat(int(ns), &s1); err != nil {
return false
}
- if err := syscall.Fstat(int(other), &s2); err != nil {
+ if err := unix.Fstat(int(other), &s2); err != nil {
return false
}
return (s1.Dev == s2.Dev) && (s1.Ino == s2.Ino)
@@ -36,11 +37,11 @@ func (ns NsHandle) Equal(other NsHandle) bool {
// String shows the file descriptor number and its dev and inode.
func (ns NsHandle) String() string {
- var s syscall.Stat_t
if ns == -1 {
return "NS(None)"
}
- if err := syscall.Fstat(int(ns), &s); err != nil {
+ var s unix.Stat_t
+ if err := unix.Fstat(int(ns), &s); err != nil {
return fmt.Sprintf("NS(%d: unknown)", ns)
}
return fmt.Sprintf("NS(%d: %d, %d)", ns, s.Dev, s.Ino)
@@ -49,11 +50,11 @@ func (ns NsHandle) String() string {
// UniqueId returns a string which uniquely identifies the namespace
// associated with the network handle.
func (ns NsHandle) UniqueId() string {
- var s syscall.Stat_t
if ns == -1 {
return "NS(none)"
}
- if err := syscall.Fstat(int(ns), &s); err != nil {
+ var s unix.Stat_t
+ if err := unix.Fstat(int(ns), &s); err != nil {
return "NS(unknown)"
}
return fmt.Sprintf("NS(%d:%d)", s.Dev, s.Ino)
@@ -67,7 +68,7 @@ func (ns NsHandle) IsOpen() bool {
// Close closes the NsHandle and resets its file descriptor to -1.
// It is not safe to use an NsHandle after Close() is called.
func (ns *NsHandle) Close() error {
- if err := syscall.Close(int(*ns)); err != nil {
+ if err := unix.Close(int(*ns)); err != nil {
return err
}
(*ns) = -1
diff --git a/vendor/github.com/vishvananda/netns/netns_linux.go b/vendor/github.com/vishvananda/netns/netns_linux.go
index b1e3b07c0..c76acd087 100644
--- a/vendor/github.com/vishvananda/netns/netns_linux.go
+++ b/vendor/github.com/vishvananda/netns/netns_linux.go
@@ -6,46 +6,30 @@ import (
"fmt"
"io/ioutil"
"os"
+ "path"
"path/filepath"
- "runtime"
"strconv"
"strings"
"syscall"
-)
-// SYS_SETNS syscall allows changing the namespace of the current process.
-var SYS_SETNS = map[string]uintptr{
- "386": 346,
- "amd64": 308,
- "arm64": 268,
- "arm": 375,
- "mips": 4344,
- "mipsle": 4344,
- "mips64le": 4344,
- "ppc64": 350,
- "ppc64le": 350,
- "riscv64": 268,
- "s390x": 339,
-}[runtime.GOARCH]
+ "golang.org/x/sys/unix"
+)
// Deprecated: use syscall pkg instead (go >= 1.5 needed).
const (
- CLONE_NEWUTS = 0x04000000 /* New utsname group? */
- CLONE_NEWIPC = 0x08000000 /* New ipcs */
- CLONE_NEWUSER = 0x10000000 /* New user namespace */
- CLONE_NEWPID = 0x20000000 /* New pid namespace */
- CLONE_NEWNET = 0x40000000 /* New network namespace */
- CLONE_IO = 0x80000000 /* Get io context */
+ CLONE_NEWUTS = 0x04000000 /* New utsname group? */
+ CLONE_NEWIPC = 0x08000000 /* New ipcs */
+ CLONE_NEWUSER = 0x10000000 /* New user namespace */
+ CLONE_NEWPID = 0x20000000 /* New pid namespace */
+ CLONE_NEWNET = 0x40000000 /* New network namespace */
+ CLONE_IO = 0x80000000 /* Get io context */
+ bindMountPath = "/run/netns" /* Bind mount path for named netns */
)
// Setns sets namespace using syscall. Note that this should be a method
// in syscall but it has not been added.
func Setns(ns NsHandle, nstype int) (err error) {
- _, _, e1 := syscall.Syscall(SYS_SETNS, uintptr(ns), uintptr(nstype), 0)
- if e1 != 0 {
- err = e1
- }
- return
+ return unix.Setns(int(ns), nstype)
}
// Set sets the current network namespace to the namespace represented
@@ -57,21 +41,64 @@ func Set(ns NsHandle) (err error) {
// New creates a new network namespace, sets it as current and returns
// a handle to it.
func New() (ns NsHandle, err error) {
- if err := syscall.Unshare(CLONE_NEWNET); err != nil {
+ if err := unix.Unshare(CLONE_NEWNET); err != nil {
return -1, err
}
return Get()
}
+// NewNamed creates a new named network namespace and returns a handle to it
+func NewNamed(name string) (NsHandle, error) {
+ if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
+ err = os.MkdirAll(bindMountPath, 0755)
+ if err != nil {
+ return None(), err
+ }
+ }
+
+ newNs, err := New()
+ if err != nil {
+ return None(), err
+ }
+
+ namedPath := path.Join(bindMountPath, name)
+
+ f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
+ if err != nil {
+ return None(), err
+ }
+ f.Close()
+
+ nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
+ err = syscall.Mount(nsPath, namedPath, "bind", syscall.MS_BIND, "")
+ if err != nil {
+ return None(), err
+ }
+
+ return newNs, nil
+}
+
+// DeleteNamed deletes a named network namespace
+func DeleteNamed(name string) error {
+ namedPath := path.Join(bindMountPath, name)
+
+ err := syscall.Unmount(namedPath, syscall.MNT_DETACH)
+ if err != nil {
+ return err
+ }
+
+ return os.Remove(namedPath)
+}
+
// Get gets a handle to the current threads network namespace.
func Get() (NsHandle, error) {
- return GetFromThread(os.Getpid(), syscall.Gettid())
+ return GetFromThread(os.Getpid(), unix.Gettid())
}
// GetFromPath gets a handle to a network namespace
// identified by the path
func GetFromPath(path string) (NsHandle, error) {
- fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
+ fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
if err != nil {
return -1, err
}
diff --git a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
index 06f84b855..6b4027b33 100644
--- a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
+++ b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_arm64.s
index a54436e39..cfc08c979 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_arm64.s
+++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go
index 7b88e865a..7f7f272a0 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
package cpu
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
index 568bcd031..75a955661 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
package cpu
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
index f7cb46971..4adb89cf9 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32
-// +build !gccgo
+// +build gc
package cpu
diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s
index e5037d92e..964946df9 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_s390x.s
+++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.s b/vendor/golang.org/x/sys/cpu/cpu_x86.s
index 47f084128..2f557a588 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_x86.s
+++ b/vendor/golang.org/x/sys/cpu/cpu_x86.s
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
index 78fe25e86..5b427d67e 100644
--- a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
+++ b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
@@ -7,7 +7,7 @@
// (See golang.org/issue/32102)
// +build aix,ppc64
-// +build !gccgo
+// +build gc
package cpu
diff --git a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
index 06f84b855..6b4027b33 100644
--- a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
+++ b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_386.s b/vendor/golang.org/x/sys/unix/asm_darwin_386.s
index 8a7278319..8a06b87d7 100644
--- a/vendor/golang.org/x/sys/unix/asm_darwin_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_386.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s b/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
index 6321421f2..f2397fde5 100644
--- a/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_arm.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm.s
index 333242d50..c9e6b6fc8 100644
--- a/vendor/golang.org/x/sys/unix/asm_darwin_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
// +build arm,darwin
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
index 97e017437..89843f8f4 100644
--- a/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
// +build arm64,darwin
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
index 603dd5728..27674e1ca 100644
--- a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_386.s b/vendor/golang.org/x/sys/unix/asm_freebsd_386.s
index c9a0a2601..49f0ac236 100644
--- a/vendor/golang.org/x/sys/unix/asm_freebsd_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_386.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
index 35172477c..f2dfc57b8 100644
--- a/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
index 9227c875b..6d740db2c 100644
--- a/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
index d9318cbf0..a8f5a29b3 100644
--- a/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s
index 448bebbb5..0655ecbfb 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_386.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
index c6468a958..bc3fb6ac3 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
index cf0f3575c..55b13c7ba 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
index afe6fdf6b..22a83d8e3 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
@@ -4,7 +4,7 @@
// +build linux
// +build arm64
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
index ab9d63831..dc222b90c 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
@@ -4,7 +4,7 @@
// +build linux
// +build mips64 mips64le
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
index 99e539904..d333f13cf 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
@@ -4,7 +4,7 @@
// +build linux
// +build mips mipsle
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
index 88f712557..459a629c2 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
@@ -4,7 +4,7 @@
// +build linux
// +build ppc64 ppc64le
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
index 3cfefed2e..04d38497c 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build riscv64,!gccgo
+// +build riscv64,gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
index a5a863c6b..cc303989e 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
@@ -4,7 +4,7 @@
// +build s390x
// +build linux
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_386.s b/vendor/golang.org/x/sys/unix/asm_netbsd_386.s
index 48bdcd763..ae7b498d5 100644
--- a/vendor/golang.org/x/sys/unix/asm_netbsd_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_386.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
index 2ede05c72..e57367c17 100644
--- a/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
index e8928571c..d7da175e1 100644
--- a/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
index 6f98ba5a3..e7cbe1904 100644
--- a/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_386.s b/vendor/golang.org/x/sys/unix/asm_openbsd_386.s
index 00576f3c8..2f00b0310 100644
--- a/vendor/golang.org/x/sys/unix/asm_openbsd_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_386.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
index 790ef77f8..07632c99c 100644
--- a/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s b/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
index 469bfa100..73e997320 100644
--- a/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
index 0cedea3d3..c47302aa4 100644
--- a/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
index 567a4763c..47c93fcb6 100644
--- a/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
index ded8260f3..1f2c755a7 100644
--- a/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
+// +build gc
#include "textflag.h"
diff --git a/vendor/golang.org/x/sys/unix/endian_big.go b/vendor/golang.org/x/sys/unix/endian_big.go
index 5e9269063..86781eac2 100644
--- a/vendor/golang.org/x/sys/unix/endian_big.go
+++ b/vendor/golang.org/x/sys/unix/endian_big.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
-// +build ppc64 s390x mips mips64
+// +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64
package unix
diff --git a/vendor/golang.org/x/sys/unix/endian_little.go b/vendor/golang.org/x/sys/unix/endian_little.go
index bcdb5d30e..8822d8541 100644
--- a/vendor/golang.org/x/sys/unix/endian_little.go
+++ b/vendor/golang.org/x/sys/unix/endian_little.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
-// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64
+// +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
package unix
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 0c9a5c44b..c0f9f2d52 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -225,6 +225,7 @@ struct ltchars {
#include <linux/kexec.h>
#include <linux/keyctl.h>
#include <linux/loop.h>
+#include <linux/lwtunnel.h>
#include <linux/magic.h>
#include <linux/memfd.h>
#include <linux/module.h>
@@ -561,6 +562,7 @@ ccflags="$@"
$2 ~ /^CRYPTO_/ ||
$2 ~ /^TIPC_/ ||
$2 ~ /^DEVLINK_/ ||
+ $2 ~ /^LWTUNNEL_IP/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ ||
$2 ~/^PPPIOC/ ||
diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
index 842ab5acd..a4f2944a2 100644
--- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
+++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
@@ -105,6 +105,19 @@ func Pipe(p []int) (err error) {
return
}
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) error {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err := pipe2(&pp, flags)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return err
+}
+
//sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error)
func Pread(fd int, p []byte, offset int64) (n int, err error) {
return extpread(fd, p, 0, offset)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index 84a9e5277..28be1306e 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -641,6 +641,36 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
}
+// SockaddrCANJ1939 implements the Sockaddr interface for AF_CAN using J1939
+// protocol (https://en.wikipedia.org/wiki/SAE_J1939). For more information
+// on the purposes of the fields, check the official linux kernel documentation
+// available here: https://www.kernel.org/doc/Documentation/networking/j1939.rst
+type SockaddrCANJ1939 struct {
+ Ifindex int
+ Name uint64
+ PGN uint32
+ Addr uint8
+ raw RawSockaddrCAN
+}
+
+func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_CAN
+ sa.raw.Ifindex = int32(sa.Ifindex)
+ n := (*[8]byte)(unsafe.Pointer(&sa.Name))
+ for i := 0; i < 8; i++ {
+ sa.raw.Addr[i] = n[i]
+ }
+ p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
+ for i := 0; i < 4; i++ {
+ sa.raw.Addr[i+8] = p[i]
+ }
+ sa.raw.Addr[12] = sa.Addr
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
+}
+
// SockaddrALG implements the Sockaddr interface for AF_ALG type sockets.
// SockaddrALG enables userspace access to the Linux kernel's cryptography
// subsystem. The Type and Name fields specify which type of hash or cipher
@@ -952,6 +982,10 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil
}
+var socketProtocol = func(fd int) (int, error) {
+ return GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+}
+
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
@@ -1002,7 +1036,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
return sa, nil
case AF_INET:
- proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+ proto, err := socketProtocol(fd)
if err != nil {
return nil, err
}
@@ -1028,7 +1062,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
}
case AF_INET6:
- proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+ proto, err := socketProtocol(fd)
if err != nil {
return nil, err
}
@@ -1063,7 +1097,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
}
return sa, nil
case AF_BLUETOOTH:
- proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+ proto, err := socketProtocol(fd)
if err != nil {
return nil, err
}
@@ -1150,20 +1184,43 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
return sa, nil
case AF_CAN:
- pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa))
- sa := &SockaddrCAN{
- Ifindex: int(pp.Ifindex),
- }
- rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
- for i := 0; i < 4; i++ {
- rx[i] = pp.Addr[i]
- }
- tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
- for i := 0; i < 4; i++ {
- tx[i] = pp.Addr[i+4]
+ proto, err := socketProtocol(fd)
+ if err != nil {
+ return nil, err
}
- return sa, nil
+ pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa))
+
+ switch proto {
+ case CAN_J1939:
+ sa := &SockaddrCANJ1939{
+ Ifindex: int(pp.Ifindex),
+ }
+ name := (*[8]byte)(unsafe.Pointer(&sa.Name))
+ for i := 0; i < 8; i++ {
+ name[i] = pp.Addr[i]
+ }
+ pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
+ for i := 0; i < 4; i++ {
+ pgn[i] = pp.Addr[i+8]
+ }
+ addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
+ addr[0] = pp.Addr[12]
+ return sa, nil
+ default:
+ sa := &SockaddrCAN{
+ Ifindex: int(pp.Ifindex),
+ }
+ rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
+ for i := 0; i < 4; i++ {
+ rx[i] = pp.Addr[i]
+ }
+ tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
+ for i := 0; i < 4; i++ {
+ tx[i] = pp.Addr[i+4]
+ }
+ return sa, nil
+ }
}
return nil, EAFNOSUPPORT
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go
index 21a4946ba..baa771f8a 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build amd64,linux
-// +build !gccgo
+// +build gc
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc.go
index c26e6ec23..9edf3961b 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_gc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux,!gccgo
+// +build linux,gc
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
index 070bd3899..90e33d8cf 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux,!gccgo,386
+// +build linux,gc,386
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go
index 8c514c95e..1a97baae7 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build arm,!gccgo,linux
+// +build arm,gc,linux
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
index 1c70d1b69..87bd161ce 100644
--- a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-// +build !gccgo,!ppc64le,!ppc64
+// +build gc,!ppc64le,!ppc64
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
index 86dc765ab..d36216c3c 100644
--- a/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
@@ -4,7 +4,7 @@
// +build linux
// +build ppc64le ppc64
-// +build !gccgo
+// +build gc
package unix
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index 2069fb861..b46110354 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -1217,6 +1217,12 @@ const (
LOOP_SET_STATUS_SETTABLE_FLAGS = 0xc
LO_KEY_SIZE = 0x20
LO_NAME_SIZE = 0x40
+ LWTUNNEL_IP6_MAX = 0x8
+ LWTUNNEL_IP_MAX = 0x8
+ LWTUNNEL_IP_OPTS_MAX = 0x3
+ LWTUNNEL_IP_OPT_ERSPAN_MAX = 0x4
+ LWTUNNEL_IP_OPT_GENEVE_MAX = 0x3
+ LWTUNNEL_IP_OPT_VXLAN_MAX = 0x1
MADV_COLD = 0x14
MADV_DODUMP = 0x11
MADV_DOFORK = 0xb
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go
index 4b3a8ad7b..0550da06d 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go
@@ -2,7 +2,7 @@
// Code generated by the command above; see README.md. DO NOT EDIT.
// +build aix,ppc64
-// +build !gccgo
+// +build gc
package unix
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
index aebfe511a..1aaccd361 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
@@ -362,6 +362,16 @@ func pipe() (r int, w int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func pipe2(p *[2]_C_int, flags int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go
index 830fbb35c..725b4bee2 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go
@@ -269,6 +269,7 @@ const (
SizeofSockaddrDatalink = 0x14
SizeofSockaddrCtl = 0x20
SizeofLinger = 0x8
+ SizeofIovec = 0x8
SizeofIPMreq = 0x8
SizeofIPv6Mreq = 0x14
SizeofMsghdr = 0x1c
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
index e53a7c49f..080ffce32 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
@@ -274,6 +274,7 @@ const (
SizeofSockaddrDatalink = 0x14
SizeofSockaddrCtl = 0x20
SizeofLinger = 0x8
+ SizeofIovec = 0x10
SizeofIPMreq = 0x8
SizeofIPv6Mreq = 0x14
SizeofMsghdr = 0x30
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go
index 98be973ef..f2a77bc4e 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go
@@ -269,6 +269,7 @@ const (
SizeofSockaddrDatalink = 0x14
SizeofSockaddrCtl = 0x20
SizeofLinger = 0x8
+ SizeofIovec = 0x8
SizeofIPMreq = 0x8
SizeofIPv6Mreq = 0x14
SizeofMsghdr = 0x1c
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
index ddae5afe1..c9492428b 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
@@ -274,6 +274,7 @@ const (
SizeofSockaddrDatalink = 0x14
SizeofSockaddrCtl = 0x20
SizeofLinger = 0x8
+ SizeofIovec = 0x10
SizeofIPMreq = 0x8
SizeofIPv6Mreq = 0x14
SizeofMsghdr = 0x30
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index a96ad4c29..504ef131f 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -2981,3 +2981,21 @@ type PPSKTime struct {
Nsec int32
Flags uint32
}
+
+const (
+ LWTUNNEL_ENCAP_NONE = 0x0
+ LWTUNNEL_ENCAP_MPLS = 0x1
+ LWTUNNEL_ENCAP_IP = 0x2
+ LWTUNNEL_ENCAP_ILA = 0x3
+ LWTUNNEL_ENCAP_IP6 = 0x4
+ LWTUNNEL_ENCAP_SEG6 = 0x5
+ LWTUNNEL_ENCAP_BPF = 0x6
+ LWTUNNEL_ENCAP_SEG6_LOCAL = 0x7
+ LWTUNNEL_ENCAP_RPL = 0x8
+ LWTUNNEL_ENCAP_MAX = 0x8
+
+ MPLS_IPTUNNEL_UNSPEC = 0x0
+ MPLS_IPTUNNEL_DST = 0x1
+ MPLS_IPTUNNEL_TTL = 0x2
+ MPLS_IPTUNNEL_MAX = 0x2
+)
diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go
index 82076fb74..115341fba 100644
--- a/vendor/golang.org/x/sys/windows/dll_windows.go
+++ b/vendor/golang.org/x/sys/windows/dll_windows.go
@@ -32,6 +32,8 @@ type DLLError struct {
func (e *DLLError) Error() string { return e.Msg }
+func (e *DLLError) Unwrap() error { return e.Err }
+
// A DLL implements access to a single DLL.
type DLL struct {
Name string
@@ -389,7 +391,6 @@ func loadLibraryEx(name string, system bool) (*DLL, error) {
var flags uintptr
if system {
if canDoSearchSystem32() {
- const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
} else if isBaseName(name) {
// WindowsXP or unpatched Windows machine
diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go
index 9e3c44a85..69eb462c5 100644
--- a/vendor/golang.org/x/sys/windows/security_windows.go
+++ b/vendor/golang.org/x/sys/windows/security_windows.go
@@ -624,6 +624,7 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
// Authorization Functions
//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
+//sys isTokenRestricted(tokenHandle Token) (ret bool, err error) [!failretval] = advapi32.IsTokenRestricted
//sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
//sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
@@ -837,6 +838,16 @@ func (t Token) IsMember(sid *SID) (bool, error) {
return b != 0, nil
}
+// IsRestricted reports whether the access token t is a restricted token.
+func (t Token) IsRestricted() (isRestricted bool, err error) {
+ isRestricted, err = isTokenRestricted(t)
+ if !isRestricted && err == syscall.EINVAL {
+ // If err is EINVAL, this returned ERROR_SUCCESS indicating a non-restricted token.
+ err = nil
+ }
+ return
+}
+
const (
WTS_CONSOLE_CONNECT = 0x1
WTS_CONSOLE_DISCONNECT = 0x2
@@ -1103,9 +1114,10 @@ type OBJECTS_AND_NAME struct {
}
//sys getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetSecurityInfo
-//sys SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) = advapi32.SetSecurityInfo
+//sys SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetSecurityInfo
//sys getNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetNamedSecurityInfoW
//sys SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetNamedSecurityInfoW
+//sys SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) = advapi32.SetKernelObjectSecurity
//sys buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries uint32, accessEntries *EXPLICIT_ACCESS, countAuditEntries uint32, auditEntries *EXPLICIT_ACCESS, oldSecurityDescriptor *SECURITY_DESCRIPTOR, sizeNewSecurityDescriptor *uint32, newSecurityDescriptor **SECURITY_DESCRIPTOR) (ret error) = advapi32.BuildSecurityDescriptorW
//sys initializeSecurityDescriptor(absoluteSD *SECURITY_DESCRIPTOR, revision uint32) (err error) = advapi32.InitializeSecurityDescriptor
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 008ffc11a..c71bad127 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -170,10 +170,13 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
//sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
//sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW
+//sys SetDefaultDllDirectories(directoryFlags uint32) (err error)
+//sys SetDllDirectory(path string) (err error) = kernel32.SetDllDirectoryW
//sys GetVersion() (ver uint32, err error)
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32)
//sys IsWow64Process(handle Handle, isWow64 *bool) (err error) = IsWow64Process
+//sys IsWow64Process2(handle Handle, processMachine *uint16, nativeMachine *uint16) (err error) = IsWow64Process2?
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
@@ -187,6 +190,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys FindClose(handle Handle) (err error)
//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
//sys GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte, outBufferLen uint32) (err error)
+//sys SetFileInformationByHandle(handle Handle, class uint32, inBuffer *byte, inBufferLen uint32) (err error)
//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
@@ -243,6 +247,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
+//sys GetFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW
//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
//sys UnmapViewOfFile(addr uintptr) (err error)
@@ -255,7 +260,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
-//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
+//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) = crypt32.CertOpenStore
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
@@ -351,7 +356,6 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
-//sys GetFinalPathNameByHandleW(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW
// Process Status API (PSAPI)
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index da1652e74..265d797ca 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -1772,3 +1772,51 @@ const (
MUI_LANGUAGE_INSTALLED = 0x20
MUI_LANGUAGE_LICENSED = 0x40
)
+
+// FILE_INFO_BY_HANDLE_CLASS constants for SetFileInformationByHandle/GetFileInformationByHandleEx
+const (
+ FileBasicInfo = 0
+ FileStandardInfo = 1
+ FileNameInfo = 2
+ FileRenameInfo = 3
+ FileDispositionInfo = 4
+ FileAllocationInfo = 5
+ FileEndOfFileInfo = 6
+ FileStreamInfo = 7
+ FileCompressionInfo = 8
+ FileAttributeTagInfo = 9
+ FileIdBothDirectoryInfo = 10
+ FileIdBothDirectoryRestartInfo = 11
+ FileIoPriorityHintInfo = 12
+ FileRemoteProtocolInfo = 13
+ FileFullDirectoryInfo = 14
+ FileFullDirectoryRestartInfo = 15
+ FileStorageInfo = 16
+ FileAlignmentInfo = 17
+ FileIdInfo = 18
+ FileIdExtdDirectoryInfo = 19
+ FileIdExtdDirectoryRestartInfo = 20
+ FileDispositionInfoEx = 21
+ FileRenameInfoEx = 22
+ FileCaseSensitiveInfo = 23
+ FileNormalizedNameInfo = 24
+)
+
+// LoadLibrary flags for determining from where to search for a DLL
+const (
+ DONT_RESOLVE_DLL_REFERENCES = 0x1
+ LOAD_LIBRARY_AS_DATAFILE = 0x2
+ LOAD_WITH_ALTERED_SEARCH_PATH = 0x8
+ LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x10
+ LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x20
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x40
+ LOAD_LIBRARY_REQUIRE_SIGNED_TARGET = 0x80
+ LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100
+ LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x200
+ LOAD_LIBRARY_SEARCH_USER_DIRS = 0x400
+ LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x800
+ LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000
+ LOAD_LIBRARY_SAFE_CURRENT_DIRS = 0x00002000
+ LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER = 0x00004000
+ LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY = 0x00008000
+)
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index d400c3512..03e9f182e 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -95,6 +95,7 @@ var (
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procInitializeSecurityDescriptor = modadvapi32.NewProc("InitializeSecurityDescriptor")
procInitiateSystemShutdownExW = modadvapi32.NewProc("InitiateSystemShutdownExW")
+ procIsTokenRestricted = modadvapi32.NewProc("IsTokenRestricted")
procIsValidSecurityDescriptor = modadvapi32.NewProc("IsValidSecurityDescriptor")
procIsValidSid = modadvapi32.NewProc("IsValidSid")
procIsWellKnownSid = modadvapi32.NewProc("IsWellKnownSid")
@@ -122,6 +123,7 @@ var (
procReportEventW = modadvapi32.NewProc("ReportEventW")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
+ procSetKernelObjectSecurity = modadvapi32.NewProc("SetKernelObjectSecurity")
procSetNamedSecurityInfoW = modadvapi32.NewProc("SetNamedSecurityInfoW")
procSetSecurityDescriptorControl = modadvapi32.NewProc("SetSecurityDescriptorControl")
procSetSecurityDescriptorDacl = modadvapi32.NewProc("SetSecurityDescriptorDacl")
@@ -248,6 +250,7 @@ var (
procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW")
procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW")
procIsWow64Process = modkernel32.NewProc("IsWow64Process")
+ procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
procLocalFree = modkernel32.NewProc("LocalFree")
@@ -277,12 +280,15 @@ var (
procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition")
procSetConsoleMode = modkernel32.NewProc("SetConsoleMode")
procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
+ procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent")
procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
+ procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procSetFilePointer = modkernel32.NewProc("SetFilePointer")
procSetFileTime = modkernel32.NewProc("SetFileTime")
procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
@@ -753,6 +759,15 @@ func InitiateSystemShutdownEx(machineName *uint16, message *uint16, timeout uint
return
}
+func isTokenRestricted(tokenHandle Token) (ret bool, err error) {
+ r0, _, e1 := syscall.Syscall(procIsTokenRestricted.Addr(), 1, uintptr(tokenHandle), 0, 0)
+ ret = r0 != 0
+ if !ret {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func isValidSecurityDescriptor(sd *SECURITY_DESCRIPTOR) (isValid bool) {
r0, _, _ := syscall.Syscall(procIsValidSecurityDescriptor.Addr(), 1, uintptr(unsafe.Pointer(sd)), 0, 0)
isValid = r0 != 0
@@ -970,6 +985,14 @@ func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCE
return
}
+func SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetKernelObjectSecurity.Addr(), 3, uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor)))
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) {
var _p0 *uint16
_p0, ret = syscall.UTF16PtrFromString(objectName)
@@ -1056,8 +1079,11 @@ func setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl *
return
}
-func SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) {
- syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
+func SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) {
+ r0, _, _ := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
+ if r0 != 0 {
+ ret = syscall.Errno(r0)
+ }
return
}
@@ -1167,7 +1193,7 @@ func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, a
func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
handle = Handle(r0)
- if handle == InvalidHandle {
+ if handle == 0 {
err = errnoErr(e1)
}
return
@@ -1727,7 +1753,7 @@ func GetFileType(filehandle Handle) (n uint32, err error) {
return
}
-func GetFinalPathNameByHandleW(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) {
+func GetFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) {
r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0)
n = uint32(r0)
if n == 0 {
@@ -2055,6 +2081,18 @@ func IsWow64Process(handle Handle, isWow64 *bool) (err error) {
return
}
+func IsWow64Process2(handle Handle, processMachine *uint16, nativeMachine *uint16) (err error) {
+ err = procIsWow64Process2.Find()
+ if err != nil {
+ return
+ }
+ r1, _, e1 := syscall.Syscall(procIsWow64Process2.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(processMachine)), uintptr(unsafe.Pointer(nativeMachine)))
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(libname)
@@ -2340,6 +2378,31 @@ func SetCurrentDirectory(path *uint16) (err error) {
return
}
+func SetDefaultDllDirectories(directoryFlags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetDefaultDllDirectories.Addr(), 1, uintptr(directoryFlags), 0, 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func SetDllDirectory(path string) (err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(path)
+ if err != nil {
+ return
+ }
+ return _SetDllDirectory(_p0)
+}
+
+func _SetDllDirectory(path *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetDllDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func SetEndOfFile(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
@@ -2386,6 +2449,14 @@ func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error)
return
}
+func SetFileInformationByHandle(handle Handle, class uint32, inBuffer *byte, inBufferLen uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), 0, 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) {
r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
newlowoffset = uint32(r0)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 422a6d88d..39771fbe8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -3,13 +3,15 @@ github.com/Azure/go-ansiterm
github.com/Azure/go-ansiterm/winterm
# github.com/BurntSushi/toml v0.3.1
github.com/BurntSushi/toml
-# github.com/Microsoft/go-winio v0.4.15
+# github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331
github.com/Microsoft/go-winio
github.com/Microsoft/go-winio/backuptar
github.com/Microsoft/go-winio/pkg/guid
+github.com/Microsoft/go-winio/pkg/security
github.com/Microsoft/go-winio/vhd
-# github.com/Microsoft/hcsshim v0.8.9
+# github.com/Microsoft/hcsshim v0.8.14
github.com/Microsoft/hcsshim
+github.com/Microsoft/hcsshim/computestorage
github.com/Microsoft/hcsshim/internal/cow
github.com/Microsoft/hcsshim/internal/hcs
github.com/Microsoft/hcsshim/internal/hcserror
@@ -26,6 +28,7 @@ github.com/Microsoft/hcsshim/internal/schema2
github.com/Microsoft/hcsshim/internal/timeout
github.com/Microsoft/hcsshim/internal/vmcompute
github.com/Microsoft/hcsshim/internal/wclayer
+github.com/Microsoft/hcsshim/internal/winapi
github.com/Microsoft/hcsshim/osversion
# github.com/VividCortex/ewma v1.1.1
github.com/VividCortex/ewma
@@ -42,7 +45,7 @@ github.com/checkpoint-restore/go-criu
github.com/checkpoint-restore/go-criu/rpc
# github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/chzyer/readline
-# github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f
+# github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59
github.com/containerd/cgroups/stats/v1
# github.com/containerd/containerd v1.4.1
github.com/containerd/containerd/errdefs
@@ -60,14 +63,14 @@ github.com/containernetworking/cni/pkg/types/020
github.com/containernetworking/cni/pkg/types/current
github.com/containernetworking/cni/pkg/utils
github.com/containernetworking/cni/pkg/version
-# github.com/containernetworking/plugins v0.8.7
+# github.com/containernetworking/plugins v0.9.0
github.com/containernetworking/plugins/pkg/ip
github.com/containernetworking/plugins/pkg/ns
github.com/containernetworking/plugins/pkg/utils/hwaddr
github.com/containernetworking/plugins/pkg/utils/sysctl
github.com/containernetworking/plugins/plugins/ipam/host-local/backend
github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator
-# github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c
+# github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c
github.com/containers/buildah
github.com/containers/buildah/bind
github.com/containers/buildah/chroot
@@ -86,7 +89,7 @@ github.com/containers/buildah/pkg/parse
github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/util
-# github.com/containers/common v0.31.0
+# github.com/containers/common v0.31.2
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/apparmor/internal/supported
github.com/containers/common/pkg/auth
@@ -160,7 +163,7 @@ github.com/containers/ocicrypt/keywrap/pgp
github.com/containers/ocicrypt/keywrap/pkcs7
github.com/containers/ocicrypt/spec
github.com/containers/ocicrypt/utils
-# github.com/containers/psgo v1.5.1
+# github.com/containers/psgo v1.5.2
github.com/containers/psgo
github.com/containers/psgo/internal/capabilities
github.com/containers/psgo/internal/cgroups
@@ -168,7 +171,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.24.1
+# github.com/containers/storage v1.24.4
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -315,7 +318,7 @@ github.com/golang/protobuf/ptypes/timestamp
github.com/google/gofuzz
# github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/google/shlex
-# github.com/google/uuid v1.1.2
+# github.com/google/uuid v1.1.3
github.com/google/uuid
# github.com/gorilla/mux v1.8.0
github.com/gorilla/mux
@@ -344,7 +347,7 @@ github.com/json-iterator/go
# github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a
github.com/juju/ansiterm
github.com/juju/ansiterm/tabwriter
-# github.com/klauspost/compress v1.11.3
+# github.com/klauspost/compress v1.11.4
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
@@ -459,7 +462,7 @@ github.com/opencontainers/runtime-tools/generate
github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/specerror
github.com/opencontainers/runtime-tools/validate
-# github.com/opencontainers/selinux v1.7.0
+# github.com/opencontainers/selinux v1.8.0
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
@@ -563,10 +566,10 @@ github.com/vbauerster/mpb/v5
github.com/vbauerster/mpb/v5/cwriter
github.com/vbauerster/mpb/v5/decor
github.com/vbauerster/mpb/v5/internal
-# github.com/vishvananda/netlink v1.1.0
+# github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852
github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
-# github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
+# github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae
github.com/vishvananda/netns
# github.com/willf/bitset v1.1.11
github.com/willf/bitset
@@ -627,7 +630,7 @@ golang.org/x/oauth2/internal
# golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.0.0-20201112073958-5cba982894dd
+# golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3
golang.org/x/sys/cpu
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix
@@ -719,7 +722,7 @@ gopkg.in/yaml.v3
# k8s.io/api v0.0.0-20190620084959-7cf5895f2711
k8s.io/api/apps/v1
k8s.io/api/core/v1
-# k8s.io/apimachinery v0.20.0
+# k8s.io/apimachinery v0.20.1
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1