aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml30
-rw-r--r--.gitignore1
-rwxr-xr-xAPI.md37
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--Dockerfile1
-rw-r--r--Dockerfile.centos4
-rw-r--r--Dockerfile.fedora4
-rw-r--r--Makefile7
-rw-r--r--README.md19
-rw-r--r--RELEASE_NOTES.md20
-rw-r--r--changelog.txt110
-rw-r--r--cmd/podman/cliconfig/config.go2
-rw-r--r--cmd/podman/cp.go4
-rw-r--r--cmd/podman/import.go5
-rw-r--r--cmd/podman/main.go20
-rw-r--r--cmd/podman/main_remote.go30
-rw-r--r--cmd/podman/network_create.go6
-rw-r--r--cmd/podman/remoteclientconfig/config.go10
-rw-r--r--cmd/podman/remoteclientconfig/configfile_test.go6
-rw-r--r--cmd/podman/varlink/io.podman.varlink37
-rw-r--r--contrib/cirrus/README.md45
-rwxr-xr-xcontrib/cirrus/build_release.sh24
-rwxr-xr-xcontrib/cirrus/check_image.sh5
-rw-r--r--contrib/cirrus/lib.sh2
-rwxr-xr-xcontrib/cirrus/logcollector.sh37
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh6
-rw-r--r--contrib/cirrus/packer/ubuntu_setup.sh12
-rwxr-xr-xcontrib/cirrus/upload_release_archive.sh62
-rw-r--r--contrib/perftest/main.go7
-rw-r--r--contrib/spec/podman.spec.in2
-rwxr-xr-xcontrib/upldrel/entrypoint.sh57
-rw-r--r--docs/podman-cp.1.md2
-rw-r--r--docs/podman-import.1.md20
-rw-r--r--docs/podman-remote.conf.5.md6
-rw-r--r--docs/tutorials/README.md14
-rw-r--r--docs/tutorials/podman-derivative-api.md46
-rw-r--r--docs/tutorials/podman_tutorial.md2
-rw-r--r--go.mod21
-rw-r--r--go.sum36
-rwxr-xr-xhack/get_release_info.sh2
-rwxr-xr-xhack/install_catatonit.sh19
-rw-r--r--install.md1
-rw-r--r--libpod/container_internal.go22
-rw-r--r--libpod/container_internal_linux.go21
-rw-r--r--libpod/container_internal_unsupported.go4
-rw-r--r--libpod/image/image.go4
-rw-r--r--libpod/image/image_test.go8
-rw-r--r--libpod/info.go10
-rw-r--r--libpod/networking_linux.go68
-rw-r--r--libpod/oci_internal_linux.go15
-rw-r--r--libpod/options.go20
-rw-r--r--libpod/runtime.go7
-rw-r--r--libpod/runtime_pod_infra_linux.go4
-rw-r--r--pkg/adapter/client.go2
-rw-r--r--pkg/adapter/client_unix.go11
-rw-r--r--pkg/adapter/client_windows.go15
-rw-r--r--pkg/adapter/containers_remote.go7
-rw-r--r--pkg/adapter/pods.go7
-rw-r--r--pkg/netns/netns_linux.go46
-rw-r--r--pkg/rootless/rootless_linux.go2
-rw-r--r--pkg/spec/createconfig.go2
-rw-r--r--pkg/spec/spec.go3
-rw-r--r--pkg/spec/storage.go3
-rw-r--r--pkg/util/utils.go85
-rw-r--r--pkg/util/utils_test.go71
-rw-r--r--pkg/varlinkapi/attach.go4
-rw-r--r--rootless.md1
-rw-r--r--test/e2e/common_test.go12
-rw-r--r--test/e2e/cp_test.go51
-rw-r--r--test/e2e/import_test.go42
-rw-r--r--test/e2e/libpod_suite_remoteclient_test.go4
-rw-r--r--test/e2e/libpod_suite_test.go9
-rw-r--r--test/e2e/mount_test.go120
-rw-r--r--test/e2e/network_create_test.go6
-rw-r--r--test/e2e/run_volume_test.go10
-rw-r--r--test/e2e/start_test.go17
-rw-r--r--test/system/005-info.bats2
-rw-r--r--test/system/030-run.bats21
-rw-r--r--test/system/055-rm.bats2
-rw-r--r--test/system/065-cp.bats15
-rw-r--r--test/system/400-unprivileged-access.bats2
-rw-r--r--test/utils/utils.go34
-rw-r--r--test/utils/utils_suite_test.go2
-rw-r--r--vendor/github.com/containernetworking/plugins/pkg/ip/link_linux.go33
-rw-r--r--vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go13
-rw-r--r--vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go1
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go1
-rw-r--r--vendor/github.com/containers/storage/store.go13
-rw-r--r--vendor/github.com/docker/docker-credential-helpers/credentials/version.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/CHANGELOG.md26
-rw-r--r--vendor/github.com/onsi/ginkgo/config/config.go10
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go5
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/convert/import.go3
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/convert/package_rewriter.go1
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/convert/testfile_rewriter.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/interrupthandler/interrupt_handler.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/main.go12
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/suite_runner.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go6
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/watch/dependencies.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/watch/package_hash.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo_dsl.go4
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/codelocation/code_location.go20
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go12
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/server.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/spec/spec.go10
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/spec/specs.go4
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/reporters/default_reporter.go3
-rw-r--r--vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go25
-rw-r--r--vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go9
-rw-r--r--vendor/github.com/onsi/ginkgo/types/types.go2
-rw-r--r--vendor/github.com/onsi/gomega/.travis.yml1
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md32
-rw-r--r--vendor/github.com/onsi/gomega/format/format.go37
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/say_matcher.go4
-rw-r--r--vendor/github.com/onsi/gomega/gexec/build.go4
-rw-r--r--vendor/github.com/onsi/gomega/gexec/exit_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/gexec/prefixed_writer.go4
-rw-r--r--vendor/github.com/onsi/gomega/gexec/session.go3
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go10
-rw-r--r--vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers.go16
-rw-r--r--vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_directory.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go57
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_false_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_identical_to.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_true_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/consist_of.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go22
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/receive_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go3
-rw-r--r--vendor/github.com/onsi/gomega/matchers/type_support.go3
-rw-r--r--vendor/github.com/spf13/pflag/.travis.yml7
-rw-r--r--vendor/github.com/spf13/pflag/README.md4
-rw-r--r--vendor/github.com/spf13/pflag/bool_slice.go38
-rw-r--r--vendor/github.com/spf13/pflag/count.go4
-rw-r--r--vendor/github.com/spf13/pflag/duration_slice.go38
-rw-r--r--vendor/github.com/spf13/pflag/flag.go16
-rw-r--r--vendor/github.com/spf13/pflag/float32_slice.go174
-rw-r--r--vendor/github.com/spf13/pflag/float64_slice.go166
-rw-r--r--vendor/github.com/spf13/pflag/go.mod3
-rw-r--r--vendor/github.com/spf13/pflag/go.sum0
-rw-r--r--vendor/github.com/spf13/pflag/int32_slice.go174
-rw-r--r--vendor/github.com/spf13/pflag/int64_slice.go166
-rw-r--r--vendor/github.com/spf13/pflag/int_slice.go30
-rw-r--r--vendor/github.com/spf13/pflag/ip_slice.go40
-rw-r--r--vendor/github.com/spf13/pflag/string_array.go26
-rw-r--r--vendor/github.com/spf13/pflag/string_slice.go22
-rw-r--r--vendor/github.com/spf13/pflag/string_to_int64.go149
-rw-r--r--vendor/github.com/spf13/pflag/uint_slice.go42
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_format.go82
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_forward.go164
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_order.go309
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertions.go96
-rw-r--r--vendor/github.com/stretchr/testify/require/require.go716
-rw-r--r--vendor/github.com/stretchr/testify/require/require.go.tmpl2
-rw-r--r--vendor/github.com/stretchr/testify/require/require_forward.go164
-rw-r--r--vendor/github.com/uber/jaeger-client-go/.travis.yml8
-rw-r--r--vendor/github.com/uber/jaeger-client-go/CHANGELOG.md31
-rw-r--r--vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md10
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Gopkg.lock87
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Gopkg.toml4
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Makefile28
-rw-r--r--vendor/github.com/uber/jaeger-client-go/README.md33
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/config.go8
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/config_env.go3
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/options.go35
-rw-r--r--vendor/github.com/uber/jaeger-client-go/constants.go20
-rw-r--r--vendor/github.com/uber/jaeger-client-go/context.go10
-rw-r--r--vendor/github.com/uber/jaeger-client-go/glide.lock46
-rw-r--r--vendor/github.com/uber/jaeger-client-go/glide.yaml9
-rw-r--r--vendor/github.com/uber/jaeger-client-go/reporter.go18
-rw-r--r--vendor/github.com/uber/jaeger-client-go/sampler.go8
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span.go87
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span_allocator.go56
-rw-r--r--vendor/github.com/uber/jaeger-client-go/tracer.go164
-rw-r--r--vendor/github.com/uber/jaeger-client-go/tracer_options.go12
-rw-r--r--vendor/gopkg.in/yaml.v2/decode.go13
-rw-r--r--vendor/gopkg.in/yaml.v2/resolve.go2
-rw-r--r--vendor/modules.txt18
-rw-r--r--version/version.go2
201 files changed, 4517 insertions, 881 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 241ac4b2b..7f295e22e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -30,7 +30,7 @@ env:
####
#### Cache-image names to test with (double-quotes around names are critical)
###
- _BUILT_IMAGE_SUFFIX: "libpod-5664838702858240"
+ _BUILT_IMAGE_SUFFIX: "libpod-5816955207942144"
FEDORA_CACHE_IMAGE_NAME: "fedora-30-${_BUILT_IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-${_BUILT_IMAGE_SUFFIX}"
SPECIAL_FEDORA_CACHE_IMAGE_NAME: "xfedora-30-${_BUILT_IMAGE_SUFFIX}"
@@ -117,6 +117,12 @@ gating_task:
- '/usr/local/bin/entrypoint.sh podman-remote-darwin |& ${TIMESTAMP}'
- '/usr/local/bin/entrypoint.sh podman-remote-windows |& ${TIMESTAMP}'
+ # Verify some aspects of ci/related scripts
+ ci_script:
+ - '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/lib.sh.t |& ${TIMESTAMP}'
+ - '/usr/local/bin/entrypoint.sh -C ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/packer test'
+ - '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/cirrus_yaml_test.py |& ${TIMESTAMP}'
+
# Verify expected bash environment (-o pipefail)
pipefail_enabledscript: 'if /bin/false | /bin/true; then echo "pipefail fault" && exit 72; fi'
@@ -289,7 +295,7 @@ meta_task:
image_prune_task:
# Do not run this frequently
- only_if: $CIRRUS_BRANCH == 'master'
+ only_if: $CIRRUS_BRANCH == $DEST_BRANCH
depends_on:
- "meta"
@@ -345,12 +351,19 @@ testing_task:
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}'
+ # For PRs this confirms uploading releases after merge, is functional.
upload_release_archive_script: '$SCRIPT_BASE/upload_release_archive.sh |& ${TIMESTAMP}'
+ # When examining a particular run, provide convenient access to release files.
+ tar_artifacts:
+ path: "*.tar.gz"
+ type: "application/x-tar"
+
on_failure:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
always: &standardlogs
+ package_versions_script: '$SCRIPT_BASE/logcollector.sh packages'
ginkgo_node_logs_script: '$SCRIPT_BASE/logcollector.sh ginkgo'
df_script: '$SCRIPT_BASE/logcollector.sh df'
audit_log_script: '$SCRIPT_BASE/logcollector.sh audit'
@@ -474,6 +487,15 @@ special_testing_cross_task:
on_failure:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
+ # When examining a particular run, provide convenient access to release files.
+ zip_artifacts:
+ path: "*.zip"
+ type: "application/zip"
+
+ msi_artifacts:
+ path: "*.msi"
+ type: "application/octet-stream"
+
special_testing_cgroupv2_task:
@@ -616,9 +638,7 @@ verify_test_built_images_task:
integration_test_script: >-
[[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \
$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}
- build_release_script: >-
- [[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \
- $SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}
+ build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}'
system_test_script: >-
[[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \
$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}
diff --git a/.gitignore b/.gitignore
index d3e56ecdf..598384582 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@
/test/bin2img/bin2img
/test/checkseccomp/checkseccomp
/test/copyimg/copyimg
+/test/goecho/goecho
/build/
.nfs*
.ropeproject
diff --git a/API.md b/API.md
index 7d11fdd3f..a9905c940 100755
--- a/API.md
+++ b/API.md
@@ -306,8 +306,43 @@ method AttachControl(name: [string](https://godoc.org/builtin#string)) </div>
method BuildImage(build: [BuildInfo](#BuildInfo)) [MoreResponse](#MoreResponse)</div>
BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the
-'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [MoreResponse](#MoreResponse) structure
+contextDir tarball path, the 'dockerfiles' path, and 'output' option in the BuildInfo structure. The 'output'
+options is the name of the of the resulting build. It will return a [MoreResponse](#MoreResponse) structure
that contains the build logs and resulting image ID.
+#### Example
+~~~
+$ sudo varlink call -m unix:///run/podman/io.podman/io.podman.BuildImage '{"build":{"contextDir":"/tmp/t/context.tar","dockerfiles":["Dockerfile"], "output":"foobar"}}'
+{
+ "image": {
+ "id": "",
+ "logs": [
+ "STEP 1: FROM alpine\n"
+ ]
+ }
+}
+{
+ "image": {
+ "id": "",
+ "logs": [
+ "STEP 2: COMMIT foobar\n"
+ ]
+ }
+}
+{
+ "image": {
+ "id": "",
+ "logs": [
+ "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9\n"
+ ]
+ }
+}
+{
+ "image": {
+ "id": "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9",
+ "logs": []
+ }
+}
+~~~
### <a name="BuildImageHierarchyMap"></a>func BuildImageHierarchyMap
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 07b2b3584..be13b6de3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -347,9 +347,6 @@ tracking system.
There is also a [mailing list](https://lists.podman.io/archives/) at `lists.podman.io`.
You can subscribe by sending a message to `podman@lists.podman.io` with the subject `subscribe`.
-[owners]: https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md#owners
-
-
### Bot Interactions
The primary human-interface is through comments in pull-requests. Some of these are outlined
diff --git a/Dockerfile b/Dockerfile
index 1f51cd874..3c65bf5a8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y \
build-essential \
curl \
e2fslibs-dev \
+ file \
gawk \
gettext \
go-md2man \
diff --git a/Dockerfile.centos b/Dockerfile.centos
index 513c4bdfd..9af7ef7f1 100644
--- a/Dockerfile.centos
+++ b/Dockerfile.centos
@@ -2,9 +2,12 @@ FROM registry.centos.org/centos/centos:7
RUN yum -y install btrfs-progs-devel \
atomic-registries \
+ autoconf \
+ automake \
bzip2 \
device-mapper-devel \
findutils \
+ file \
git \
glibc-static \
glib2-devel \
@@ -15,6 +18,7 @@ RUN yum -y install btrfs-progs-devel \
libassuan-devel \
libseccomp-devel \
libselinux-devel \
+ libtool \
containers-common \
runc \
make \
diff --git a/Dockerfile.fedora b/Dockerfile.fedora
index 9b1568b0b..8769b5c18 100644
--- a/Dockerfile.fedora
+++ b/Dockerfile.fedora
@@ -2,8 +2,11 @@ FROM registry.fedoraproject.org/fedora:30
RUN dnf -y install btrfs-progs-devel \
atomic-registries \
+ autoconf \
+ automake \
bzip2 \
device-mapper-devel \
+ file \
findutils \
git \
glib2-devel \
@@ -15,6 +18,7 @@ RUN dnf -y install btrfs-progs-devel \
libassuan-devel \
libseccomp-devel \
libselinux-devel \
+ libtool \
containers-common \
runc \
make \
diff --git a/Makefile b/Makefile
index 6734ef1b0..97f5d407c 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ export GOPROXY=https://proxy.golang.org
GO ?= go
DESTDIR ?=
-EPOCH_TEST_COMMIT ?= 2366fd7ac621ba15abe559832f024d06b3db3c9b
+EPOCH_TEST_COMMIT ?= 960f07b0f79e6d6f94842fd4892e775c319f0a39
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
@@ -189,7 +189,7 @@ clean: ## Clean artifacts
rm -rf \
.gopathok \
_output \
- release.txt
+ release.txt \
$(wildcard podman-remote*.zip) \
$(wildcard podman*.tar.gz) \
bin \
@@ -245,9 +245,6 @@ localunit: test/goecho/goecho varlink_generate
--covermode atomic \
--tags "$(BUILDTAGS)" \
--succinct
- $(MAKE) -C contrib/cirrus/packer test
- ./contrib/cirrus/lib.sh.t
- ./contrib/cirrus/cirrus_yaml_test.py
ginkgo:
ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/.
diff --git a/README.md b/README.md
index 4cdccd3a9..9bb7403dc 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Libpod provides a library for applications looking to use the Container Pod concept,
popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes.
-* [Latest Version: 1.5.1](https://github.com/containers/libpod/releases/latest)
+* [Latest Version: 1.6.0](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
* [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod)
* Automated continuous release downloads (including remote-client):
@@ -33,6 +33,23 @@ This project tests all builds against each supported version of Fedora, the late
1. Further work on the podman pod command
1. Further improvements on rootless containers
+## Communications
+
+If you think you've identified a security issue in the project, please *DO NOT* report the issue publically 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
+IRC `#podman` channel on `irc.freenode.net`.
+
+For discussions around issues/bugs and features, you can use the GitHub
+[issues](https://github.com/containers/libpod/issues)
+and
+[PRs](https://github.com/containers/libpod/pulls)
+tracking system.
+
+There is also a [mailing list](https://lists.podman.io/archives/) at `lists.podman.io`.
+You can subscribe by sending a message to `podman@lists.podman.io` with the subject `subscribe`.
+
## Rootless
Podman can be easily run as a normal user, without requiring a setuid binary.
When run without root, Podman containers use user namespaces to set root in the container to the user running Podman.
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 5c9c06687..bff9a5f14 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,11 @@
# Release Notes
+## 1.6.1
+### Bugfixes
+- Fixed a bug where rootless Podman on systems using CGroups V2 would not function with the `cgroupfs` CGroups manager
+- Fixed a bug where rootless Podman could not correctly identify the DBus session address, causing containers to fail to start ([#4162](https://github.com/containers/libpod/issues/4162))
+- Fixed a bug where rootless Podman with `slirp4netns` networking would fail to start containers due to mount leaks
+
## 1.6.0
### Features
- The `podman network create`, `podman network rm`, `podman network inspect`, and `podman network ls` commands have been added to manage CNI networks used by Podman
@@ -8,6 +14,7 @@
- The `podman volume rm` and `podman volume inspect` commands can now refer to volumes by an unambiguous partial name, in addition to full name (e.g. `podman volume rm myvol` to remove a volume named `myvolume`) ([#3891](https://github.com/containers/libpod/issues/3891))
- The `podman run` and `podman create` commands now support the `--pull` flag to allow forced re-pulling of images ([#3734](https://github.com/containers/libpod/issues/3734))
- Mounting volumes into a container using `--volume`, `--mount`, and `--tmpfs` now allows the `suid`, `dev`, and `exec` mount options (the inverse of `nosuid`, `nodev`, `noexec`) ([#3819](https://github.com/containers/libpod/issues/3819))
+- Mounting volumes into a container using `--mount` now allows the `relabel=Z` and `relabel=z` options to relabel mounts.
- The `podman push` command now supports the `--digestfile` option to save a file containing the pushed digest
- Pods can now have their hostname set via `podman pod create --hostname` or providing Pod YAML with a hostname set to `podman play kube` ([#3732](https://github.com/containers/libpod/issues/3732))
- The `podman image sign` command now supports the `--cert-dir` flag
@@ -37,12 +44,25 @@
- Fixed a bug where `podman exec` would run as the wrong user when execing into a container was started from an image with Dockerfile `USER` (or a user specified via `podman run --user`) ([#3838](https://github.com/containers/libpod/issues/3838))
- Fixed a bug where images pulled using the `oci:` transport would be improperly named
- Fixed a bug where `podman varlink` would hang when managed by systemd due to SD_NOTIFY support conflicting with Varlink ([#3572](https://github.com/containers/libpod/issues/3572))
+- Fixed a bug where mounts to the same destination would sometimes not trigger a conflict, causing a race as to which was actually mounted
+- Fixed a bug where `podman exec --preserve-fds` caused Podman to hang ([#4020](https://github.com/containers/libpod/issues/4020))
+- Fixed a bug where removing an unmounted container that was unmounted might sometimes not properly clean up the container ([#4033](https://github.com/containers/libpod/issues/4033))
+- Fixed a bug where the Varlink server would freeze when run in a systemd unit file ([#4005](https://github.com/containers/libpod/issues/4005))
+- Fixed a bug where Podman would not properly set the `$HOME` environment variable when the OCI runtime did not set it
+- Fixed a bug where rootless Podman would incorrectly print warning messages when an OCI runtime was not found ([#4012](https://github.com/containers/libpod/issues/4012))
+- Fixed a bug where named volumes would conflict with, instead of overriding, `tmpfs` filesystems added by the `--read-only-tmpfs` flag to `podman create` and `podman run`
+- Fixed a bug where `podman cp` would incorrectly make the target directory when copying to a symlink which pointed to a nonexistent directory ([#3894](https://github.com/containers/libpod/issues/3894))
+- Fixed a bug where remote Podman would incorrectly read `STDIN` when the `-i` flag was not set ([#4095](https://github.com/containers/libpod/issues/4095))
+- Fixed a bug where `podman play kube` would create an empty pod when given an unsupported YAML type ([#4093](https://github.com/containers/libpod/issues/4093))
+- Fixed a bug where `podman import --change` improperly parsed `CMD` ([#4000](https://github.com/containers/libpod/issues/4000))
### Misc
- Significant changes were made to Podman volumes in this release. If you have pre-existing volumes, it is strongly recommended to run `podman system renumber` after upgrading.
- Version 0.8.1 or greater of the CNI Plugins is now required for Podman
- Version 2.0.1 or greater of Conmon is strongly recommended
- Updated vendored Buildah to v1.11.2
+- Updated vendored containers/storage library to v1.13.4
+- Improved error messages when trying to create a pod with no name via `podman play kube`
- Improved error messages when trying to run `podman pause` or `podman stats` on a rootless container on a system without CGroups V2 enabled
- `TMPDIR` has been set to `/var/tmp` by default to better handle large temporary files
- `podman wait` has been optimized to detect stopped containers more rapidly
diff --git a/changelog.txt b/changelog.txt
index c2c2a8ce9..8508d0d1c 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,113 @@
+- Changelog for v1.6.1 (2019-10-02)
+ * Update release notes for v1.6.1
+ * Bump gitvalidation epoch
+ * Bump to v1.6.1-dev
+ * rootless: allow cgroupfs manager on cgroups v2
+ * system tests: reenable skipped tests
+
+- Changelog for v1.6.1-rc1 (2019-10-02)
+ * rootless: set DBUS_SESSION_BUS_ADDRESS if it is not set
+ * install.md: add libbtrfs-dev for Debian build
+ * Bump github.com/onsi/gomega from 1.5.0 to 1.7.0
+ * Cirrus: Show names/versions of critical packages
+ * network: add workaround for slirp4netns --enable-sandbox issue
+ * rootless: do not attempt a CNI refresh
+ * Bump github.com/containernetworking/plugins from 0.8.1 to 0.8.2
+ * network: hide EPERM warning when rootless
+ * networking: fix segfault when slirp4netns is missing
+ * Bump gitvalidation epoch
+ * Bump to v1.6.1-dev
+ * Move derivitive doc so it won't be treated as a manpage
+ * catatonit: clone and build
+ * bump catatonit to v0.1.4
+
+- Changelog for v1.6.0 (2019-09-30)
+ * info: add cgroups2
+ * Finalize release notes for 1.6.0 final
+ * Bump github.com/onsi/ginkgo from 1.8.0 to 1.10.1
+ * Bump github.com/docker/docker-credential-helpers from 0.6.2 to 0.6.3
+ * Bump github.com/stretchr/testify from 1.3.0 to 1.4.0
+ * Bump github.com/uber/jaeger-client-go
+ * Bump github.com/spf13/pflag from 1.0.3 to 1.0.5
+ * update c/storage to v1.13.4
+ * Cirrus: Minor, fix env. var. intention
+ * new examples added updated two examples with supported CMD and ENTRYPOINT syntax.
+ * new testcase for podman import --change added
+ * syntax updated for podman import --change
+ * Correct use of reexec.Init()
+ * Add a missing escape in the Makefile
+ * Change ginkgo Wait() to Eventually() test
+ * Set log-level immediately, before rootless setup
+ * Cirrus: Implement newly built VM images
+ * Add README note about security reporting process.
+ * Cirrus: Disable boottime Ubuntu package update
+ * Move noCache logic lower in stack
+ * cirrus: Add bash-completion support
+ * Add an error for pods without a name
+ * Make links relative in Tutorial README
+ * docs/podman-derivative-api.md: New file
+ * fix cp none exists dest path ends with '/'
+ * Dockerfile.fedora: install packages to build catatonit
+ * README: add Communications section
+ * drop OWNERS link for CONTRIBUTING.md
+ * Bump gitvalidation epoch
+ * Bump to v1.6.0-dev
+ * Handle conflict between volumes and --read-only-tmpfs
+ * Cirrus: Upload windows MSI release file
+ * conditionally send stdin on remote run
+ * Cirrus: VM Image accounting doc update
+ * Force a CNI Delete on refreshing containers
+ * Document the required varlink build args
+ * Update mac_client link
+ * Cirrus: Fail early on CI script unit test
+ * Unconditionally remove conmon files before starting
+
+- Changelog for v1.6.0-rc2 (2019-09-24)
+ * Add release notes for new-in-RC2 changes
+ * system tests: run test: reenable and fix
+ * play kube: Only support pod kind in k8s yaml
+ * runtime: fix logic to disable SDNotify
+ * add list mount tests
+ * Make netns bind mount shared
+ * Add Kata Containers support
+ * rootless: Rearrange setup of rootless containers
+ * Document the 'system' event types for 'podman events'
+ * Cirrus: Add upload_snap to success dependencies
+ * Cirrus: Add snapcraft credentials
+ * Cirrus: Upload snap only on merges to master
+ * Cirrus: Push snap continuously
+ * exec: set HOME also with exec sessions
+ * execuser: look at the source for /etc/{passwd,group} overrides
+ * We need to convert libpod.conf files in user homedir for cgroupv2
+ * Cirrus: Temporarily disable testing on Ubuntu 19
+ * Cirrus: disable Evil Units in base-images
+ * Cirrus: Add latest ubuntu
+ * Cirrus: More podbot/success improvements
+ * Cirrus: Fix success script
+ * Cirrus: Update podbot credentials
+ * container: make sure $HOME is always set
+ * Move rootless and Mac to Tutorials page
+ * fix trivial type for event logger
+ * Support podman-remote help on windows
+ * Clean destination paths during mount generation
+ * tests: use crun package
+ * Add a note on systemd shortcomings in rootless containers
+ * support non-standard ssh port for remote-client
+ * Add links to the Mac tutorial in the main tutorial
+ * Vendor c/storage 1.13.3
+ * System-test: Temporarily disable 030-run
+ * Fix exit code failure
+ * exec: fix --preserve-fds
+ * networking: use --enable-sandbox if available
+ * Add 'relabel' to --mount options
+ * Bump Gitvalidation epoch
+ * Bump to v1.6.0-dev
+ * Unmounting a container that is already unmounted is OK
+ * Check for rootless before checking cgroups version in spec_test.
+ * Skip spec_test for rootless envs without cgroup v2.
+ * fix unit test to use Expect
+ * Cirrus: Prevent resident pollution
+
- Changelog for v1.6.0-rc1 (2019-09-16)
* Fix default to pause in podman cp
* Update release notes for v1.6.0
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index b8796f9b3..5b5225f02 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -42,6 +42,8 @@ type MainFlags struct {
ConnectionName string
RemoteConfigFilePath string
Port int
+ IdentityFile string
+ IgnoreHosts bool
}
type AttachValues struct {
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index 7205f9357..75a23afd6 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -290,7 +290,7 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
}
destdir := destPath
- if !srcfi.IsDir() && !strings.HasSuffix(dest, string(os.PathSeparator)) {
+ if !srcfi.IsDir() {
destdir = filepath.Dir(destPath)
}
_, err = os.Stat(destdir)
@@ -329,7 +329,7 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
destfi, err := os.Stat(destPath)
if err != nil {
- if !os.IsNotExist(err) {
+ if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) {
return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
}
}
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index d49792f27..027fa7299 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -39,7 +39,7 @@ func init() {
importCommand.SetHelpTemplate(HelpTemplate())
importCommand.SetUsageTemplate(UsageTemplate())
flags := importCommand.Flags()
- flags.StringSliceVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
+ flags.StringArrayVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
flags.StringVarP(&importCommand.Message, "message", "m", "", "Set commit message for imported image")
flags.BoolVarP(&importCommand.Quiet, "quiet", "q", false, "Suppress output")
@@ -56,7 +56,6 @@ func importCmd(c *cliconfig.ImportValues) error {
source string
reference string
)
-
args := c.InputArgs
switch len(args) {
case 0:
@@ -81,7 +80,7 @@ func importCmd(c *cliconfig.ImportValues) error {
if runtime.Remote {
quiet = false
}
- iid, err := runtime.Import(getContext(), source, reference, c.StringSlice("change"), c.String("message"), quiet)
+ iid, err := runtime.Import(getContext(), source, reference, importCommand.Change, c.String("message"), quiet)
if err == nil {
fmt.Println(iid)
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 992dbe1d5..344170ddd 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -107,15 +107,6 @@ func before(cmd *cobra.Command, args []string) error {
os.Exit(1)
}
- if err := setupRootless(cmd, args); err != nil {
- return err
- }
-
- // check that global opts input is valid
- if err := checkInput(); err != nil {
- return err
- }
-
// Set log level; if not log-level is provided, default to error
logLevel := MainGlobalOpts.LogLevel
if logLevel == "" {
@@ -130,6 +121,15 @@ func before(cmd *cobra.Command, args []string) error {
return err
}
+ if err := setupRootless(cmd, args); err != nil {
+ return err
+ }
+
+ // check that global opts input is valid
+ if err := checkInput(); err != nil {
+ return err
+ }
+
if err := setRLimits(); err != nil {
return err
}
@@ -149,6 +149,8 @@ func main() {
//cpuProfile := false
if reexec.Init() {
+ // We were invoked with a different argv[0] indicating that we
+ // had a specific job to do as a subprocess, and it's done.
return
}
// Hard code TMPDIR functions to use /var/tmp, if user did not override
diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go
index f617422e6..623f4098e 100644
--- a/cmd/podman/main_remote.go
+++ b/cmd/podman/main_remote.go
@@ -3,9 +3,11 @@
package main
import (
- "github.com/pkg/errors"
+ "os"
"os/user"
+ "strconv"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -13,14 +15,32 @@ const remote = true
func init() {
var username string
- if curruser, err := user.Current(); err == nil {
- username = curruser.Username
+ if username = os.Getenv("PODMAN_USER"); username == "" {
+ if curruser, err := user.Current(); err == nil {
+ username = curruser.Username
+ }
+ }
+ host := os.Getenv("PODMAN_HOST")
+ port := 22
+ if portstr := os.Getenv("PODMAN_PORT"); portstr != "" {
+ if p, err := strconv.Atoi(portstr); err == nil {
+ port = p
+ }
+ }
+ key := os.Getenv("PODMAN_IDENTITY_FILE")
+ ignore := false
+ if ignorestr := os.Getenv("PODMAN_IGNORE_HOSTS"); ignorestr != "" {
+ if b, err := strconv.ParseBool(ignorestr); err == nil {
+ ignore = b
+ }
}
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConnectionName, "connection", "", "remote connection name")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteConfigFilePath, "remote-config-path", "", "alternate path for configuration file")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", username, "username on the remote host")
- rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.Port, "port", 22, "port on remote host")
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host")
+ rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.Port, "port", port, "port on remote host")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", host, "remote host")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.IdentityFile, "identity-file", key, "identity-file")
+ rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.IgnoreHosts, "ignore-hosts", ignore, "ignore hosts")
// TODO maybe we allow the altering of this for bridge connections?
// rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic. Logged to ~/.config/containers/podman.log")
diff --git a/cmd/podman/network_create.go b/cmd/podman/network_create.go
index 378a92568..11f13faad 100644
--- a/cmd/podman/network_create.go
+++ b/cmd/podman/network_create.go
@@ -4,11 +4,12 @@ package main
import (
"fmt"
- "github.com/containers/libpod/pkg/network"
"net"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/network"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -58,6 +59,9 @@ func networkcreateCmd(c *cliconfig.NetworkCreateValues) error {
if len(c.InputArgs) > 1 {
return errors.Errorf("only one network can be created at a time")
}
+ if len(c.InputArgs) > 0 && !libpod.NameRegex.MatchString(c.InputArgs[0]) {
+ return libpod.RegexError
+ }
runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return err
diff --git a/cmd/podman/remoteclientconfig/config.go b/cmd/podman/remoteclientconfig/config.go
index 13880a868..3faa7954a 100644
--- a/cmd/podman/remoteclientconfig/config.go
+++ b/cmd/podman/remoteclientconfig/config.go
@@ -9,10 +9,12 @@ type RemoteConfig struct {
// RemoteConnection describes the attributes of a podman-remote endpoint
type RemoteConnection struct {
- Destination string `toml:"destination"`
- Username string `toml:"username"`
- IsDefault bool `toml:"default"`
- Port int `toml:"port"`
+ Destination string `toml:"destination"`
+ Username string `toml:"username"`
+ IsDefault bool `toml:"default"`
+ Port int `toml:"port"`
+ IdentityFile string `toml:"identity_file"`
+ IgnoreHosts bool `toml:"ignore_hosts"`
}
// GetConfigFilePath is a simple helper to export the configuration file's
diff --git a/cmd/podman/remoteclientconfig/configfile_test.go b/cmd/podman/remoteclientconfig/configfile_test.go
index ea2224ea7..0bcac29a8 100644
--- a/cmd/podman/remoteclientconfig/configfile_test.go
+++ b/cmd/podman/remoteclientconfig/configfile_test.go
@@ -143,7 +143,7 @@ func TestRemoteConfig_GetDefault(t *testing.T) {
wantErr bool
}{
// A good toml should return the connection that is marked isDefault
- {"good", fields{Connections: makeGoodResult().Connections}, &RemoteConnection{"192.168.1.1", "myuser", true, 22}, false},
+ {"good", fields{Connections: makeGoodResult().Connections}, &RemoteConnection{"192.168.1.1", "myuser", true, 22, "", false}, false},
// If nothing is marked as isDefault and there is more than one connection, error should occur
{"nodefault", fields{Connections: noDefault}, nil, true},
// if nothing is marked as isDefault but there is only one connection, the one connection is considered the default
@@ -183,9 +183,9 @@ func TestRemoteConfig_GetRemoteConnection(t *testing.T) {
wantErr bool
}{
// Good connection
- {"goodhomer", fields{Connections: makeGoodResult().Connections}, args{name: "homer"}, &RemoteConnection{"192.168.1.1", "myuser", true, 22}, false},
+ {"goodhomer", fields{Connections: makeGoodResult().Connections}, args{name: "homer"}, &RemoteConnection{"192.168.1.1", "myuser", true, 22, "", false}, false},
// Good connection
- {"goodbart", fields{Connections: makeGoodResult().Connections}, args{name: "bart"}, &RemoteConnection{"foobar.com", "root", false, 22}, false},
+ {"goodbart", fields{Connections: makeGoodResult().Connections}, args{name: "bart"}, &RemoteConnection{"foobar.com", "root", false, 22, "", false}, false},
// Getting an unknown connection should result in error
{"noexist", fields{Connections: makeGoodResult().Connections}, args{name: "foobar"}, nil, true},
// Getting a connection when there are none should result in an error
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 3434a2bcb..2408dc80c 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -781,8 +781,43 @@ method ListImages() -> (images: []Image)
method GetImage(id: string) -> (image: Image)
# BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the
-# 'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [MoreResponse](#MoreResponse) structure
+# contextDir tarball path, the 'dockerfiles' path, and 'output' option in the BuildInfo structure. The 'output'
+# options is the name of the of the resulting build. It will return a [MoreResponse](#MoreResponse) structure
# that contains the build logs and resulting image ID.
+# #### Example
+# ~~~
+# $ sudo varlink call -m unix:///run/podman/io.podman/io.podman.BuildImage '{"build":{"contextDir":"/tmp/t/context.tar","dockerfiles":["Dockerfile"], "output":"foobar"}}'
+# {
+# "image": {
+# "id": "",
+# "logs": [
+# "STEP 1: FROM alpine\n"
+# ]
+# }
+# }
+# {
+# "image": {
+# "id": "",
+# "logs": [
+# "STEP 2: COMMIT foobar\n"
+# ]
+# }
+# }
+# {
+# "image": {
+# "id": "",
+# "logs": [
+# "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9\n"
+# ]
+# }
+# }
+# {
+# "image": {
+# "id": "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9",
+# "logs": []
+# }
+# }
+# ~~~
method BuildImage(build: BuildInfo) -> (image: MoreResponse)
# This function is not implemented yet.
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 7aa8881d6..779f95d95 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -124,35 +124,46 @@ you'll find the new image names displayed at the end of the
```
...cut...
-==> Builds finished. The artifacts of successful builds are:
---> ubuntu-18: A disk image was created: ubuntu-18-libpod-5699523102900224
---> ubuntu-18:
---> fedora-29: A disk image was created: fedora-29-libpod-5699523102900224
---> fedora-29:
---> fedora-28: A disk image was created: fedora-28-libpod-5699523102900224
+
+[+0747s] ==> Builds finished. The artifacts of successful builds are:
+[+0747s] --> ubuntu-18: A disk image was created: ubuntu-18-libpod-5664838702858240
+[+0747s] --> fedora-29: A disk image was created: fedora-29-libpod-5664838702858240
+[+0747s] --> fedora-30: A disk image was created: fedora-30-libpod-5664838702858240
+[+0747s] --> ubuntu-19: A disk image was created: ubuntu-19-libpod-5664838702858240
```
-Now edit `.cirrus.yml`, updating the `*_IMAGE_NAME` lines to reflect the
-images from above:
+Notice the suffix on all the image names comes from the env. var. set in
+*.cirrus.yml*: `BUILT_IMAGE_SUFFIX: "-${CIRRUS_REPO_NAME}-${CIRRUS_BUILD_ID}"`.
+Edit `.cirrus.yml`, in the top-level `env` section, update the suffix variable
+used at runtime to launch VMs for testing:
```yaml
env:
...cut...
####
- #### Cache-image names to test with
+ #### Cache-image names to test with (double-quotes around names are critical)
###
- FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5699523102900224"
- PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-5699523102900224"
- UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5699523102900224"
+ _BUILT_IMAGE_SUFFIX: "libpod-5664838702858240"
+ FEDORA_CACHE_IMAGE_NAME: "fedora-30-${_BUILT_IMAGE_SUFFIX}"
+ PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-${_BUILT_IMAGE_SUFFIX}"
...cut...
```
-***NOTE:*** If re-using the same PR with new images in `.cirrus.yml`,
-take care to also *update the PR description* to remove
-the magic ``***CIRRUS: TEST IMAGES***`` string. Keeping it and
-`--force` pushing would needlessly cause Cirrus-CI to build
-and test images again.
+***NOTES:***
+* If re-using the same PR with new images in `.cirrus.yml`,
+ take care to also *update the PR description* to remove
+ the magic ``***CIRRUS: TEST IMAGES***`` string. Keeping it and
+ `--force` pushing would needlessly cause Cirrus-CI to build
+ and test images again.
+* In the future, if you need to review the log from the build that produced
+ the referenced image:
+
+ * Note the Build ID from the image name (for example `5664838702858240`).
+ * Go to that build in the Cirrus-CI WebUI, using the build ID in the URL.
+ (For example `https://cirrus-ci.com/build/5664838702858240`.
+ * Choose the *test_build_cache_images* task.
+ * Open the *build_vm_images* script section.
### `release` Task
diff --git a/contrib/cirrus/build_release.sh b/contrib/cirrus/build_release.sh
index 287643f47..07db88f81 100755
--- a/contrib/cirrus/build_release.sh
+++ b/contrib/cirrus/build_release.sh
@@ -1,5 +1,7 @@
#!/bin/bash
+set -e
+
source $(dirname $0)/lib.sh
req_env_var TEST_REMOTE_CLIENT OS_RELEASE_ID GOSRC
@@ -13,18 +15,20 @@ fi
if [[ -n "$CROSS_PLATFORM" ]]
then
+ # Will fail if $CROSS_PLATFORM is unsupported cross-compile $GOOS value
+ make podman-remote-${CROSS_PLATFORM}-release
+
echo "Compiling podman-remote release archive for ${CROSS_PLATFORM}"
- case "$CROSS_PLATFORM" in
- linux) ;&
- windows) ;&
- darwin)
- make podman-remote-${CROSS_PLATFORM}-release
- ;;
- *)
- die 1 "Unknown/unsupported cross-compile platform '$CROSS_PLATFORM'"
- ;;
- esac
+ if [[ "$CROSS_PLATFORM" == "windows" ]]
+ then
+ # TODO: Remove next line, part of VM images next time they're built.
+ dnf install -y libmsi1 msitools pandoc
+ make podman.msi
+ fi
else
echo "Compiling release archive for $OS_RELEASE_ID"
make podman-release
fi
+
+echo "Preserving build details for later use."
+mv -v release.txt actual_release.txt # Another 'make' during testing could overwrite it
diff --git a/contrib/cirrus/check_image.sh b/contrib/cirrus/check_image.sh
index 39f49d0a1..5423f67d6 100755
--- a/contrib/cirrus/check_image.sh
+++ b/contrib/cirrus/check_image.sh
@@ -56,6 +56,11 @@ then
item_test "On ubuntu /usr/bin/runc is /usr/lib/cri-o-runc/sbin/runc" "$SAMESAME" -eq "0" || let "NFAILS+=1"
fi
+if [[ "$OS_RELEASE_ID" == "ubuntu" ]]
+then
+ item_test "On ubuntu, no periodic apt crap is enabled" -z "$(egrep $PERIODIC_APT_RE /etc/apt/apt.conf.d/*)"
+fi
+
echo "Checking items specific to ${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}"
case "$PACKER_BUILDER_NAME" in
xfedora*)
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index f81a8d501..fe4c25e73 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -73,6 +73,8 @@ UPLDREL_IMAGE="quay.io/libpod/upldrel:latest"
export DEBIAN_FRONTEND="noninteractive"
SUDOAPTGET="ooe.sh sudo -E apt-get -qq --yes"
SUDOAPTADD="ooe.sh sudo -E add-apt-repository --yes"
+# Regex that finds enabled periodic apt configuration items
+PERIODIC_APT_RE='^(APT::Periodic::.+")1"\;'
# Short-cuts for retrying/timeout calls
LILTO="timeout_attempt_delay_command 24s 5 30s"
BIGTO="timeout_attempt_delay_command 300s 5 30s"
diff --git a/contrib/cirrus/logcollector.sh b/contrib/cirrus/logcollector.sh
index 425a619b0..3393ac9b5 100755
--- a/contrib/cirrus/logcollector.sh
+++ b/contrib/cirrus/logcollector.sh
@@ -32,5 +32,42 @@ case $1 in
df) showrun df -lhTx tmpfs ;;
ginkgo) showrun cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log ;;
journal) showrun journalctl -b ;;
+ packages)
+ case $OS_RELEASE_ID in
+ fedora*)
+ PKG_LST_CMD='rpm -q --qf=%{N}-%{V}-%{R}-%{ARCH}\n'
+ PKG_NAMES=(\
+ container-selinux \
+ containernetworking-plugins \
+ containers-common \
+ criu \
+ golang \
+ podman \
+ slirp4netns \
+ )
+ if [[ "$OS_RELEASE_VER" -lt "31" ]]; then
+ PKG_NAMES+=(runc)
+ else
+ PKG_NAMES+=(crun)
+ fi
+ ;;
+ ubuntu*)
+ PKG_LST_CMD='dpkg-query --show --showformat=${Package}-${Version}-${Architecture}\n'
+ PKG_NAMES=(\
+ containernetworking-plugins \
+ containers-common \
+ cri-o-runc \
+ criu \
+ golang \
+ libvarlink \
+ podman \
+ skopeo \
+ slirp4netns \
+ )
+ ;;
+ *) bad_os_id_ver ;;
+ esac
+ $PKG_LST_CMD ${PKG_NAMES[@]} | sort -u
+ ;;
*) die 1 "Warning, $(basename $0) doesn't know how to handle the parameter '$1'"
esac
diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh
index 6709eecaf..679ad3b8d 100644
--- a/contrib/cirrus/packer/fedora_setup.sh
+++ b/contrib/cirrus/packer/fedora_setup.sh
@@ -26,6 +26,7 @@ ooe.sh sudo dnf install -y \
atomic-registries \
autoconf \
automake \
+ bash-completion \
bats \
bridge-utils \
btrfs-progs-devel \
@@ -36,6 +37,7 @@ ooe.sh sudo dnf install -y \
criu \
device-mapper-devel \
emacs-nox \
+ file \
findutils \
fuse3 \
fuse3-devel \
@@ -53,18 +55,22 @@ ooe.sh sudo dnf install -y \
jq \
libassuan-devel \
libcap-devel \
+ libmsi1 \
libnet \
libnet-devel \
libnl3-devel \
libseccomp \
libseccomp-devel \
libselinux-devel \
+ libtool \
libvarlink-util \
lsof \
make \
+ msitools \
nmap-ncat \
ostree \
ostree-devel \
+ pandoc \
podman \
procps-ng \
protobuf \
diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh
index da7d457a5..2f54da9ed 100644
--- a/contrib/cirrus/packer/ubuntu_setup.sh
+++ b/contrib/cirrus/packer/ubuntu_setup.sh
@@ -18,8 +18,16 @@ trap "sudo rm -rf $GOPATH" EXIT
# Ensure there are no disruptive periodic services enabled by default in image
systemd_banish
+# Stop disruption upon boot ASAP after booting
+echo "Disabling all packaging activity on boot"
+# Don't let sed process sed's temporary files
+_FILEPATHS=$(sudo ls -1 /etc/apt/apt.conf.d)
+for filename in $_FILEPATHS; do \
+ echo "Checking/Patching $filename"
+ sudo sed -i -r -e "s/$PERIODIC_APT_RE/"'\10"\;/' "/etc/apt/apt.conf.d/$filename"; done
+
echo "Updating/configuring package repositories."
-$LILTO $SUDOAPTGET update
+$BIGTO $SUDOAPTGET update
echo "Upgrading all packages"
$BIGTO $SUDOAPTGET upgrade
@@ -41,6 +49,7 @@ $BIGTO $SUDOAPTGET install \
aufs-tools \
autoconf \
automake \
+ bash-completion \
bats \
bison \
btrfs-tools \
@@ -52,6 +61,7 @@ $BIGTO $SUDOAPTGET install \
curl \
e2fslibs-dev \
emacs-nox \
+ file \
gawk \
gcc \
gettext \
diff --git a/contrib/cirrus/upload_release_archive.sh b/contrib/cirrus/upload_release_archive.sh
index 942255821..25107f0ef 100755
--- a/contrib/cirrus/upload_release_archive.sh
+++ b/contrib/cirrus/upload_release_archive.sh
@@ -9,6 +9,7 @@ req_env_var CI UPLDREL_IMAGE CIRRUS_BUILD_ID GOSRC RELEASE_GCPJSON RELEASE_GCPNA
[[ "$CI" == "true" ]] || \
die 56 "$0 must be run under Cirrus-CI to function"
+# We store "releases" for each PR, mostly to validate the process is functional
unset PR_OR_BRANCH BUCKET
if [[ -n "$CIRRUS_PR" ]]
then
@@ -22,31 +23,76 @@ else
die 1 "Expecting either \$CIRRUS_PR or \$CIRRUS_BRANCH to be non-empty."
fi
-# Functional local podman required for uploading a release
+echo "Parsing actual_release.txt contents: $(< actual_release.txt)"
cd $GOSRC
+RELEASETXT=$(<actual_release.txt) # see build_release.sh
+[[ -n "$RELEASETXT" ]] || \
+ die 3 "Could not obtain metadata from actual_release.txt"
+RELEASE_INFO=$(echo "$RELEASETXT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/')
+if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]]
+then
+ die 4 "Metadata is empty or invalid: '$RELEASETXT'"
+fi
+# Format specified in Makefile
+# e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64
+# or libpod-remote v1.3.1-166-g60df124e windows - amd64
+FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH"
+read $FIELDS <<< $RELEASE_INFO
+req_env_var $FIELDS
+
+# Functional local podman required for uploading
+echo "Verifying a local, functional podman, building one if necessary."
[[ -n "$(type -P podman)" ]] || \
- make install || \
+ make install PREFIX=/usr || \
die 57 "$0 requires working podman binary on path to function"
TMPF=$(mktemp -p '' $(basename $0)_XXXX.json)
trap "rm -f $TMPF" EXIT
set +x
echo "$RELEASE_GCPJSON" > "$TMPF"
+[[ "$OS_RELEASE_ID" == "ubuntu" ]] || \
+ chcon -t container_file_t "$TMPF"
unset RELEASE_GCPJSON
cd $GOSRC
-for filename in $(ls -1 *.tar.gz *.zip)
+for filename in $(ls -1 *.tar.gz *.zip *.msi)
do
- echo "Running podman ... $UPLDREL_IMAGE $filename"
+ unset EXT
+ EXT=$(echo "$filename" | sed -r -e 's/.+\.(.+$)/\1/g')
+ if [[ -z "$EXT" ]] || [[ "$EXT" == "$filename" ]]
+ then
+ echo "Warning: Not processing $filename (invalid extension '$EXT')"
+ continue
+ fi
+
+ [[ "$OS_RELEASE_ID" == "ubuntu" ]] || \
+ chcon -t container_file_t "$filename"
+ # Form the generic "latest" file for this branch or pr
+ TO_PREFIX="${RELEASE_BASENAME}-latest-${PR_OR_BRANCH}-${RELEASE_DIST}"
+ # Form the fully-versioned filename for historical sake
+ ALSO_PREFIX="${RELEASE_BASENAME}-${RELEASE_VERSION}-${PR_OR_BRANCH}-${RELEASE_DIST}"
+ TO_SUFFIX="${RELEASE_ARCH}.${EXT}"
+ if [[ "$RELEASE_DIST" == "windows" ]] || [[ "$RELEASE_DIST" == "darwin" ]]
+ then
+ TO_FILENAME="${TO_PREFIX}-${TO_SUFFIX}"
+ ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}"
+ else
+ TO_FILENAME="${TO_PREFIX}-${RELEASE_DIST_VER}-${TO_SUFFIX}"
+ ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}"
+ fi
+
+ echo "Running podman ... $UPLDREL_IMAGE for $filename -> $TO_FILENAME"
+ echo "Warning: upload failures are completely ignored, avoiding any needless holdup of PRs."
podman run -i --rm \
-e "GCPNAME=$RELEASE_GCPNAME" \
-e "GCPPROJECT=$RELEASE_GCPROJECT" \
-e "GCPJSON_FILEPATH=$TMPF" \
- -e "REL_ARC_FILEPATH=/tmp/$filename" \
+ -e "FROM_FILEPATH=/tmp/$filename" \
+ -e "TO_FILENAME=$TO_FILENAME" \
+ -e "ALSO_FILENAME=$ALSO_FILENAME" \
-e "PR_OR_BRANCH=$PR_OR_BRANCH" \
-e "BUCKET=$BUCKET" \
- --security-opt label=disable \
-v "$TMPF:$TMPF:ro" \
- -v "$GOSRC/$filename:/tmp/$filename:ro" \
- $UPLDREL_IMAGE
+ -v "$(realpath $GOSRC/$filename):/tmp/$filename:ro" \
+ $UPLDREL_IMAGE || true
done
diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go
index f6c90914a..9b928a6b3 100644
--- a/contrib/perftest/main.go
+++ b/contrib/perftest/main.go
@@ -36,6 +36,9 @@ var helpMessage = `
`
func main() {
+ if reexec.Init() {
+ return
+ }
ctx := context.Background()
imageName := ""
@@ -51,10 +54,6 @@ func main() {
flag.Parse()
- if reexec.Init() {
- return
- }
-
switch strings.ToLower(*logLevel) {
case "error":
logrus.SetLevel(logrus.ErrorLevel)
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 6ac324499..bd2cff3f6 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -39,7 +39,7 @@
%global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7})
Name: podman
-Version: 1.6.0
+Version: 1.6.2
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/contrib/upldrel/entrypoint.sh b/contrib/upldrel/entrypoint.sh
index 985b828a0..6af6829c5 100755
--- a/contrib/upldrel/entrypoint.sh
+++ b/contrib/upldrel/entrypoint.sh
@@ -4,59 +4,22 @@ set -e
source /usr/local/bin/lib_entrypoint.sh
-req_env_var GCPJSON_FILEPATH GCPNAME GCPPROJECT REL_ARC_FILEPATH PR_OR_BRANCH BUCKET
+req_env_var GCPJSON_FILEPATH GCPNAME GCPPROJECT BUCKET FROM_FILEPATH TO_FILENAME ALSO_FILENAME
-[[ -r "$REL_ARC_FILEPATH" ]] || \
+[[ -r "$FROM_FILEPATH" ]] || \
die 2 ERROR Cannot read release archive file: "$REL_ARC_FILEPATH"
[[ -r "$GCPJSON_FILEPATH" ]] || \
die 3 ERROR Cannot read GCP credentials file: "$GCPJSON_FILEPATH"
-cd $TMPDIR
-echo "Attempting to extract release.txt from tar or zip $REL_ARC_FILEPATH"
-unset SFX
-if tar xzf "$REL_ARC_FILEPATH" "./release.txt"
-then
- echo "It's a tarball"
- SFX="tar.gz"
-elif unzip "$REL_ARC_FILEPATH" release.txt
-then
- echo "It's a zip"
- SFX="zip"
-else
- die 5 ERROR Could not extract release.txt from $REL_ARC_FILEPATH
-fi
-
-echo "Parsing release.txt contents"
-RELEASETXT=$(<release.txt)
-cd -
-[[ -n "$RELEASETXT" ]] || \
- die 3 ERROR Could not obtain metadata from release.txt in $REL_ARC_FILEPATH
-
-RELEASE_INFO=$(echo "$RELEASETXT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/')
-if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]]
-then
- die 4 ERROR Metadata is empty or invalid: '$RELEASETXT'
-fi
-
-# e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64
-# or libpod v1.3.1-166-g60df124e amd64
-FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH"
-read $FIELDS <<< $RELEASE_INFO
-for f in $FIELDS
-do
- [[ -n "${!f}" ]] || \
- die 5 ERROR Expecting $f to be non-empty in metadata: '$RELEASE_INFO'
-done
-
+echo "Authenticating to google cloud for upload"
gcloud_init "$GCPJSON_FILEPATH"
-# Drop version number to enable "latest" representation
-# (version available w/in zip-file comment)
-RELEASE_ARCHIVE_NAME="${RELEASE_BASENAME}-${PR_OR_BRANCH}-${RELEASE_DIST}-${RELEASE_DIST_VER}-${RELEASE_ARCH}.${SFX}"
-
-echo "Uploading archive as $RELEASE_ARCHIVE_NAME"
-gsutil cp "$REL_ARC_FILEPATH" "gs://$BUCKET/$RELEASE_ARCHIVE_NAME"
+echo "Uploading archive as $TO_FILENAME"
+gsutil cp "$FROM_FILEPATH" "gs://$BUCKET/$TO_FILENAME"
+gsutil cp "$FROM_FILEPATH" "gs://$BUCKET/$ALSO_FILENAME"
-echo "Release now available at:"
-echo " https://storage.cloud.google.com/$BUCKET/$RELEASE_ARCHIVE_NAME"
+echo "."
+echo "Release now available for download at:"
+echo " https://storage.cloud.google.com/$BUCKET/$TO_FILENAME"
+echo " https://storage.cloud.google.com/$BUCKET/$ALSO_FILENAME"
diff --git a/docs/podman-cp.1.md b/docs/podman-cp.1.md
index 736bdb12a..0f54b2e8b 100644
--- a/docs/podman-cp.1.md
+++ b/docs/podman-cp.1.md
@@ -29,7 +29,7 @@ Assuming a path separator of /, a first argument of **src_path** and second argu
- **dest_path** does not exist
- the file is saved to a file created at **dest_path**
- **dest_path** does not exist and ends with /
- - **dest_path** is created as a directory and the file is copied into this directory using the basename from **src_path**
+ - Error condition: the destination directory must exist.
- **dest_path** exists and is a file
- the destination is overwritten with the source file's contents
- **dest_path** exists and is a directory
diff --git a/docs/podman-import.1.md b/docs/podman-import.1.md
index 5e57c1bcb..946b680dd 100644
--- a/docs/podman-import.1.md
+++ b/docs/podman-import.1.md
@@ -55,6 +55,26 @@ db65d991f3bbf7f31ed1064db9a6ced7652e3f8166c4736aa9133dadd3c7acb3
```
```
+$ podman import --change "ENTRYPOINT ["/bin/sh","-c","test-image"]" --change LABEL=blue=image test-image.tar image-imported
+Getting image source signatures
+Copying blob e3b0c44298fc skipped: already exists
+Copying config 1105523502 done
+Writing manifest to image destination
+Storing signatures
+110552350206337183ceadc0bdd646dc356e06514c548b69a8917b4182414b
+```
+```
+$ podman import --change "CMD /bin/sh" --change LABEL=blue=image test-image.tar image-imported
+Getting image source signatures
+Copying blob e3b0c44298fc skipped: already exists
+Copying config ae9a27e249 done
+Writing manifest to image destination
+Storing signatures
+ae9a27e249f801aff11a4ba54a81751ea9fbc9db45a6df3f1bfd63fc2437bb9c
+```
+
+
+```
$ cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported
db65d991f3bbf7f31ed1064db9a6ced7652e3f8166c4736aa9133dadd3c7acb3
```
diff --git a/docs/podman-remote.conf.5.md b/docs/podman-remote.conf.5.md
index 3c8a1a801..e9cc05989 100644
--- a/docs/podman-remote.conf.5.md
+++ b/docs/podman-remote.conf.5.md
@@ -25,6 +25,12 @@ of the user's remote connections.
**port** = int
Use an alternative port for the ssh connections. The default port is 22.
+**identity_file** = ""
+ Use an alternative location for the ssh private key
+
+**ignore_hosts** = bool
+ Don't match the remote ssh host key with known hosts
+
## EXAMPLE
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index c340d683f..bcd1b01d9 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -4,18 +4,22 @@
## Links to a number of useful tutorials for the Podman utility.
-**[Introduction Tutorial](https://github.com/containers/libpod/tree/master/docs/tutorials/podman_tutorial.md)**
+**[Introduction Tutorial](podman_tutorial.md)**
Learn how to setup Podman and perform some basic commands with the utility.
-**[Basic Setup and Use of Podman in a Rootless environment.](https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md).**
+**[Basic Setup and Use of Podman in a Rootless environment](rootless_tutorial.md)**
The steps required to setup rootless Podman are enumerated.
-**[Setup on OS X](https://github.com/containers/libpod/blob/master/doc/tutorials/mac_client.md)**
+**[Setup on OS X](mac_client.md)**
-Special setup for running the Podman remote client on a Mac and connecting to Podman running on a Linux VM are documented
+Special setup for running the Podman remote client on a Mac and connecting to Podman running on a Linux VM are documented.
-**[Remote Client](https://github.com/containers/libpod/blob/master/doc/tutorials/remote_client.md)**
+**[Remote Client](remote_client.md)**
A brief how-to on using the Podman remote-client.
+
+**[How to use libpod for custom/derivative projects](podman-derivative-api.md)**
+
+How the libpod API can be used within your own project.
diff --git a/docs/tutorials/podman-derivative-api.md b/docs/tutorials/podman-derivative-api.md
new file mode 100644
index 000000000..065b0c4a9
--- /dev/null
+++ b/docs/tutorials/podman-derivative-api.md
@@ -0,0 +1,46 @@
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+# How to use libpod for custom/derivative projects
+
+libpod today is a Golang library and a CLI. The choice of interface you make has advantages and disadvantages.
+
+Running as a subprocess
+---
+
+Advantages:
+
+ - Many commands output JSON
+ - Works with languages other than Golang
+ - Easy to get started
+
+Disadvantages:
+
+ - Error handling is harder
+ - May be slower
+ - Can't hook into or control low-level things like how images are pulled
+
+Vendoring into a Go project
+---
+
+Advantages:
+
+ - Significant power and control
+
+Disadvantages:
+
+ - You are now on the hook for container runtime security updates (partially, `runc`/`crun` are separate)
+ - Binary size
+ - Potential skew between multiple libpod versions operating on the same storage can cause problems
+
+Varlink
+---
+
+Some code exists for this; splits the difference. Future uncertain.
+
+Making the choice
+---
+
+A good question to ask first is: Do you want users to be able to use `podman` to manipulate the containers created by your project?
+If so, that makes it more likely that you want to run `podman` as a subprocess. If you want a separate image store and a fundamentally
+different experience; if what you're doing with containers is quite different from those created by the `podman` CLI,
+that may drive you towards vendoring.
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index 559d25d6a..169cefc0e 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -5,7 +5,7 @@ Podman is a utility provided as part of the libpod library. It can be used to c
containers. The following tutorial will teach you how to set up Podman and perform some basic
commands with Podman.
-If you are running on a Mac, you should instead follow the [Mac tutorial](https://github.com/containers/libpod/blob/master/mac_client.md)
+If you are running on a Mac, you should instead follow the [Mac tutorial](https://github.com/containers/libpod/blob/master/docs/tutorials/mac_client.md)
to set up the remote Podman client.
**NOTE**: the code samples are intended to be run as a non-root user, and use `sudo` where
diff --git a/go.mod b/go.mod
index 117f85b3c..7dd0a8845 100644
--- a/go.mod
+++ b/go.mod
@@ -12,15 +12,14 @@ require (
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
github.com/containernetworking/cni v0.7.1
- github.com/containernetworking/plugins v0.8.1
+ github.com/containernetworking/plugins v0.8.2
github.com/containers/buildah v1.11.2
github.com/containers/conmon v0.3.0 // indirect
github.com/containers/image v3.0.2+incompatible
github.com/containers/psgo v1.3.1
- github.com/containers/storage v1.13.3
+ github.com/containers/storage v1.13.4
github.com/coreos/bbolt v1.3.3 // indirect
github.com/coreos/etcd v3.3.13+incompatible // indirect
- github.com/coreos/go-iptables v0.4.2 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/cri-o/ocicni v0.1.1-0.20190702175919-7762645d18ca
@@ -28,7 +27,7 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/docker/distribution v2.7.1+incompatible
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16
- github.com/docker/docker-credential-helpers v0.6.2
+ github.com/docker/docker-credential-helpers v0.6.3
github.com/docker/go-connections v0.4.0
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 // indirect
github.com/docker/go-units v0.4.0
@@ -61,8 +60,8 @@ require (
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect
- github.com/onsi/ginkgo v1.8.0
- github.com/onsi/gomega v1.5.0
+ github.com/onsi/ginkgo v1.10.1
+ github.com/onsi/gomega v1.7.0
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc8.0.20190827142921-dd075602f158
@@ -76,17 +75,16 @@ require (
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/common v0.6.0 // indirect
github.com/rogpeppe/fastuuid v1.1.0 // indirect
- github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 // indirect
github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f // indirect
github.com/seccomp/libseccomp-golang v0.9.1 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/spf13/jwalterweatherman v1.1.0 // indirect
- github.com/spf13/pflag v1.0.3
+ github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0 // indirect
- github.com/stretchr/testify v1.3.0
+ github.com/stretchr/testify v1.4.0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
- github.com/uber/jaeger-client-go v2.16.0+incompatible
+ github.com/uber/jaeger-client-go v2.19.0+incompatible
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5 // indirect
github.com/ugorji/go v1.1.5-pre // indirect
github.com/ulikunitz/xz v0.5.6 // indirect
@@ -106,8 +104,7 @@ require (
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect
google.golang.org/grpc v1.21.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
- gopkg.in/yaml.v2 v2.2.2
+ gopkg.in/yaml.v2 v2.2.3
k8s.io/api v0.0.0-20190813020757-36bff7324fb7
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
diff --git a/go.sum b/go.sum
index 63c2ddd30..c82030a32 100644
--- a/go.sum
+++ b/go.sum
@@ -34,6 +34,7 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
@@ -44,6 +45,7 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37 h1:uxxtrnACqI9zK4ENDMf0WpXfUsHP5V8liuq5QdgDISU=
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48 h1:AQMF0Xixllgf29MKlx/TGEhRk7bEDX5kxz8Ui8lOvEs=
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
@@ -62,12 +64,15 @@ github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVl
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containernetworking/cni v0.7.0-rc2 h1:2GGDhbwdWPY53iT7LXy+LBP76Ch2D/hnw1U2zVFfGbk=
github.com/containernetworking/cni v0.7.0-rc2/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.7.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.7.4 h1:ugkuXfg1Pdzm54U5DGMzreYIkZPSCmSq4rm5TIXVICA=
github.com/containernetworking/plugins v0.7.4/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
github.com/containernetworking/plugins v0.8.1 h1:dJbykiiSIS3Xvo8d+A6rSXcUEFGfvCjUA+bUED4qegQ=
github.com/containernetworking/plugins v0.8.1/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
+github.com/containernetworking/plugins v0.8.2 h1:5lnwfsAYO+V7yXhysJKy3E1A2Gy9oVut031zfdOzI9w=
+github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc=
github.com/containers/buildah v1.8.4-0.20190821140209-376e52ee0142 h1:RxJ7MbdmorTHiKcJDOz6SwRPasZVp4LOdRWoZ1fdlsQ=
github.com/containers/buildah v1.8.4-0.20190821140209-376e52ee0142/go.mod h1:QIIw13J1YIwWQskItX1wqZPQtUOOKrOnHE+LTibbLLA=
github.com/containers/buildah v1.9.0 h1:ktVRCGNoVfW8PlTuCKUeh+zGdqn1Nik80DSWvGX+v4Y=
@@ -110,6 +115,8 @@ github.com/containers/storage v1.13.2 h1:UXZ0Ckmk6+6+4vj2M2ywruVtH97pnRoAhTG8ctd
github.com/containers/storage v1.13.2/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/containers/storage v1.13.3 h1:9EzTXZXG/8SGD9MnkSCe/jLq3QldcE1QlgW7vePEsjw=
github.com/containers/storage v1.13.3/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
+github.com/containers/storage v1.13.4 h1:j0bBaJDKbUHtAW1MXPFnwXJtqcH+foWeuXK1YaBV5GA=
+github.com/containers/storage v1.13.4/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -143,6 +150,10 @@ github.com/cyphar/filepath-securejoin v0.2.1 h1:5DPkzz/0MwUpvR4fxASKzgApeq2OMFY5
github.com/cyphar/filepath-securejoin v0.2.1/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
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/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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=
@@ -167,6 +178,8 @@ github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjs
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.2 h1:CrW9H1VMf3a4GrtyAi7IUJjkJVpwBBpX0+mvkvYJaus=
github.com/docker/docker-credential-helpers v0.6.2/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA=
@@ -222,6 +235,7 @@ github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcs
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f h1:zlOR3rOlPAVvtfuxGKoghCmop5B0TRyu/ZieziZuGiM=
github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
@@ -307,6 +321,7 @@ github.com/ishidawataru/sctp v0.0.0-20180213033435-07191f837fed h1:3MJOWnAfq3T9e
github.com/ishidawataru/sctp v0.0.0-20180213033435-07191f837fed/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111 h1:NAAiV9ass6VReWFjuxqrMIq12WKlSULI6Gs3PxQghLA=
github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -317,6 +332,9 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/juju/errors v0.0.0-20180806074554-22422dad46e1/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
+github.com/juju/testing v0.0.0-20190613124551-e81189438503/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
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=
@@ -376,12 +394,16 @@ github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@@ -389,6 +411,8 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -506,15 +530,20 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.2.6+incompatible h1:JvoDL7JSoIP2HDE8AbDH3zC8QBPxmzYe32HHy5yQ+Ck=
@@ -526,6 +555,8 @@ github.com/uber/jaeger-client-go v0.0.0-20190214182810-64f57863bf63 h1:AUyEEP9m1
github.com/uber/jaeger-client-go v0.0.0-20190214182810-64f57863bf63/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY=
github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-client-go v2.19.0+incompatible h1:pbwbYfHUoaase0oPQOdZ1GcaUjImYGimUXSQ/+8+Z8Q=
+github.com/uber/jaeger-client-go v2.19.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5 h1:CwmGyzHTzCqCdZJkWR0A7ucZXgrCY7spRcpvm7ci//s=
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@@ -546,6 +577,7 @@ github.com/vbauerster/mpb v3.3.4+incompatible h1:DDIhnwmgTQIDZo+SWlEr5d6mJBxkOLB
github.com/vbauerster/mpb v3.3.4+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tLAD8IceomUCNw=
github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
@@ -569,6 +601,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M=
@@ -598,6 +631,7 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8=
@@ -724,6 +758,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
diff --git a/hack/get_release_info.sh b/hack/get_release_info.sh
index 29b4237b4..b75751170 100755
--- a/hack/get_release_info.sh
+++ b/hack/get_release_info.sh
@@ -33,7 +33,7 @@ case "$1" in
OUTPUT="${GOARCH:-$(go env GOARCH 2> /dev/null)}"
;;
BASENAME*)
- OUTPUT="${CIRRUS_REPO_NAME:-$(basename $(git rev-parse --show-toplevel))}"
+ OUTPUT="podman"
;;
REMOTENAME*)
OUTPUT="$($0 BASENAME)-remote"
diff --git a/hack/install_catatonit.sh b/hack/install_catatonit.sh
index e5532a200..7fd7592a9 100755
--- a/hack/install_catatonit.sh
+++ b/hack/install_catatonit.sh
@@ -1,15 +1,24 @@
#!/bin/bash -e
BASE_PATH="/usr/libexec/podman"
CATATONIT_PATH="${BASE_PATH}/catatonit"
-CATATONIT_VERSION="v0.1.3"
+CATATONIT_VERSION="v0.1.4"
if [ -f $CATATONIT_PATH ]; then
echo "skipping ... catatonit is already installed"
else
- echo "downloading catatonit to $CATATONIT_PATH"
- curl -o catatonit -L https://github.com/openSUSE/catatonit/releases/download/$CATATONIT_VERSION/catatonit.x86_64
- chmod +x catatonit
+ echo "installing catatonit to $CATATONIT_PATH"
+ buildDir=$(mktemp -d)
+ git clone https://github.com/openSUSE/catatonit.git $buildDir
+
+ pushd $buildDir
+ echo `pwd`
+ git reset --hard ${CATATONIT_VERSION}
+ autoreconf -fi
+ ./configure
+ make
install ${SELINUXOPT} -d -m 755 $BASE_PATH
install ${SELINUXOPT} -m 755 catatonit $CATATONIT_PATH
- rm catatonit
+ popd
+
+ rm -rf $buildDir
fi
diff --git a/install.md b/install.md
index eb4ecfa68..b90f20395 100644
--- a/install.md
+++ b/install.md
@@ -130,6 +130,7 @@ sudo apt-get install \
go-md2man \
iptables \
libassuan-dev \
+ libbtrfs-dev \
libc6-dev \
libdevmapper-dev \
libglib2.0-dev \
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 8b96b3f62..a4dcd23be 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -622,7 +622,11 @@ func (c *Container) refresh() error {
return err
}
- return nil
+ if rootless.IsRootless() {
+ return nil
+ }
+
+ return c.refreshCNI()
}
// Remove conmon attach socket and terminal resize FIFO
@@ -646,14 +650,8 @@ func (c *Container) removeConmonFiles() error {
// Remove the exit file so we don't leak memory in tmpfs
exitFile := filepath.Join(c.ociRuntime.exitsDir, c.ID())
- if _, err := os.Stat(exitFile); err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "error running stat on container %s exit file", c.ID())
- }
- } else {
- if err := os.Remove(exitFile); err != nil {
- return errors.Wrapf(err, "error removing container %s exit file", c.ID())
- }
+ if err := os.Remove(exitFile); err != nil && !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error removing container %s exit file", c.ID())
}
return nil
@@ -922,6 +920,12 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
span.SetTag("struct", "container")
defer span.Finish()
+ // Unconditionally remove conmon temporary files.
+ // We've been running into far too many issues where they block startup.
+ if err := c.removeConmonFiles(); err != nil {
+ return err
+ }
+
// Generate the OCI newSpec
newSpec, err := c.generateSpec(ctx)
if err != nil {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 230b5b888..2636fdb6c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -78,15 +78,21 @@ func (c *Container) prepare() (Err error) {
// Set up network namespace if not already set up
if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
+ if createNetNSErr != nil {
+ return
+ }
tmpStateLock.Lock()
defer tmpStateLock.Unlock()
// Assign NetNS attributes to container
- if createNetNSErr == nil {
- c.state.NetNS = netNS
- c.state.NetworkStatus = networkStatus
- }
+ c.state.NetNS = netNS
+ c.state.NetworkStatus = networkStatus
+ }
+
+ // handle rootless network namespace setup
+ if c.state.NetNS != nil && c.config.NetMode == "slirp4netns" && !c.config.PostConfigureNetNS {
+ createNetNSErr = c.runtime.setupRootlessNetNS(c)
}
}()
// Mount storage if not mounted
@@ -1319,3 +1325,10 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
}
return nil
}
+
+// Teardown CNI config on refresh
+func (c *Container) refreshCNI() error {
+ // Let's try and delete any lingering network config...
+ podNetwork := c.runtime.getPodNetwork(c.ID(), c.config.Name, "", c.config.Networks, c.config.PortMappings, c.config.StaticIP)
+ return c.runtime.netPlugin.TearDownPod(podNetwork)
+}
diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go
index 6fa19a778..05a587c59 100644
--- a/libpod/container_internal_unsupported.go
+++ b/libpod/container_internal_unsupported.go
@@ -40,3 +40,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
func (c *Container) copyOwnerAndPerms(source, dest string) error {
return nil
}
+
+func (c *Container) refreshCNI() error {
+ return define.ErrNotImplemented
+}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 0be6eeeb9..855da8611 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -29,7 +29,6 @@ import (
"github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
- "github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -85,9 +84,6 @@ func NewImageRuntimeFromStore(store storage.Store) *Runtime {
// NewImageRuntimeFromOptions creates an Image Runtime including the store given
// store options
func NewImageRuntimeFromOptions(options storage.StoreOptions) (*Runtime, error) {
- if reexec.Init() {
- return nil, errors.Errorf("unable to reexec")
- }
store, err := setStore(options)
if err != nil {
return nil, err
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 5a6d095f6..ef39d09c3 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
+ "github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
)
@@ -70,6 +71,13 @@ func makeLocalMatrix(b, bg *Image) ([]localImageTest, error) {
}
+func TestMain(m *testing.M) {
+ if reexec.Init() {
+ return
+ }
+ os.Exit(m.Run())
+}
+
// TestImage_NewFromLocal tests finding the image locally by various names,
// tags, and aliases
func TestImage_NewFromLocal(t *testing.T) {
diff --git a/libpod/info.go b/libpod/info.go
index e5132b5f6..297086ebb 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,6 +13,7 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/utils"
"github.com/containers/storage"
@@ -29,6 +30,15 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
info["arch"] = runtime.GOARCH
info["cpus"] = runtime.NumCPU()
info["rootless"] = rootless.IsRootless()
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading cgroups mode")
+ }
+ cgroupVersion := "v1"
+ if unified {
+ cgroupVersion = "v2"
+ }
+ info["CgroupVersion"] = cgroupVersion
mi, err := system.ReadMemInfo()
if err != nil {
return nil, errors.Wrapf(err, "error reading memory info")
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 67dd0150b..61ab57d65 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -90,9 +90,6 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
// Create and configure a new network namespace for a container
func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result, err error) {
- if rootless.IsRootless() {
- return nil, nil, errors.New("cannot configure a new network namespace in rootless mode, only --network=slirp4netns is supported")
- }
ctrNS, err := netns.NewNS()
if err != nil {
return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
@@ -110,7 +107,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result,
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
- networkStatus, err := r.configureNetNS(ctr, ctrNS)
+ networkStatus := []*cnitypes.Result{}
+ if !rootless.IsRootless() {
+ networkStatus, err = r.configureNetNS(ctr, ctrNS)
+ }
return ctrNS, networkStatus, err
}
@@ -138,9 +138,6 @@ func checkSlirpFlags(path string) (bool, bool, bool, error) {
// Configure the network namespace for a rootless container
func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
-
path := r.config.NetworkCmdPath
if path == "" {
@@ -164,7 +161,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
cmdArgs := []string{}
if havePortMapping {
- cmdArgs = append(cmdArgs, "--api-socket", apiSocket, fmt.Sprintf("%d", ctr.state.PID))
+ cmdArgs = append(cmdArgs, "--api-socket", apiSocket)
}
dhp, mtu, sandbox, err := checkSlirpFlags(path)
if err != nil {
@@ -179,13 +176,38 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
if sandbox {
cmdArgs = append(cmdArgs, "--enable-sandbox")
}
- cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4", fmt.Sprintf("%d", ctr.state.PID), "tap0")
- cmd := exec.Command(path, cmdArgs...)
+ // the slirp4netns arguments being passed are describes as follows:
+ // from the slirp4netns documentation: https://github.com/rootless-containers/slirp4netns
+ // -c, --configure Brings up the tap interface
+ // -e, --exit-fd=FD specify the FD for terminating slirp4netns
+ // -r, --ready-fd=FD specify the FD to write to when the initialization steps are finished
+ cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4")
+ if !ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ cmdArgs = append(cmdArgs, "--netns-type=path", ctr.state.NetNS.Path(), "tap0")
+ } else {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
+ cmdArgs = append(cmdArgs, fmt.Sprintf("%d", ctr.state.PID), "tap0")
+ }
+ cmd := exec.Command(path, cmdArgs...)
+ logrus.Debugf("slirp4netns command: %s", strings.Join(cmd.Args, " "))
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
+
+ // workaround for https://github.com/rootless-containers/slirp4netns/pull/153
+ if sandbox {
+ cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
+ cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
+ }
+
+ // Leak one end of the pipe in slirp4netns, the other will be sent to conmon
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncR, syncW)
if err := cmd.Start(); err != nil {
@@ -388,20 +410,22 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- var requestedIP net.IP
- if ctr.requestedIP != nil {
- requestedIP = ctr.requestedIP
- // cancel request for a specific IP in case the container is reused later
- ctr.requestedIP = nil
- } else {
- requestedIP = ctr.config.StaticIP
- }
+ // rootless containers do not use the CNI plugin
+ if !rootless.IsRootless() {
+ var requestedIP net.IP
+ if ctr.requestedIP != nil {
+ requestedIP = ctr.requestedIP
+ // cancel request for a specific IP in case the container is reused later
+ ctr.requestedIP = nil
+ } else {
+ requestedIP = ctr.config.StaticIP
+ }
- podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
- // The network may have already been torn down, so don't fail here, just log
- if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
- return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
+ return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ }
}
// First unmount the namespace
diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go
index a90af32ed..437b7cf4d 100644
--- a/libpod/oci_internal_linux.go
+++ b/libpod/oci_internal_linux.go
@@ -131,9 +131,18 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Containe
}
if ctr.config.NetMode.IsSlirp4netns() {
- ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
- if err != nil {
- return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ if ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ } else {
+ if ctr.rootlessSlirpSyncR != nil {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ }
+ if ctr.rootlessSlirpSyncW != nil {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
+ }
}
// Leak one end in conmon, the other one will be leaked into slirp4netns
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncW)
diff --git a/libpod/options.go b/libpod/options.go
index d28cb3d8c..22ab22a95 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -20,8 +20,8 @@ import (
)
var (
- nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
- regexError = errors.Wrapf(define.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*")
+ NameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
+ RegexError = errors.Wrapf(define.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*")
)
// Runtime Creation Options
@@ -648,8 +648,8 @@ func WithName(name string) CtrCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
ctr.config.Name = name
@@ -1426,8 +1426,8 @@ func WithVolumeName(name string) VolumeCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
volume.config.Name = name
@@ -1532,8 +1532,8 @@ func WithPodName(name string) PodCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
pod.config.Name = name
@@ -1550,8 +1550,8 @@ func WithPodHostname(hostname string) PodCreateOption {
}
// Check the hostname against a regex
- if !nameRegex.MatchString(hostname) {
- return regexError
+ if !NameRegex.MatchString(hostname) {
+ return RegexError
}
pod.config.Hostname = hostname
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 675c92b7a..9f3549e00 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -387,6 +387,13 @@ func SetXdgDirs() error {
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
+ if rootless.IsRootless() && os.Getenv("DBUS_SESSION_BUS_ADDRESS") == "" {
+ sessionAddr := filepath.Join(runtimeDir, "bus")
+ if _, err := os.Stat(sessionAddr); err == nil {
+ os.Setenv("DBUS_SESSION_BUS_ADDRESS", fmt.Sprintf("unix:path=%s", sessionAddr))
+ }
+ }
+
// Setup XDG_CONFIG_HOME
if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" {
if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil {
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index ad6662f03..6a27c2800 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -99,7 +99,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
if isRootless {
netmode = "slirp4netns"
}
- options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, isRootless, netmode, networks))
+ // PostConfigureNetNS should not be set since user namespace sharing is not implemented
+ // and rootless networking no longer supports post configuration setup
+ options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, networks))
return r.newContainer(ctx, g.Config, options...)
}
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
index 1805c758d..da4670892 100644
--- a/pkg/adapter/client.go
+++ b/pkg/adapter/client.go
@@ -35,7 +35,7 @@ func (r RemoteRuntime) RemoteEndpoint() (remoteEndpoint *Endpoint, err error) {
if len(r.cmd.RemoteUserName) < 1 {
return nil, errors.New("you must provide a username when providing a remote host name")
}
- rc := remoteclientconfig.RemoteConnection{r.cmd.RemoteHost, r.cmd.RemoteUserName, false, r.cmd.Port}
+ rc := remoteclientconfig.RemoteConnection{r.cmd.RemoteHost, r.cmd.RemoteUserName, false, r.cmd.Port, r.cmd.IdentityFile, r.cmd.IgnoreHosts}
remoteEndpoint, err = newBridgeConnection("", &rc, r.cmd.LogLevel)
// if the user has a config file with connections in it
} else if len(remoteConfigConnections.Connections) > 0 {
diff --git a/pkg/adapter/client_unix.go b/pkg/adapter/client_unix.go
index a7bc7c1c0..7af8b24c6 100644
--- a/pkg/adapter/client_unix.go
+++ b/pkg/adapter/client_unix.go
@@ -14,7 +14,14 @@ func formatDefaultBridge(remoteConn *remoteclientconfig.RemoteConnection, logLev
if port == 0 {
port = 22
}
+ options := ""
+ if remoteConn.IdentityFile != "" {
+ options += " -i " + remoteConn.IdentityFile
+ }
+ if remoteConn.IgnoreHosts {
+ options += " -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
+ }
return fmt.Sprintf(
- `ssh -p %d -T %s@%s -- /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`,
- port, remoteConn.Username, remoteConn.Destination, logLevel)
+ `ssh -p %d -T%s %s@%s -- varlink -A \'podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`,
+ port, options, remoteConn.Username, remoteConn.Destination, logLevel)
}
diff --git a/pkg/adapter/client_windows.go b/pkg/adapter/client_windows.go
index 31e5d9830..32302a600 100644
--- a/pkg/adapter/client_windows.go
+++ b/pkg/adapter/client_windows.go
@@ -9,7 +9,18 @@ import (
)
func formatDefaultBridge(remoteConn *remoteclientconfig.RemoteConnection, logLevel string) string {
+ port := remoteConn.Port
+ if port == 0 {
+ port = 22
+ }
+ options := ""
+ if remoteConn.IdentityFile != "" {
+ options += " -i " + remoteConn.IdentityFile
+ }
+ if remoteConn.IgnoreHosts {
+ options += " -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
+ }
return fmt.Sprintf(
- `ssh -T %s@%s -- /usr/bin/varlink -A '/usr/bin/podman --log-level=%s varlink $VARLINK_ADDRESS' bridge`,
- remoteConn.Username, remoteConn.Destination, logLevel)
+ `ssh -p %d -T%s %s@%s -- varlink -A 'podman --log-level=%s varlink $VARLINK_ADDRESS' bridge`,
+ port, options, remoteConn.Username, remoteConn.Destination, logLevel)
}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 07ec1f19e..f7cb28b0c 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -488,7 +488,12 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
fmt.Println(cid)
return 0, nil
}
- exitChan, errChan, err := r.attach(ctx, os.Stdin, os.Stdout, cid, true, c.String("detach-keys"))
+ inputStream := os.Stdin
+ // If -i is not set, clear stdin
+ if !c.Bool("interactive") {
+ inputStream = nil
+ }
+ exitChan, errChan, err := r.attach(ctx, inputStream, os.Stdout, cid, true, c.String("detach-keys"))
if err != nil {
return exitCode, err
}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 70293a2c5..c8d57e2a2 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -467,8 +467,15 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
return nil, errors.Wrapf(err, "unable to read %s as YAML", yamlFile)
}
+ if podYAML.Kind != "Pod" {
+ return nil, errors.Errorf("Invalid YAML kind: %s. Pod is the only supported Kubernetes YAML kind", podYAML.Kind)
+ }
+
// check for name collision between pod and container
podName := podYAML.ObjectMeta.Name
+ if podName == "" {
+ return nil, errors.Errorf("pod does not have a name")
+ }
for _, n := range podYAML.Spec.Containers {
if n.Name == podName {
fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName)
diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go
index 1d6fb873c..e765bd46f 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -23,23 +23,42 @@ import (
"fmt"
"os"
"path"
+ "path/filepath"
"runtime"
"strings"
"sync"
"github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
-const nsRunDir = "/var/run/netns"
+// get NSRunDir returns the dir of where to create the netNS. When running
+// rootless, it needs to be at a location writable by user.
+func getNSRunDir() (string, error) {
+ if rootless.IsRootless() {
+ rootlessDir, err := util.GetRuntimeDir()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(rootlessDir, "netns"), nil
+ }
+ return "/var/run/netns", nil
+}
// NewNS creates a new persistent (bind-mounted) network namespace and returns
// an object representing that namespace, without switching to it.
func NewNS() (ns.NetNS, error) {
+ nsRunDir, err := getNSRunDir()
+ if err != nil {
+ return nil, err
+ }
+
b := make([]byte, 16)
- _, err := rand.Reader.Read(b)
+ _, err = rand.Reader.Read(b)
if err != nil {
return nil, fmt.Errorf("failed to generate random netns name: %v", err)
}
@@ -107,9 +126,12 @@ func NewNS() (ns.NetNS, error) {
// Don't unlock. By not unlocking, golang will kill the OS thread when the
// goroutine is done (for go1.10+)
+ threadNsPath := getCurrentThreadNetNSPath()
+
var origNS ns.NetNS
- origNS, err = ns.GetNS(getCurrentThreadNetNSPath())
+ origNS, err = ns.GetNS(threadNsPath)
if err != nil {
+ logrus.Warnf("cannot open current network namespace %s: %q", threadNsPath, err)
return
}
defer func() {
@@ -121,20 +143,27 @@ func NewNS() (ns.NetNS, error) {
// create a new netns on the current thread
err = unix.Unshare(unix.CLONE_NEWNET)
if err != nil {
+ logrus.Warnf("cannot create a new network namespace: %q", err)
return
}
// Put this thread back to the orig ns, since it might get reused (pre go1.10)
defer func() {
if err := origNS.Set(); err != nil {
- logrus.Errorf("unable to set namespace: %q", err)
+ if rootless.IsRootless() && strings.Contains(err.Error(), "operation not permitted") {
+ // When running in rootless mode it will fail to re-join
+ // the network namespace owned by root on the host.
+ return
+ }
+ logrus.Warnf("unable to reset namespace: %q", err)
}
}()
// 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.
- err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "")
+ // are no threads in the ns. Make this a shared mount; it needs to be
+ // back-propogated 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)
}
@@ -150,6 +179,11 @@ func NewNS() (ns.NetNS, error) {
// UnmountNS unmounts the NS held by the netns object
func UnmountNS(ns ns.NetNS) error {
+ nsRunDir, err := getNSRunDir()
+ if err != nil {
+ return err
+ }
+
nsPath := ns.Path()
// Only unmount if it's been bind-mounted (don't touch namespaces in /proc...)
if strings.HasPrefix(nsPath, nsRunDir) {
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index ecb84f6a9..6f6239e5f 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -365,7 +365,7 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) {
}
mappings, err := idtools.NewIDMappings(username, username)
if err != nil {
- logrus.Warnf("cannot find mappings for user %s: %v", username, err)
+ logrus.Errorf("cannot find mappings for user %s: %v", username, err)
} else {
uids = mappings.UIDs()
gids = mappings.GIDs()
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index c17172016..7c3195be4 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -275,7 +275,7 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
options = append(options, libpod.WithNetNSFrom(connectedCtr))
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
- postConfigureNetNS := c.NetMode.IsSlirp4netns() || (hasUserns && !c.UsernsMode.IsHost())
+ postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 38f9c7306..c7aa003e8 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -387,6 +387,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
if err != nil {
return nil, err
}
+ if !addedResources {
+ configSpec.Linux.Resources = &spec.LinuxResources{}
+ }
if addedResources && !cgroup2 {
return nil, errors.New("invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode")
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index 3d59d70d8..93919dd0a 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -168,6 +168,9 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
if _, ok := baseMounts[dest]; ok {
continue
}
+ if _, ok := baseVolumes[dest]; ok {
+ continue
+ }
localOpts := options
if dest == "/run" {
localOpts = append(localOpts, "noexec", "size=65536k")
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 583bf5d18..edcad1d1b 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "regexp"
"strings"
"sync"
"time"
@@ -16,7 +17,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
- "github.com/opencontainers/image-spec/specs-go/v1"
+ v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
@@ -69,6 +70,50 @@ func StringInSlice(s string, sl []string) bool {
return false
}
+// ParseChanges returns key, value(s) pair for given option.
+func ParseChanges(option string) (key string, vals []string, err error) {
+ // Supported format as below
+ // 1. key=value
+ // 2. key value
+ // 3. key ["value","value1"]
+ if strings.Contains(option, " ") {
+ // This handles 2 & 3 conditions.
+ var val string
+ tokens := strings.SplitAfterN(option, " ", 2)
+ if len(tokens) < 2 {
+ return "", []string{}, fmt.Errorf("invalid key value %s", option)
+ }
+ key = strings.Trim(tokens[0], " ") // Need to trim whitespace part of delimeter.
+ val = tokens[1]
+ if strings.Contains(tokens[1], "[") && strings.Contains(tokens[1], "]") {
+ //Trim '[',']' if exist.
+ val = strings.TrimLeft(strings.TrimRight(tokens[1], "]"), "[")
+ }
+ vals = strings.Split(val, ",")
+ } else if strings.Contains(option, "=") {
+ // handles condition 1.
+ tokens := strings.Split(option, "=")
+ key = tokens[0]
+ vals = tokens[1:]
+ } else {
+ // either ` ` or `=` must be provided after command
+ return "", []string{}, fmt.Errorf("invalid format %s", option)
+ }
+
+ if len(vals) == 0 {
+ return "", []string{}, errors.Errorf("no value given for instruction %q", key)
+ }
+
+ for _, v := range vals {
+ //each option must not have ' '., `[`` or `]` & empty strings
+ whitespaces := regexp.MustCompile(`[\[\s\]]`)
+ if whitespaces.MatchString(v) || len(v) == 0 {
+ return "", []string{}, fmt.Errorf("invalid value %s", v)
+ }
+ }
+ return key, vals, nil
+}
+
// GetImageConfig converts the --change flag values in the format "CMD=/bin/bash USER=example"
// to a type v1.ImageConfig
func GetImageConfig(changes []string) (v1.ImageConfig, error) {
@@ -87,40 +132,42 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) {
exposedPorts := make(map[string]struct{})
volumes := make(map[string]struct{})
labels := make(map[string]string)
-
for _, ch := range changes {
- pair := strings.Split(ch, "=")
- if len(pair) == 1 {
- return v1.ImageConfig{}, errors.Errorf("no value given for instruction %q", ch)
+ key, vals, err := ParseChanges(ch)
+ if err != nil {
+ return v1.ImageConfig{}, err
}
- switch pair[0] {
+
+ switch key {
case "USER":
- user = pair[1]
+ user = vals[0]
case "EXPOSE":
var st struct{}
- exposedPorts[pair[1]] = st
+ exposedPorts[vals[0]] = st
case "ENV":
- if len(pair) < 3 {
- return v1.ImageConfig{}, errors.Errorf("no value given for environment variable %q", pair[1])
+ if len(vals) < 2 {
+ return v1.ImageConfig{}, errors.Errorf("no value given for environment variable %q", vals[0])
}
- env = append(env, strings.Join(pair[1:], "="))
+ env = append(env, strings.Join(vals[0:], "="))
case "ENTRYPOINT":
- entrypoint = append(entrypoint, pair[1])
+ // ENTRYPOINT and CMD can have array of strings
+ entrypoint = append(entrypoint, vals...)
case "CMD":
- cmd = append(cmd, pair[1])
+ // ENTRYPOINT and CMD can have array of strings
+ cmd = append(cmd, vals...)
case "VOLUME":
var st struct{}
- volumes[pair[1]] = st
+ volumes[vals[0]] = st
case "WORKDIR":
- workingDir = pair[1]
+ workingDir = vals[0]
case "LABEL":
- if len(pair) == 3 {
- labels[pair[1]] = pair[2]
+ if len(vals) == 2 {
+ labels[vals[0]] = vals[1]
} else {
- labels[pair[1]] = ""
+ labels[vals[0]] = ""
}
case "STOPSIGNAL":
- stopSignal = pair[1]
+ stopSignal = vals[0]
}
}
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index f47c0b7ad..c938dc592 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -1,8 +1,9 @@
package util
import (
- "github.com/stretchr/testify/assert"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
var (
@@ -17,3 +18,71 @@ func TestStringInSlice(t *testing.T) {
// string is not in empty slice
assert.False(t, StringInSlice("one", []string{}))
}
+
+func TestParseChanges(t *testing.T) {
+ // CMD=/bin/sh
+ _, vals, err := ParseChanges("CMD=/bin/sh")
+ assert.EqualValues(t, []string{"/bin/sh"}, vals)
+ assert.NoError(t, err)
+
+ // CMD [/bin/sh]
+ _, vals, err = ParseChanges("CMD [/bin/sh]")
+ assert.EqualValues(t, []string{"/bin/sh"}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh","-c","ls"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh","c","ls"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`, `"c"`, `"ls"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh","arg-with,comma"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh","arg-with,comma"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`, `"arg-with`, `comma"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD "/bin/sh"]
+ _, _, err = ParseChanges(`CMD "/bin/sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin/sh"]`, err.Error())
+
+ // CMD [bin/sh
+ _, _, err = ParseChanges(`CMD "/bin/sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin/sh"]`, err.Error())
+
+ // CMD ["/bin /sh"]
+ _, _, err = ParseChanges(`CMD ["/bin /sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin /sh"`, err.Error())
+
+ // CMD ["/bin/sh", "-c","ls"] whitespace between values
+ _, vals, err = ParseChanges(`CMD ["/bin/sh", "c","ls"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "c"`, err.Error())
+
+ // CMD?
+ _, _, err = ParseChanges(`CMD?`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid format CMD?`, err.Error())
+
+ // empty values for CMD
+ _, _, err = ParseChanges(`CMD `)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value `, err.Error())
+
+ // LABEL=blue=image
+ _, vals, err = ParseChanges(`LABEL=blue=image`)
+ assert.EqualValues(t, []string{"blue", "image"}, vals)
+ assert.NoError(t, err)
+
+ // LABEL = blue=image
+ _, vals, err = ParseChanges(`LABEL = blue=image`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value = blue=image`, err.Error())
+
+}
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 3bd487849..f8557ae0c 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -65,7 +65,9 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
}
// ACK the client upgrade request
- call.ReplyAttach()
+ if err := call.ReplyAttach(); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
reader, writer, _, pw, streams := setupStreams(call)
diff --git a/rootless.md b/rootless.md
index 53463dccc..8cccb86eb 100644
--- a/rootless.md
+++ b/rootless.md
@@ -27,7 +27,6 @@ can easily fail
* Can not use overlayfs driver, but does support fuse-overlayfs
* Ubuntu supports non root overlay, but no other Linux distros do.
* Only other supported driver is VFS.
-* No KATA Container support
* No CNI Support
* CNI wants to modify IPTables, plus other network manipulation that requires CAP_SYS_ADMIN.
* There is potential we could probably do some sort of blacklisting of the relevant plugins, and add a new plugin for rootless networking - slirp4netns as one example and there may be others
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 4e9881d59..b390df8b2 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -78,11 +78,15 @@ func (a testResultsSorted) Less(i, j int) bool { return a[i].length < a[j].lengt
var testResults []testResult
-// TestLibpod ginkgo master function
-func TestLibpod(t *testing.T) {
+func TestMain(m *testing.M) {
if reexec.Init() {
- os.Exit(1)
+ return
}
+ os.Exit(m.Run())
+}
+
+// TestLibpod ginkgo master function
+func TestLibpod(t *testing.T) {
if os.Getenv("NOCACHE") == "1" {
CACHE_IMAGES = []string{}
RESTORE_IMAGES = []string{}
@@ -412,7 +416,7 @@ func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers
// PodmanPID execs podman and returns its PID
func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegration, int) {
- podmanOptions := p.MakeOptions(args, false)
+ podmanOptions := p.MakeOptions(args, false, false)
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
command := exec.Command(p.PodmanBinary, podmanOptions...)
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index 9b0cb757d..3317683de 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -51,6 +51,10 @@ var _ = Describe("Podman cp", func() {
err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644)
Expect(err).To(BeNil())
+ session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo/"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+
session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -65,30 +69,29 @@ var _ = Describe("Podman cp", func() {
})
It("podman cp file to dir", func() {
- srcPath := filepath.Join(podmanTest.RunRoot, "cp_test.txt")
- dstDir := filepath.Join(podmanTest.RunRoot, "receive")
+ name := "testctr"
+ setup := podmanTest.RunTopContainer(name)
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ srcPath := "/tmp/cp_test.txt"
fromHostToContainer := []byte("copy from host to container directory")
+ err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644)
+ Expect(err).To(BeNil())
- session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"})
+ session := podmanTest.Podman([]string{"exec", name, "mkdir", "foodir"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- name := session.OutputToString()
-
- err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644)
- Expect(err).To(BeNil())
- err = os.Mkdir(dstDir, 0755)
- Expect(err).To(BeNil())
session = podmanTest.Podman([]string{"cp", srcPath, name + ":foodir/"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"cp", name + ":foodir/cp_test.txt", dstDir})
+ session = podmanTest.Podman([]string{"exec", name, "ls", "foodir/cp_test.txt"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- os.Remove("cp_test.txt")
- os.RemoveAll("receive")
+ os.Remove("/tmp/cp_test.txt")
})
It("podman cp dir to dir", func() {
@@ -137,10 +140,18 @@ var _ = Describe("Podman cp", func() {
session = podmanTest.Podman([]string{"cp", name + ":/foo.tar.gz", "-"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+
+ os.RemoveAll(testDirPath)
+ os.Remove("file.tar.gz")
})
It("podman cp tar", func() {
- session := podmanTest.Podman([]string{"create", "--name", "testctr", ALPINE, "ls", "-l", "foo"})
+ testctr := "testctr"
+ setup := podmanTest.RunTopContainer(testctr)
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"exec", testctr, "mkdir", "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -157,7 +168,7 @@ var _ = Describe("Podman cp", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"start", "-a", "testctr"})
+ session = podmanTest.Podman([]string{"exec", testctr, "ls", "-l", "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("file.tar"))
@@ -187,6 +198,15 @@ var _ = Describe("Podman cp", func() {
_, err = os.Stat("/tmp/cp_test.txt")
Expect(err).To(Not(BeNil()))
+
+ session = podmanTest.Podman([]string{"exec", name, "ln", "-s", "/tmp/nonesuch", "/test1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"cp", "--pause=false", srcPath, name + ":/test1/"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+
})
It("podman cp volume", func() {
session := podmanTest.Podman([]string{"volume", "create", "data"})
@@ -208,6 +228,9 @@ var _ = Describe("Podman cp", func() {
session = podmanTest.Podman([]string{"cp", "container1" + ":/data/cp_vol1", "cp_vol2"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+
+ os.Remove("cp_vol")
+ os.Remove("cp_vol2")
})
It("podman cp from ctr chown ", func() {
diff --git a/test/e2e/import_test.go b/test/e2e/import_test.go
index 84a91a783..979440a50 100644
--- a/test/e2e/import_test.go
+++ b/test/e2e/import_test.go
@@ -88,7 +88,7 @@ var _ = Describe("Podman import", func() {
Expect(results.LineInOuputStartsWith("importing container test message")).To(BeTrue())
})
- It("podman import with change flag", func() {
+ It("podman import with change flag CMD=<path>", func() {
outfile := filepath.Join(podmanTest.TempDir, "container.tar")
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
@@ -108,4 +108,44 @@ var _ = Describe("Podman import", func() {
Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/bash"))
})
+ It("podman import with change flag CMD <path>", func() {
+ outfile := filepath.Join(podmanTest.TempDir, "container.tar")
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ export := podmanTest.Podman([]string{"export", "-o", outfile, cid})
+ export.WaitWithDefaultTimeout()
+ Expect(export.ExitCode()).To(Equal(0))
+
+ importImage := podmanTest.Podman([]string{"import", "--change", "CMD /bin/sh", outfile, "imported-image"})
+ importImage.WaitWithDefaultTimeout()
+ Expect(importImage.ExitCode()).To(Equal(0))
+
+ results := podmanTest.Podman([]string{"inspect", "imported-image"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ imageData := results.InspectImageJSON()
+ Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/sh"))
+ })
+
+ It("podman import with change flag CMD [\"path\",\"path'\"", func() {
+ outfile := filepath.Join(podmanTest.TempDir, "container.tar")
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ export := podmanTest.Podman([]string{"export", "-o", outfile, cid})
+ export.WaitWithDefaultTimeout()
+ Expect(export.ExitCode()).To(Equal(0))
+
+ importImage := podmanTest.Podman([]string{"import", "--change", "CMD [/bin/bash]", outfile, "imported-image"})
+ importImage.WaitWithDefaultTimeout()
+ Expect(importImage.ExitCode()).To(Equal(0))
+
+ results := podmanTest.Podman([]string{"inspect", "imported-image"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ imageData := results.InspectImageJSON()
+ Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/bash"))
+ })
+
})
diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go
index 7f33fec87..2cd485114 100644
--- a/test/e2e/libpod_suite_remoteclient_test.go
+++ b/test/e2e/libpod_suite_remoteclient_test.go
@@ -36,7 +36,7 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
// PodmanNoCache calls podman with out adding the imagecache
func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration {
- podmanSession := p.PodmanBase(args, true, false)
+ podmanSession := p.PodmanBase(args, false, true)
return &PodmanSessionIntegration{podmanSession}
}
@@ -142,7 +142,7 @@ func (p *PodmanTestIntegration) StopVarlink() {
}
//MakeOptions assembles all the podman main options
-func (p *PodmanTestIntegration) makeOptions(args []string, noEvents bool) []string {
+func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache bool) []string {
return args
}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index 1df59dbe3..5239f4d8e 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -29,7 +29,7 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
// PodmanNoCache calls the podman command with no configured imagecache
func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration {
- podmanSession := p.PodmanBase(args, true, false)
+ podmanSession := p.PodmanBase(args, false, true)
return &PodmanSessionIntegration{podmanSession}
}
@@ -66,7 +66,7 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
}
// MakeOptions assembles all the podman main options
-func (p *PodmanTestIntegration) makeOptions(args []string, noEvents bool) []string {
+func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache bool) []string {
var debug string
if _, ok := os.LookupEnv("DEBUG"); ok {
debug = "--log-level=debug --syslog=true "
@@ -84,6 +84,11 @@ func (p *PodmanTestIntegration) makeOptions(args []string, noEvents bool) []stri
}
podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...)
+ if !noCache {
+ cacheOptions := []string{"--storage-opt",
+ fmt.Sprintf("%s.imagestore=%s", p.PodmanTest.ImageCacheFS, p.PodmanTest.ImageCacheDir)}
+ podmanOptions = append(cacheOptions, podmanOptions...)
+ }
podmanOptions = append(podmanOptions, args...)
return podmanOptions
}
diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go
index 3197aa655..dda83ba31 100644
--- a/test/e2e/mount_test.go
+++ b/test/e2e/mount_test.go
@@ -156,4 +156,124 @@ var _ = Describe("Podman mount", func() {
umount.WaitWithDefaultTimeout()
Expect(umount.ExitCode()).To(Equal(0))
})
+
+ It("podman list mounted container", func() {
+ setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ lmount := podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(Equal(""))
+
+ mount := podmanTest.Podman([]string{"mount", cid})
+ mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
+ lmount = podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(ContainSubstring(cid))
+
+ umount := podmanTest.Podman([]string{"umount", cid})
+ umount.WaitWithDefaultTimeout()
+ Expect(umount.ExitCode()).To(Equal(0))
+ })
+
+ It("podman list running container", func() {
+ SkipIfRootless()
+
+ setup := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ lmount := podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(ContainSubstring(cid))
+
+ stop := podmanTest.Podman([]string{"stop", cid})
+ stop.WaitWithDefaultTimeout()
+ Expect(stop.ExitCode()).To(Equal(0))
+
+ lmount = podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(Equal(""))
+ })
+
+ It("podman list mulitple mounted containers", func() {
+ SkipIfRootless()
+
+ setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid1 := setup.OutputToString()
+
+ setup = podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid2 := setup.OutputToString()
+
+ setup = podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid3 := setup.OutputToString()
+
+ lmount := podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(Equal(""))
+
+ mount := podmanTest.Podman([]string{"mount", cid1, cid3})
+ mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
+ lmount = podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(ContainSubstring(cid1))
+ Expect(lmount.OutputToString()).ToNot(ContainSubstring(cid2))
+ Expect(lmount.OutputToString()).To(ContainSubstring(cid3))
+
+ umount := podmanTest.Podman([]string{"umount", cid1, cid3})
+ umount.WaitWithDefaultTimeout()
+ Expect(umount.ExitCode()).To(Equal(0))
+
+ lmount = podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(Equal(""))
+
+ })
+
+ It("podman list mounted container", func() {
+ SkipIfRootless()
+
+ setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ lmount := podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(Equal(""))
+
+ mount := podmanTest.Podman([]string{"mount", cid})
+ mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
+ lmount = podmanTest.Podman([]string{"mount", "--notruncate"})
+ lmount.WaitWithDefaultTimeout()
+ Expect(lmount.ExitCode()).To(Equal(0))
+ Expect(lmount.OutputToString()).To(ContainSubstring(cid))
+
+ umount := podmanTest.Podman([]string{"umount", cid})
+ umount.WaitWithDefaultTimeout()
+ Expect(umount.ExitCode()).To(Equal(0))
+ })
})
diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go
index 410d0b97c..264219178 100644
--- a/test/e2e/network_create_test.go
+++ b/test/e2e/network_create_test.go
@@ -208,4 +208,10 @@ var _ = Describe("Podman network create", func() {
Expect(ncFail.ExitCode()).ToNot(BeZero())
})
+ It("podman network create with invalid network name", func() {
+ nc := podmanTest.Podman([]string{"network", "create", "foo "})
+ nc.WaitWithDefaultTimeout()
+ Expect(nc.ExitCode()).ToNot(BeZero())
+ })
+
})
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index fc1998ab2..bc3a14b66 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -270,4 +270,14 @@ var _ = Describe("Podman run with volumes", func() {
Expect(separateVolumeSession.ExitCode()).To(Equal(0))
Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
})
+
+ It("podman read-only tmpfs conflict with volume", func() {
+ session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:/run", ALPINE, "touch", "/run/a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session2 := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "--tmpfs", "/run", ALPINE, "touch", "/run/a"})
+ session2.WaitWithDefaultTimeout()
+ Expect(session2.ExitCode()).To(Equal(0))
+ })
})
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index fc1203ed1..06ab6aacd 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -6,6 +6,7 @@ import (
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman start", func() {
@@ -107,32 +108,30 @@ var _ = Describe("Podman start", func() {
start := podmanTest.Podman([]string{"start", "-l"})
start.WaitWithDefaultTimeout()
- Expect(start.ExitCode()).To(Not(Equal(0)))
+ Expect(start.ExitCode()).Should(BeNumerically(">", 0))
- numContainers := podmanTest.NumberOfContainers()
- Expect(numContainers).To(BeZero())
+ Eventually(podmanTest.NumberOfContainers(), defaultWaitTimeout).Should(BeZero())
})
It("podman failed to start without --rm should NOT delete the container", func() {
session := podmanTest.Podman([]string{"create", "-it", ALPINE, "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
start := podmanTest.Podman([]string{"start", "-l"})
start.WaitWithDefaultTimeout()
- Expect(start.ExitCode()).To(Not(Equal(0)))
+ Expect(start.ExitCode()).Should(BeNumerically(">", 0))
- numContainers := podmanTest.NumberOfContainers()
- Expect(numContainers).To(Equal(1))
+ Eventually(podmanTest.NumberOfContainers(), defaultWaitTimeout).Should(Equal(1))
})
It("podman start --sig-proxy should not work without --attach", func() {
session := podmanTest.Podman([]string{"create", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"start", "-l", "--sig-proxy"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(125))
+ Expect(session).Should(Exit(125))
})
})
diff --git a/test/system/005-info.bats b/test/system/005-info.bats
index 7fccc75af..5df6033fc 100644
--- a/test/system/005-info.bats
+++ b/test/system/005-info.bats
@@ -33,7 +33,7 @@ RunRoot:
run_podman info --format=json
expr_nvr="[a-z0-9-]\\\+-[a-z0-9.]\\\+-[a-z0-9]\\\+\."
- expr_path="/[a-z0-9\\\-\\\/.]\\\+\\\$"
+ expr_path="/[a-z0-9\\\/.-]\\\+\\\$"
tests="
host.BuildahVersion | [0-9.]
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 65e13d559..7cbb60501 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -3,7 +3,6 @@
load helpers
@test "podman run - basic tests" {
- skip "Temporarily disabled during investigation into github issue 4044"
rand=$(random_string 30)
# 2019-09 Fedora 31 and rawhide (32) are switching from runc to crun
@@ -28,6 +27,7 @@ echo $rand | 0 | $rand
/etc | 126 | $err_no_exec_dir
"
+ tests_run=0
while read cmd expected_rc expected_output; do
if [ "$expected_output" = "''" ]; then expected_output=""; fi
@@ -41,9 +41,24 @@ echo $rand | 0 | $rand
# a way to do so.
eval set "$cmd"
- run_podman $expected_rc run $IMAGE "$@"
- is "$output" "$expected_output" "podman run $cmd - output"
+ # FIXME: The </dev/null is a hack, necessary because as of 2019-09
+ # podman-remote has a bug in which it silently slurps up stdin,
+ # including the output of parse_table (i.e. tests to be run).
+ run_podman $expected_rc run $IMAGE "$@" </dev/null
+
+ # FIXME: remove conditional once podman-remote issue #4096 is fixed
+ if ! is_remote; then
+ is "$output" "$expected_output" "podman run $cmd - output"
+ fi
+
+ tests_run=$(expr $tests_run + 1)
done < <(parse_table "$tests")
+
+ # Make sure we ran the expected number of tests! Until 2019-09-24
+ # podman-remote was only running one test (the "true" one); all
+ # the rest were being silently ignored because of podman-remote
+ # bug #4095, in which it slurps up stdin.
+ is "$tests_run" "$(grep . <<<$tests | wc -l)" "Ran the full set of tests"
}
@test "podman run - uidmapping has no /sys/kernel mounts" {
diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats
index c13c8c52e..8ef8a119e 100644
--- a/test/system/055-rm.bats
+++ b/test/system/055-rm.bats
@@ -32,8 +32,6 @@ load helpers
#
# See https://github.com/containers/libpod/issues/3795
@test "podman rm -f" {
- skip_if_remote "podman-remote does not handle exit codes"
-
rand=$(random_string 30)
( sleep 3; run_podman rm -f $rand ) &
run_podman 137 run --name $rand $IMAGE sleep 30
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index 0ca730a50..0701055f9 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -38,7 +38,6 @@ load helpers
# 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"
- skip "BROKEN: PLEASE ENABLE ONCE #3829 GETS FIXED"
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
@@ -69,7 +68,6 @@ load helpers
# 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"
- skip "BROKEN: PLEASE ENABLE ONCE #3829 GETS FIXED"
srcdir=$PODMAN_TMPDIR/cp-test-in
dstdir=$PODMAN_TMPDIR/cp-test-out
@@ -144,12 +142,13 @@ load helpers
trap 'exit 0' 15;while :;do sleep 0.5;done"
# Copy file from host into container, into a file named 'x'
- # Note that the second has a trailing slash; this will trigger mkdir
+ # Note that the second has a trailing slash, implying a directory.
+ # Since that destination directory doesn't exist, the cp will fail
run_podman cp --pause=false $srcdir/$rand_filename1 cpcontainer:/tmp/d1/x
is "$output" "" "output from podman cp 1"
- run_podman cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/
- is "$output" "" "output from podman cp 3"
+ run_podman 125 cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/
+ is "$output" "Error: failed to get stat of dest path .*stat.* 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"
@@ -161,10 +160,8 @@ load helpers
run_podman exec cpcontainer cat /tmp/nonesuch1
is "$output" "$rand_content1" "cp creates destination file"
- # In the second case, podman creates a directory nonesuch2, then
- # creates a file with the same name as the input file. THIS IS WEIRD!
- run_podman exec cpcontainer cat /tmp/nonesuch2/$rand_filename2
- is "$output" "$rand_content2" "cp creates destination dir and file"
+ # cp into nonexistent directory should not mkdir nonesuch2 directory
+ run_podman 1 exec cpcontainer test -e /tmp/nonesuch2
# In the third case, podman (correctly imo) creates a file named 'x'
run_podman exec cpcontainer cat /tmp/d3/x
diff --git a/test/system/400-unprivileged-access.bats b/test/system/400-unprivileged-access.bats
index 738d8d87b..56c40e9c8 100644
--- a/test/system/400-unprivileged-access.bats
+++ b/test/system/400-unprivileged-access.bats
@@ -22,7 +22,7 @@ load helpers
# as a user, the parent directory must be world-readable.
test_script=$PODMAN_TMPDIR/fail-if-writable
cat >$test_script <<"EOF"
-#!/bin/sh
+#!/bin/bash
path="$1"
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 028107d46..7d373bd56 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -26,14 +26,14 @@ var (
// PodmanTestCommon contains common functions will be updated later in
// the inheritance structs
type PodmanTestCommon interface {
- MakeOptions(args []string, noEvents bool) []string
+ MakeOptions(args []string, noEvents, noCache bool) []string
WaitForContainer() bool
WaitContainerReady(id string, expStr string, timeout int, step int) bool
}
// PodmanTest struct for command line options
type PodmanTest struct {
- PodmanMakeOptions func(args []string, noEvents bool) []string
+ PodmanMakeOptions func(args []string, noEvents, noCache bool) []string
PodmanBinary string
ArtifactPath string
TempDir string
@@ -59,24 +59,20 @@ type HostOS struct {
}
// MakeOptions assembles all podman options
-func (p *PodmanTest) MakeOptions(args []string, noEvents bool) []string {
- return p.PodmanMakeOptions(args, noEvents)
+func (p *PodmanTest) MakeOptions(args []string, noEvents, noCache bool) []string {
+ return p.PodmanMakeOptions(args, noEvents, noCache)
}
// PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used
// to record the env for debugging
-func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, nocache, noEvents bool) *PodmanSession {
+func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool) *PodmanSession {
var command *exec.Cmd
- podmanOptions := p.MakeOptions(args, noEvents)
+ podmanOptions := p.MakeOptions(args, noEvents, noCache)
podmanBinary := p.PodmanBinary
if p.RemoteTest {
podmanBinary = p.RemotePodmanBinary
env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint))
}
- if !nocache && !p.RemoteTest {
- cacheOptions := []string{"--storage-opt", fmt.Sprintf("%s.imagestore=%s", p.ImageCacheFS, p.ImageCacheDir)}
- podmanOptions = append(cacheOptions, podmanOptions...)
- }
if env == nil {
fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " "))
@@ -105,8 +101,8 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
}
// PodmanBase exec podman with default env.
-func (p *PodmanTest) PodmanBase(args []string, nocache, noEvents bool) *PodmanSession {
- return p.PodmanAsUserBase(args, 0, 0, "", nil, nocache, noEvents)
+func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession {
+ return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache)
}
// WaitForContainer waits on a started container
@@ -124,7 +120,7 @@ func (p *PodmanTest) WaitForContainer() bool {
// containers are currently running.
func (p *PodmanTest) NumberOfContainersRunning() int {
var containers []string
- ps := p.PodmanBase([]string{"ps", "-q"}, true, false)
+ ps := p.PodmanBase([]string{"ps", "-q"}, false, true)
ps.WaitWithDefaultTimeout()
Expect(ps.ExitCode()).To(Equal(0))
for _, i := range ps.OutputToStringArray() {
@@ -139,7 +135,7 @@ func (p *PodmanTest) NumberOfContainersRunning() int {
// containers are currently defined.
func (p *PodmanTest) NumberOfContainers() int {
var containers []string
- ps := p.PodmanBase([]string{"ps", "-aq"}, true, false)
+ ps := p.PodmanBase([]string{"ps", "-aq"}, false, true)
ps.WaitWithDefaultTimeout()
Expect(ps.ExitCode()).To(Equal(0))
for _, i := range ps.OutputToStringArray() {
@@ -154,7 +150,7 @@ func (p *PodmanTest) NumberOfContainers() int {
// pods are currently defined.
func (p *PodmanTest) NumberOfPods() int {
var pods []string
- ps := p.PodmanBase([]string{"pod", "ps", "-q"}, true, false)
+ ps := p.PodmanBase([]string{"pod", "ps", "-q"}, false, true)
ps.WaitWithDefaultTimeout()
Expect(ps.ExitCode()).To(Equal(0))
for _, i := range ps.OutputToStringArray() {
@@ -170,7 +166,7 @@ func (p *PodmanTest) NumberOfPods() int {
func (p *PodmanTest) GetContainerStatus() string {
var podmanArgs = []string{"ps"}
podmanArgs = append(podmanArgs, "--all", "--format={{.Status}}")
- session := p.PodmanBase(podmanArgs, true, false)
+ session := p.PodmanBase(podmanArgs, false, true)
session.WaitWithDefaultTimeout()
return session.OutputToString()
}
@@ -178,7 +174,7 @@ func (p *PodmanTest) GetContainerStatus() string {
// WaitContainerReady waits process or service inside container start, and ready to be used.
func (p *PodmanTest) WaitContainerReady(id string, expStr string, timeout int, step int) bool {
startTime := time.Now()
- s := p.PodmanBase([]string{"logs", id}, true, false)
+ s := p.PodmanBase([]string{"logs", id}, false, true)
s.WaitWithDefaultTimeout()
for {
@@ -191,7 +187,7 @@ func (p *PodmanTest) WaitContainerReady(id string, expStr string, timeout int, s
return true
}
time.Sleep(time.Duration(step) * time.Second)
- s = p.PodmanBase([]string{"logs", id}, true, false)
+ s = p.PodmanBase([]string{"logs", id}, false, true)
s.WaitWithDefaultTimeout()
}
}
@@ -320,7 +316,7 @@ func (s *PodmanSession) IsJSONOutputValid() bool {
// WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout
func (s *PodmanSession) WaitWithDefaultTimeout() {
- s.Wait(defaultWaitTimeout)
+ Eventually(s, defaultWaitTimeout).Should(gexec.Exit())
os.Stdout.Sync()
os.Stderr.Sync()
fmt.Println("output:", s.OutputToString())
diff --git a/test/utils/utils_suite_test.go b/test/utils/utils_suite_test.go
index 5904d37dc..0cfa00e9c 100644
--- a/test/utils/utils_suite_test.go
+++ b/test/utils/utils_suite_test.go
@@ -32,7 +32,7 @@ func FakePodmanTestCreate() *FakePodmanTest {
return p
}
-func (p *FakePodmanTest) makeOptions(args []string, noEvents bool) []string {
+func (p *FakePodmanTest) makeOptions(args []string, noEvents, noCache bool) []string {
return FakeOutputs[strings.Join(args, " ")]
}
diff --git a/vendor/github.com/containernetworking/plugins/pkg/ip/link_linux.go b/vendor/github.com/containernetworking/plugins/pkg/ip/link_linux.go
index 909afd04e..c0053cabe 100644
--- a/vendor/github.com/containernetworking/plugins/pkg/ip/link_linux.go
+++ b/vendor/github.com/containernetworking/plugins/pkg/ip/link_linux.go
@@ -60,11 +60,15 @@ func peerExists(name string) bool {
return true
}
-func makeVeth(name string, mtu int) (peerName string, veth netlink.Link, err error) {
+func makeVeth(name, vethPeerName string, mtu int) (peerName string, veth netlink.Link, err error) {
for i := 0; i < 10; i++ {
- peerName, err = RandomVethName()
- if err != nil {
- return
+ if vethPeerName != "" {
+ peerName = vethPeerName
+ } else {
+ peerName, err = RandomVethName()
+ if err != nil {
+ return
+ }
}
veth, err = makeVethPair(name, peerName, mtu)
@@ -73,7 +77,7 @@ func makeVeth(name string, mtu int) (peerName string, veth netlink.Link, err err
return
case os.IsExist(err):
- if peerExists(peerName) {
+ if peerExists(peerName) && vethPeerName == "" {
continue
}
err = fmt.Errorf("container veth name provided (%v) already exists", name)
@@ -121,12 +125,13 @@ func ifaceFromNetlinkLink(l netlink.Link) net.Interface {
}
}
-// SetupVeth sets up a pair of virtual ethernet devices.
-// Call SetupVeth from inside the container netns. It will create both veth
+// SetupVethWithName sets up a pair of virtual ethernet devices.
+// Call SetupVethWithName from inside the container netns. It will create both veth
// devices and move the host-side veth into the provided hostNS namespace.
-// On success, SetupVeth returns (hostVeth, containerVeth, nil)
-func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
- hostVethName, contVeth, err := makeVeth(contVethName, mtu)
+// hostVethName: If hostVethName is not specified, the host-side veth name will use a random string.
+// On success, SetupVethWithName returns (hostVeth, containerVeth, nil)
+func SetupVethWithName(contVethName, hostVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
+ hostVethName, contVeth, err := makeVeth(contVethName, hostVethName, mtu)
if err != nil {
return net.Interface{}, net.Interface{}, err
}
@@ -161,6 +166,14 @@ func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, ne
return ifaceFromNetlinkLink(hostVeth), ifaceFromNetlinkLink(contVeth), nil
}
+// SetupVeth sets up a pair of virtual ethernet devices.
+// Call SetupVeth from inside the container netns. It will create both veth
+// devices and move the host-side veth into the provided hostNS namespace.
+// On success, SetupVeth returns (hostVeth, containerVeth, nil)
+func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
+ return SetupVethWithName(contVethName, "", mtu, hostNS)
+}
+
// DelLinkByName removes an interface link.
func DelLinkByName(ifName string) error {
iface, err := netlink.LinkByName(ifName)
diff --git a/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go b/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go
index d1c2b1018..4cec1a74e 100644
--- a/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go
+++ b/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go
@@ -40,7 +40,7 @@ func NewIPAllocator(s *RangeSet, store backend.Store, id int) *IPAllocator {
}
}
-// Get alocates an IP
+// Get allocates an IP
func (a *IPAllocator) Get(id string, ifname string, requestedIP net.IP) (*current.IPConfig, error) {
a.store.Lock()
defer a.store.Unlock()
@@ -73,6 +73,17 @@ func (a *IPAllocator) Get(id string, ifname string, requestedIP net.IP) (*curren
gw = r.Gateway
} else {
+ // try to get allocated IPs for this given id, if exists, just return error
+ // because duplicate allocation is not allowed in SPEC
+ // https://github.com/containernetworking/cni/blob/master/SPEC.md
+ allocatedIPs := a.store.GetByID(id, ifname)
+ for _, allocatedIP := range allocatedIPs {
+ // check whether the existing IP belong to this range set
+ if _, err := a.rangeset.RangeFor(allocatedIP); err == nil {
+ return nil, fmt.Errorf("%s has been allocated to %s, duplicate allocation is not allowed", allocatedIP.String(), id)
+ }
+ }
+
iter, err := a.GetIter()
if err != nil {
return nil, err
diff --git a/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go b/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go
index 4ea845da7..7211ddf6a 100644
--- a/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go
+++ b/vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go
@@ -24,4 +24,5 @@ type Store interface {
LastReservedIP(rangeID string) (net.IP, error)
Release(ip net.IP) error
ReleaseByID(id string, ifname string) error
+ GetByID(id string, ifname string) []net.IP
}
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 01b756823..80138e714 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.13.3
+1.13.4
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index 6b40ebd59..539acfe93 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: images.go
+// source: ./images.go
package storage
diff --git a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
index 98d3ee96a..c6985d757 100644
--- a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
+++ b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
@@ -26,7 +26,6 @@ func NewLogger(logger func(*tar.Header)) (io.WriteCloser, error) {
closed: false,
}
tr := tar.NewReader(reader)
- tr.RawAccounting = true
t.closeMutex.Lock()
go func() {
hdr, err := tr.Next()
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index dd3405212..af69a4b2d 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -1502,6 +1502,7 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
if err != nil {
return nil, err
}
+ foundImage := false
for _, s := range append([]ROImageStore{istore}, istores...) {
store := s
store.RLock()
@@ -1515,6 +1516,12 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
if err == nil {
return data, nil
}
+ if store.Exists(id) {
+ foundImage = true
+ }
+ }
+ if foundImage {
+ return nil, errors.Wrapf(os.ErrNotExist, "error locating item named %q for image with ID %q", key, id)
}
return nil, errors.Wrapf(ErrImageUnknown, "error locating image with ID %q", id)
}
@@ -1587,10 +1594,12 @@ func (s *store) ImageSize(id string) (int64, error) {
return -1, errors.Wrapf(ErrImageUnknown, "error locating image with ID %q", id)
}
- // Start with a list of the image's top layers.
+ // Start with a list of the image's top layers, if it has any.
queue := make(map[string]struct{})
for _, layerID := range append([]string{image.TopLayer}, image.MappedTopLayers...) {
- queue[layerID] = struct{}{}
+ if layerID != "" {
+ queue[layerID] = struct{}{}
+ }
}
visited := make(map[string]struct{})
// Walk all of the layers.
diff --git a/vendor/github.com/docker/docker-credential-helpers/credentials/version.go b/vendor/github.com/docker/docker-credential-helpers/credentials/version.go
index ecc23e68b..c2cc3e2e0 100644
--- a/vendor/github.com/docker/docker-credential-helpers/credentials/version.go
+++ b/vendor/github.com/docker/docker-credential-helpers/credentials/version.go
@@ -1,4 +1,4 @@
package credentials
// Version holds a string describing the current version
-const Version = "0.6.2"
+const Version = "0.6.3"
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index 4920406ae..aeadb66e0 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,29 @@
+## 1.10.1
+
+## Fixes
+- stack backtrace: fix skipping (#600) [2a4c0bd]
+
+## 1.10.0
+
+## Fixes
+- stack backtrace: fix alignment and skipping [66915d6]
+- fix typo in documentation [8f97b93]
+
+## 1.9.0
+
+## Features
+- Option to print output into report, when tests have passed [0545415]
+
+## Fixes
+- Fixed typos in comments [0ecbc58]
+- gofmt code [a7f8bfb]
+- Simplify code [7454d00]
+- Simplify concatenation, incrementation and function assignment [4825557]
+- Avoid unnecessary conversions [9d9403c]
+- JUnit: include more detailed information about panic [19cca4b]
+- Print help to stdout when the user asks for help [4cb7441]
+
+
## 1.8.0
### New Features
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index dab2a2470..ac55a5ad2 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,7 +20,7 @@ import (
"fmt"
)
-const VERSION = "1.8.0"
+const VERSION = "1.10.1"
type GinkgoConfigType struct {
RandomSeed int64
@@ -52,13 +52,14 @@ type DefaultReporterConfigType struct {
Succinct bool
Verbose bool
FullTrace bool
+ ReportPassed bool
}
var DefaultReporterConfig = DefaultReporterConfigType{}
func processPrefix(prefix string) string {
if prefix != "" {
- prefix = prefix + "."
+ prefix += "."
}
return prefix
}
@@ -98,6 +99,7 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.")
flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report")
flagSet.BoolVar(&(DefaultReporterConfig.FullTrace), prefix+"trace", false, "If set, default reporter prints out the full stack trace when a failure occurs")
+ flagSet.BoolVar(&(DefaultReporterConfig.ReportPassed), prefix+"reportPassed", false, "If set, default reporter prints out captured output of passed tests.")
}
func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultReporterConfigType) []string {
@@ -196,5 +198,9 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
result = append(result, fmt.Sprintf("--%strace", prefix))
}
+ if reporter.ReportPassed {
+ result = append(result, fmt.Sprintf("--%sreportPassed", prefix))
+ }
+
return result
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go
index fea4d4d4e..93150d1a4 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go
@@ -131,10 +131,7 @@ func determinePackageName(name string, internal bool) string {
func fileExists(path string) bool {
_, err := os.Stat(path)
- if err == nil {
- return true
- }
- return false
+ return err == nil
}
func generateBootstrap(agouti, noDot, internal bool, customBootstrapFile string) {
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/convert/import.go b/vendor/github.com/onsi/ginkgo/ginkgo/convert/import.go
index e226196f7..06c6ec94c 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/convert/import.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/convert/import.go
@@ -1,7 +1,6 @@
package convert
import (
- "errors"
"fmt"
"go/ast"
)
@@ -24,7 +23,7 @@ func importsForRootNode(rootNode *ast.File) (imports *ast.GenDecl, err error) {
}
}
- err = errors.New(fmt.Sprintf("Could not find imports for root node:\n\t%#v\n", rootNode))
+ err = fmt.Errorf("Could not find imports for root node:\n\t%#v\n", rootNode)
return
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/convert/package_rewriter.go b/vendor/github.com/onsi/ginkgo/ginkgo/convert/package_rewriter.go
index ed09c460d..5e00d5618 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/convert/package_rewriter.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/convert/package_rewriter.go
@@ -24,7 +24,6 @@ func RewritePackage(packageName string) {
for _, filename := range findTestsInPackage(pkg) {
rewriteTestsInFile(filename)
}
- return
}
/*
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/convert/testfile_rewriter.go b/vendor/github.com/onsi/ginkgo/ginkgo/convert/testfile_rewriter.go
index 4b001a7db..d415050ef 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/convert/testfile_rewriter.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/convert/testfile_rewriter.go
@@ -61,7 +61,6 @@ func rewriteTestsInFile(pathToFile string) {
}
ioutil.WriteFile(pathToFile, buffer.Bytes(), fileInfo.Mode())
- return
}
/*
@@ -88,7 +87,6 @@ func rewriteTestFuncAsItStatement(testFunc *ast.FuncDecl, rootNode *ast.File, de
// remove the old test func from the root node's declarations
rootNode.Decls = append(rootNode.Decls[:funcIndex], rootNode.Decls[funcIndex+1:]...)
- return
}
/*
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/interrupthandler/interrupt_handler.go b/vendor/github.com/onsi/ginkgo/ginkgo/interrupthandler/interrupt_handler.go
index c15db0b02..ec456bf29 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/interrupthandler/interrupt_handler.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/interrupthandler/interrupt_handler.go
@@ -16,7 +16,7 @@ type InterruptHandler struct {
func NewInterruptHandler() *InterruptHandler {
h := &InterruptHandler{
lock: &sync.Mutex{},
- C: make(chan bool, 0),
+ C: make(chan bool),
}
go h.handleInterrupt()
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/main.go b/vendor/github.com/onsi/ginkgo/ginkgo/main.go
index 4a1aeef4f..0741ba8c9 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/main.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/main.go
@@ -153,6 +153,7 @@ func (c *Command) Matches(name string) bool {
}
func (c *Command) Run(args []string, additionalArgs []string) {
+ c.FlagSet.Usage = usage
c.FlagSet.Parse(args)
c.Command(c.FlagSet.Args(), additionalArgs)
}
@@ -215,20 +216,21 @@ func commandMatching(name string) (*Command, bool) {
}
func usage() {
- fmt.Fprintf(os.Stderr, "Ginkgo Version %s\n\n", config.VERSION)
+ fmt.Printf("Ginkgo Version %s\n\n", config.VERSION)
usageForCommand(DefaultCommand, false)
for _, command := range Commands {
- fmt.Fprintf(os.Stderr, "\n")
+ fmt.Printf("\n")
usageForCommand(command, false)
}
}
func usageForCommand(command *Command, longForm bool) {
- fmt.Fprintf(os.Stderr, "%s\n%s\n", command.UsageCommand, strings.Repeat("-", len(command.UsageCommand)))
- fmt.Fprintf(os.Stderr, "%s\n", strings.Join(command.Usage, "\n"))
+ fmt.Printf("%s\n%s\n", command.UsageCommand, strings.Repeat("-", len(command.UsageCommand)))
+ fmt.Printf("%s\n", strings.Join(command.Usage, "\n"))
if command.SuppressFlagDocumentation && !longForm {
- fmt.Fprintf(os.Stderr, "%s\n", strings.Join(command.FlagDocSubstitute, "\n "))
+ fmt.Printf("%s\n", strings.Join(command.FlagDocSubstitute, "\n "))
} else {
+ command.FlagSet.SetOutput(os.Stdout)
command.FlagSet.PrintDefaults()
}
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/suite_runner.go b/vendor/github.com/onsi/ginkgo/ginkgo/suite_runner.go
index ce6c94602..ab746d7e9 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/suite_runner.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/suite_runner.go
@@ -41,7 +41,7 @@ func (r *SuiteRunner) compileInParallel(runners []*testrunner.TestRunner, numCom
//an array of channels - the nth runner's compilation output is sent to the nth channel in this array
//we read from these channels in order to ensure we run the suites in order
orderedCompilationOutputs := []chan compilationOutput{}
- for _ = range runners {
+ for range runners {
orderedCompilationOutputs = append(orderedCompilationOutputs, make(chan compilationOutput, 1))
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go b/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go
index dccb39518..80670d24a 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go
@@ -156,7 +156,7 @@ func (t *TestRunner) CompileTo(path string) error {
fmt.Println(string(output))
}
- if fileExists(path) == false {
+ if !fileExists(path) {
compiledFile := t.Suite.PackageName + ".test"
if fileExists(compiledFile) {
// seems like we are on an old go version that does not support the -o flag on go test
@@ -182,7 +182,7 @@ func (t *TestRunner) CompileTo(path string) error {
func fileExists(path string) bool {
_, err := os.Stat(path)
- return err == nil || os.IsNotExist(err) == false
+ return err == nil || !os.IsNotExist(err)
}
// copyFile copies the contents of the file named src to the file named
@@ -523,7 +523,7 @@ func (t *TestRunner) combineCoverprofiles() {
lines := map[string]int{}
lineOrder := []string{}
for i, coverProfile := range profiles {
- for _, line := range strings.Split(string(coverProfile), "\n")[1:] {
+ for _, line := range strings.Split(coverProfile, "\n")[1:] {
if len(line) == 0 {
continue
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/watch/dependencies.go b/vendor/github.com/onsi/ginkgo/ginkgo/watch/dependencies.go
index 82c25face..b7f756777 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/watch/dependencies.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/watch/dependencies.go
@@ -77,7 +77,7 @@ func (d Dependencies) resolveAndAdd(deps []string, depth int) {
if err != nil {
continue
}
- if pkg.Goroot == false && !ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) {
+ if !pkg.Goroot && !ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) {
d.addDepIfNotPresent(pkg.Dir, depth)
}
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/watch/package_hash.go b/vendor/github.com/onsi/ginkgo/ginkgo/watch/package_hash.go
index 7e1e4192d..67e2c1c32 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/watch/package_hash.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/watch/package_hash.go
@@ -36,7 +36,7 @@ func (p *PackageHash) CheckForChanges() bool {
codeHash, codeModifiedTime, testHash, testModifiedTime, deleted := p.computeHashes()
if deleted {
- if p.Deleted == false {
+ if !p.Deleted {
t := time.Now()
p.CodeModifiedTime = t
p.TestModifiedTime = t
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
index a6b96d88f..8734c061d 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
@@ -283,7 +283,7 @@ func GinkgoRecover() {
//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
//
//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally
-//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
+//equivalent. The difference is purely semantic -- you typically Describe the behavior of an object
//or method and, within that Describe, outline a number of Contexts and Whens.
func Describe(text string, body func()) bool {
globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
@@ -499,7 +499,7 @@ func AfterSuite(body interface{}, timeout ...float64) bool {
//until that node is done before running.
//
//SynchronizedBeforeSuite accomplishes this by taking *two* function arguments. The first is only run on parallel node #1. The second is
-//run on all nodes, but *only* after the first function completes succesfully. Ginkgo also makes it possible to send data from the first function (on Node 1)
+//run on all nodes, but *only* after the first function completes successfully. Ginkgo also makes it possible to send data from the first function (on Node 1)
//to the second function (on all the other nodes).
//
//The functions have the following signatures. The first function (which only runs on node 1) has the signature:
diff --git a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location.go b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location.go
index fa2f0bf73..aa89d6cba 100644
--- a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location.go
+++ b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location.go
@@ -11,19 +11,35 @@ import (
func New(skip int) types.CodeLocation {
_, file, line, _ := runtime.Caller(skip + 1)
- stackTrace := PruneStack(string(debug.Stack()), skip)
+ stackTrace := PruneStack(string(debug.Stack()), skip+1)
return types.CodeLocation{FileName: file, LineNumber: line, FullStackTrace: stackTrace}
}
+// PruneStack removes references to functions that are internal to Ginkgo
+// and the Go runtime from a stack string and a certain number of stack entries
+// at the beginning of the stack. The stack string has the format
+// as returned by runtime/debug.Stack. The leading goroutine information is
+// optional and always removed if present. Beware that runtime/debug.Stack
+// adds itself as first entry, so typically skip must be >= 1 to remove that
+// entry.
func PruneStack(fullStackTrace string, skip int) string {
stack := strings.Split(fullStackTrace, "\n")
+ // Ensure that the even entries are the method names and the
+ // the odd entries the source code information.
+ if len(stack) > 0 && strings.HasPrefix(stack[0], "goroutine ") {
+ // Ignore "goroutine 29 [running]:" line.
+ stack = stack[1:]
+ }
+ // The "+1" is for skipping over the initial entry, which is
+ // runtime/debug.Stack() itself.
if len(stack) > 2*(skip+1) {
stack = stack[2*(skip+1):]
}
prunedStack := []string{}
re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
for i := 0; i < len(stack)/2; i++ {
- if !re.Match([]byte(stack[i*2])) {
+ // We filter out based on the source code file name.
+ if !re.Match([]byte(stack[i*2+1])) {
prunedStack = append(prunedStack, stack[i*2])
prunedStack = append(prunedStack, stack[i*2+1])
}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go
index d6d54234c..393901e11 100644
--- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go
@@ -17,7 +17,7 @@ type benchmarker struct {
func newBenchmarker() *benchmarker {
return &benchmarker{
- measurements: make(map[string]*types.SpecMeasurement, 0),
+ measurements: make(map[string]*types.SpecMeasurement),
}
}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go
index 6b54afe01..f9ab30067 100644
--- a/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go
+++ b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go
@@ -54,11 +54,11 @@ func NewAggregator(nodeCount int, result chan bool, config config.DefaultReporte
config: config,
stenographer: stenographer,
- suiteBeginnings: make(chan configAndSuite, 0),
- beforeSuites: make(chan *types.SetupSummary, 0),
- afterSuites: make(chan *types.SetupSummary, 0),
- specCompletions: make(chan *types.SpecSummary, 0),
- suiteEndings: make(chan *types.SuiteSummary, 0),
+ suiteBeginnings: make(chan configAndSuite),
+ beforeSuites: make(chan *types.SetupSummary),
+ afterSuites: make(chan *types.SetupSummary),
+ specCompletions: make(chan *types.SpecSummary),
+ suiteEndings: make(chan *types.SuiteSummary),
}
go aggregator.mux()
@@ -227,7 +227,7 @@ func (aggregator *Aggregator) registerSuiteEnding(suite *types.SuiteSummary) (fi
aggregatedSuiteSummary.SuiteSucceeded = true
for _, suiteSummary := range aggregator.aggregatedSuiteEndings {
- if suiteSummary.SuiteSucceeded == false {
+ if !suiteSummary.SuiteSucceeded {
aggregatedSuiteSummary.SuiteSucceeded = false
}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/server.go b/vendor/github.com/onsi/ginkgo/internal/remote/server.go
index 367c54daf..93e9dac05 100644
--- a/vendor/github.com/onsi/ginkgo/internal/remote/server.go
+++ b/vendor/github.com/onsi/ginkgo/internal/remote/server.go
@@ -213,7 +213,7 @@ func (server *Server) handleCounter(writer http.ResponseWriter, request *http.Re
c := spec_iterator.Counter{}
server.lock.Lock()
c.Index = server.counter
- server.counter = server.counter + 1
+ server.counter++
server.lock.Unlock()
json.NewEncoder(writer).Encode(c)
diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/spec.go b/vendor/github.com/onsi/ginkgo/internal/spec/spec.go
index 7fd68ee8e..6eef40a0e 100644
--- a/vendor/github.com/onsi/ginkgo/internal/spec/spec.go
+++ b/vendor/github.com/onsi/ginkgo/internal/spec/spec.go
@@ -107,11 +107,11 @@ func (spec *Spec) Summary(suiteID string) *types.SpecSummary {
NumberOfSamples: spec.subject.Samples(),
ComponentTexts: componentTexts,
ComponentCodeLocations: componentCodeLocations,
- State: spec.getState(),
- RunTime: runTime,
- Failure: spec.failure,
- Measurements: spec.measurementsReport(),
- SuiteID: suiteID,
+ State: spec.getState(),
+ RunTime: runTime,
+ Failure: spec.failure,
+ Measurements: spec.measurementsReport(),
+ SuiteID: suiteID,
}
}
diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/specs.go b/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
index 27c0d1d6c..8a2007137 100644
--- a/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
+++ b/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
@@ -107,11 +107,11 @@ func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string,
toMatch := e.toMatch(description, i)
if focusFilter != nil {
- matchesFocus = focusFilter.Match([]byte(toMatch))
+ matchesFocus = focusFilter.Match(toMatch)
}
if skipFilter != nil {
- matchesSkip = skipFilter.Match([]byte(toMatch))
+ matchesSkip = skipFilter.Match(toMatch)
}
if !matchesFocus || matchesSkip {
diff --git a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go
index 2c683cb8b..c9a0a60d8 100644
--- a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go
+++ b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go
@@ -300,7 +300,7 @@ func (runner *SpecRunner) reportSpecWillRun(summary *types.SpecSummary) {
}
func (runner *SpecRunner) reportSpecDidComplete(summary *types.SpecSummary, failed bool) {
- if failed && len(summary.CapturedOutput) == 0 {
+ if len(summary.CapturedOutput) == 0 {
summary.CapturedOutput = string(runner.writer.Bytes())
}
for i := len(runner.reporters) - 1; i >= 1; i-- {
diff --git a/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go
index ac58dd5f7..c76283b46 100644
--- a/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go
+++ b/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go
@@ -62,6 +62,9 @@ func (reporter *DefaultReporter) SpecDidComplete(specSummary *types.SpecSummary)
reporter.stenographer.AnnounceSuccesfulSlowSpec(specSummary, reporter.config.Succinct)
} else {
reporter.stenographer.AnnounceSuccesfulSpec(specSummary)
+ if reporter.config.ReportPassed {
+ reporter.stenographer.AnnounceCapturedOutput(specSummary.CapturedOutput)
+ }
}
case types.SpecStatePending:
reporter.stenographer.AnnouncePendingSpec(specSummary, reporter.config.NoisyPendings && !reporter.config.Succinct)
diff --git a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
index 2c9f3c792..89a7c8465 100644
--- a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
+++ b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
@@ -32,12 +32,17 @@ type JUnitTestSuite struct {
type JUnitTestCase struct {
Name string `xml:"name,attr"`
ClassName string `xml:"classname,attr"`
+ PassedMessage *JUnitPassedMessage `xml:"passed,omitempty"`
FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"`
Skipped *JUnitSkipped `xml:"skipped,omitempty"`
Time float64 `xml:"time,attr"`
SystemOut string `xml:"system-out,omitempty"`
}
+type JUnitPassedMessage struct {
+ Message string `xml:",chardata"`
+}
+
type JUnitFailureMessage struct {
Type string `xml:"type,attr"`
Message string `xml:",chardata"`
@@ -48,9 +53,10 @@ type JUnitSkipped struct {
}
type JUnitReporter struct {
- suite JUnitTestSuite
- filename string
- testSuiteName string
+ suite JUnitTestSuite
+ filename string
+ testSuiteName string
+ ReporterConfig config.DefaultReporterConfigType
}
//NewJUnitReporter creates a new JUnit XML reporter. The XML will be stored in the passed in filename.
@@ -60,12 +66,13 @@ func NewJUnitReporter(filename string) *JUnitReporter {
}
}
-func (reporter *JUnitReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
+func (reporter *JUnitReporter) SpecSuiteWillBegin(ginkgoConfig config.GinkgoConfigType, summary *types.SuiteSummary) {
reporter.suite = JUnitTestSuite{
Name: summary.SuiteDescription,
TestCases: []JUnitTestCase{},
}
reporter.testSuiteName = summary.SuiteDescription
+ reporter.ReporterConfig = config.DefaultReporterConfig
}
func (reporter *JUnitReporter) SpecWillRun(specSummary *types.SpecSummary) {
@@ -105,11 +112,21 @@ func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
Name: strings.Join(specSummary.ComponentTexts[1:], " "),
ClassName: reporter.testSuiteName,
}
+ if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed {
+ testCase.PassedMessage = &JUnitPassedMessage{
+ Message: specSummary.CapturedOutput,
+ }
+ }
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
testCase.FailureMessage = &JUnitFailureMessage{
Type: reporter.failureTypeForState(specSummary.State),
Message: failureMessage(specSummary.Failure),
}
+ if specSummary.State == types.SpecStatePanicked {
+ testCase.FailureMessage.Message += fmt.Sprintf("\n\nPanic: %s\n\nFull stack:\n%s",
+ specSummary.Failure.ForwardedPanic,
+ specSummary.Failure.Location.FullStackTrace)
+ }
testCase.SystemOut = specSummary.CapturedOutput
}
if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending {
diff --git a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go
index 36ee2a600..c8e27b2a7 100644
--- a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go
+++ b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go
@@ -22,8 +22,9 @@ const (
)
type TeamCityReporter struct {
- writer io.Writer
- testSuiteName string
+ writer io.Writer
+ testSuiteName string
+ ReporterConfig config.DefaultReporterConfigType
}
func NewTeamCityReporter(writer io.Writer) *TeamCityReporter {
@@ -65,6 +66,10 @@ func (reporter *TeamCityReporter) SpecWillRun(specSummary *types.SpecSummary) {
func (reporter *TeamCityReporter) SpecDidComplete(specSummary *types.SpecSummary) {
testName := escape(strings.Join(specSummary.ComponentTexts[1:], " "))
+ if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed {
+ details := escape(specSummary.CapturedOutput)
+ fmt.Fprintf(reporter.writer, "%s[testPassed name='%s' details='%s']", messageId, testName, details)
+ }
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
message := escape(specSummary.Failure.ComponentCodeLocation.String())
details := escape(specSummary.Failure.Message)
diff --git a/vendor/github.com/onsi/ginkgo/types/types.go b/vendor/github.com/onsi/ginkgo/types/types.go
index 0e89521be..e4e32b761 100644
--- a/vendor/github.com/onsi/ginkgo/types/types.go
+++ b/vendor/github.com/onsi/ginkgo/types/types.go
@@ -17,7 +17,7 @@ each node does not deterministically know how many specs it will end up running.
Unfortunately making such a change would break backward compatibility.
-Until Ginkgo 2.0 comes out we will continue to reuse this struct but populate unkown fields
+Until Ginkgo 2.0 comes out we will continue to reuse this struct but populate unknown fields
with -1.
*/
type SuiteSummary struct {
diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml
index 2420a5d07..d147e451d 100644
--- a/vendor/github.com/onsi/gomega/.travis.yml
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -4,6 +4,7 @@ go:
- 1.10.x
- 1.11.x
- 1.12.x
+ - gotip
env:
- GO111MODULE=on
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 5d1eda837..f67074016 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,35 @@
+## 1.7.0
+
+### Features
+- export format property variables (#347) [642e5ba]
+
+### Fixes
+- minor fix in the documentation of ExpectWithOffset (#358) [beea727]
+
+## 1.6.0
+
+### Features
+
+- Display special chars on error [41e1b26]
+- Add BeElementOf matcher [6a48b48]
+
+### Fixes
+
+- Remove duplication in XML matcher tests [cc1a6cb]
+- Remove unnecessary conversions (#357) [7bf756a]
+- Fixed import order (#353) [2e3b965]
+- Added missing error handling in test (#355) [c98d3eb]
+- Simplify code (#356) [0001ed9]
+- Simplify code (#354) [0d9100e]
+- Fixed typos (#352) [3f647c4]
+- Add failure message tests to BeElementOf matcher [efe19c3]
+- Update go-testcov untested sections [37ee382]
+- Mark all uncovered files so go-testcov ./... works [53b150e]
+- Reenable gotip in travis [5c249dc]
+- Fix the typo of comment (#345) [f0e010e]
+- Optimize contain_element_matcher [abeb93d]
+
+
## 1.5.0
### Features
diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go
index 6559525f1..fae25adce 100644
--- a/vendor/github.com/onsi/gomega/format/format.go
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -1,6 +1,9 @@
/*
Gomega's format package pretty-prints objects. It explores input objects recursively and generates formatted, indented output with type information.
*/
+
+// untested sections: 4
+
package format
import (
@@ -33,7 +36,15 @@ var PrintContextObjects = false
// TruncatedDiff choose if we should display a truncated pretty diff or not
var TruncatedDiff = true
-// Ctx interface defined here to keep backwards compatability with go < 1.7
+// TruncateThreshold (default 50) specifies the maximum length string to print in string comparison assertion error
+// messages.
+var TruncateThreshold uint = 50
+
+// CharactersAroundMismatchToInclude (default 5) specifies how many contextual characters should be printed before and
+// after the first diff location in a truncated string assertion error message.
+var CharactersAroundMismatchToInclude uint = 5
+
+// Ctx interface defined here to keep backwards compatibility with go < 1.7
// It matches the context.Context interface
type Ctx interface {
Deadline() (deadline time.Time, ok bool)
@@ -58,7 +69,7 @@ Generates a formatted matcher success/failure message of the form:
<message>
<pretty printed expected>
-If expected is omited, then the message looks like:
+If expected is omitted, then the message looks like:
Expected
<pretty printed actual>
@@ -85,7 +96,7 @@ to equal |
*/
func MessageWithDiff(actual, message, expected string) string {
- if TruncatedDiff && len(actual) >= truncateThreshold && len(expected) >= truncateThreshold {
+ if TruncatedDiff && len(actual) >= int(TruncateThreshold) && len(expected) >= int(TruncateThreshold) {
diffPoint := findFirstMismatch(actual, expected)
formattedActual := truncateAndFormat(actual, diffPoint)
formattedExpected := truncateAndFormat(expected, diffPoint)
@@ -97,14 +108,23 @@ func MessageWithDiff(actual, message, expected string) string {
padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
return Message(formattedActual, message+padding, formattedExpected)
}
+
+ actual = escapedWithGoSyntax(actual)
+ expected = escapedWithGoSyntax(expected)
+
return Message(actual, message, expected)
}
+func escapedWithGoSyntax(str string) string {
+ withQuotes := fmt.Sprintf("%q", str)
+ return withQuotes[1 : len(withQuotes)-1]
+}
+
func truncateAndFormat(str string, index int) string {
leftPadding := `...`
rightPadding := `...`
- start := index - charactersAroundMismatchToInclude
+ start := index - int(CharactersAroundMismatchToInclude)
if start < 0 {
start = 0
leftPadding = ""
@@ -112,7 +132,7 @@ func truncateAndFormat(str string, index int) string {
// slice index must include the mis-matched character
lengthOfMismatchedCharacter := 1
- end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter
+ end := index + int(CharactersAroundMismatchToInclude) + lengthOfMismatchedCharacter
if end > len(str) {
end = len(str)
rightPadding = ""
@@ -141,11 +161,6 @@ func findFirstMismatch(a, b string) int {
return 0
}
-const (
- truncateThreshold = 50
- charactersAroundMismatchToInclude = 5
-)
-
/*
Pretty prints the passed in object at the passed in indentation level.
@@ -288,7 +303,7 @@ func formatString(object interface{}, indentation uint) string {
}
}
- return fmt.Sprintf("%s", result)
+ return result
} else {
return fmt.Sprintf("%q", object)
}
diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
index 14317182b..0763f5e2d 100644
--- a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
+++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 1
+
package gbytes
import (
@@ -19,7 +21,7 @@ Say is a Gomega matcher that operates on gbytes.Buffers:
will succeed if the unread portion of the buffer matches the regular expression "something".
-When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the succesful match.
+When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the successful match.
Thus, subsequent calls to Say will only match against the unread portion of the buffer
Say pairs very well with Eventually. To assert that a buffer eventually receives data matching "[123]-star" within 3 seconds you can:
diff --git a/vendor/github.com/onsi/gomega/gexec/build.go b/vendor/github.com/onsi/gomega/gexec/build.go
index 869c1ead8..741d845f4 100644
--- a/vendor/github.com/onsi/gomega/gexec/build.go
+++ b/vendor/github.com/onsi/gomega/gexec/build.go
@@ -1,3 +1,5 @@
+// untested sections: 5
+
package gexec
import (
@@ -66,7 +68,7 @@ func doBuild(gopath, packagePath string, env []string, args ...string) (compiled
executable := filepath.Join(tmpDir, path.Base(packagePath))
if runtime.GOOS == "windows" {
- executable = executable + ".exe"
+ executable += ".exe"
}
cmdArgs := append([]string{"build"}, args...)
diff --git a/vendor/github.com/onsi/gomega/gexec/exit_matcher.go b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
index 98a354937..6e70de68d 100644
--- a/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
+++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package gexec
import (
diff --git a/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go b/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go
index 05e695abc..feb6620c5 100644
--- a/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go
+++ b/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go
@@ -1,3 +1,5 @@
+// untested sections: 1
+
package gexec
import (
@@ -6,7 +8,7 @@ import (
)
/*
-PrefixedWriter wraps an io.Writer, emiting the passed in prefix at the beginning of each new line.
+PrefixedWriter wraps an io.Writer, emitting the passed in prefix at the beginning of each new line.
This can be useful when running multiple gexec.Sessions concurrently - you can prefix the log output of each
session by passing in a PrefixedWriter:
diff --git a/vendor/github.com/onsi/gomega/gexec/session.go b/vendor/github.com/onsi/gomega/gexec/session.go
index 5cb00ca65..6a09140fb 100644
--- a/vendor/github.com/onsi/gomega/gexec/session.go
+++ b/vendor/github.com/onsi/gomega/gexec/session.go
@@ -1,6 +1,9 @@
/*
Package gexec provides support for testing external processes.
*/
+
+// untested sections: 1
+
package gexec
import (
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 448d595da..b145768cf 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.5.0"
+const GOMEGA_VERSION = "1.7.0"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
@@ -155,7 +155,7 @@ func Expect(actual interface{}, extra ...interface{}) Assertion {
// ExpectWithOffset(1, "foo").To(Equal("foo"))
//
// Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument
-// this is used to modify the call-stack offset when computing line numbers.
+// that is used to modify the call-stack offset when computing line numbers.
//
// This is most useful in helper functions that make assertions. If you want Gomega's
// error message to refer to the calling line in the test (as opposed to the line in the helper function)
@@ -242,7 +242,7 @@ func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface
// assert that all other values are nil/zero.
// This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go.
//
-// Consistently is useful in cases where you want to assert that something *does not happen* over a period of tiem.
+// Consistently is useful in cases where you want to assert that something *does not happen* over a period of time.
// For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could:
//
// Consistently(channel).ShouldNot(Receive())
@@ -280,7 +280,7 @@ func SetDefaultEventuallyPollingInterval(t time.Duration) {
defaultEventuallyPollingInterval = t
}
-// SetDefaultConsistentlyDuration sets the default duration for Consistently. Consistently will verify that your condition is satsified for this long.
+// SetDefaultConsistentlyDuration sets the default duration for Consistently. Consistently will verify that your condition is satisfied for this long.
func SetDefaultConsistentlyDuration(t time.Duration) {
defaultConsistentlyDuration = t
}
@@ -320,7 +320,7 @@ type GomegaAsyncAssertion = AsyncAssertion
// All methods take a variadic optionalDescription argument. This is passed on to fmt.Sprintf()
// and is used to annotate failure messages.
//
-// All methods return a bool that is true if hte assertion passed and false if it failed.
+// All methods return a bool that is true if the assertion passed and false if it failed.
//
// Example:
//
diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
index cdab233eb..a233e48c0 100644
--- a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package asyncassertion
import (
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
index c3a326dd4..9ec8893cb 100644
--- a/vendor/github.com/onsi/gomega/matchers.go
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -269,6 +269,22 @@ func ContainElement(element interface{}) types.GomegaMatcher {
}
}
+//BeElementOf succeeds if actual is contained in the passed in elements.
+//BeElementOf() always uses Equal() to perform the match.
+//When the passed in elements are comprised of a single element that is either an Array or Slice, BeElementOf() behaves
+//as the reverse of ContainElement() that operates with Equal() to perform the match.
+// Expect(2).Should(BeElementOf([]int{1, 2}))
+// Expect(2).Should(BeElementOf([2]int{1, 2}))
+//Otherwise, BeElementOf() provides a syntactic sugar for Or(Equal(_), Equal(_), ...):
+// Expect(2).Should(BeElementOf(1, 2))
+//
+//Actual must be typed.
+func BeElementOf(elements ...interface{}) types.GomegaMatcher {
+ return &matchers.BeElementOfMatcher{
+ Elements: elements,
+ }
+}
+
//ConsistOf succeeds if actual contains precisely the elements passed into the matcher. The ordering of the elements does not matter.
//By default ConsistOf() uses Equal() to match the elements, however custom matchers can be passed in instead. Here are some examples:
//
diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
index 51f8be6ae..be4839520 100644
--- a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_directory.go b/vendor/github.com/onsi/gomega/matchers/be_a_directory.go
index 7b6975e41..acffc8570 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_a_directory.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_directory.go
@@ -1,3 +1,5 @@
+// untested sections: 5
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go
index e239131fb..89441c800 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go
@@ -1,3 +1,5 @@
+// untested sections: 5
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go
index d42eba223..ec6506b00 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go
@@ -1,3 +1,5 @@
+// untested sections: 3
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
index 80c9c8bb1..f13c24490 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go
new file mode 100644
index 000000000..1f9d7a8e6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go
@@ -0,0 +1,57 @@
+// untested sections: 1
+
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type BeElementOfMatcher struct {
+ Elements []interface{}
+}
+
+func (matcher *BeElementOfMatcher) Match(actual interface{}) (success bool, err error) {
+ if reflect.TypeOf(actual) == nil {
+ return false, fmt.Errorf("BeElement matcher expects actual to be typed")
+ }
+
+ length := len(matcher.Elements)
+ valueAt := func(i int) interface{} {
+ return matcher.Elements[i]
+ }
+ // Special handling of a single element of type Array or Slice
+ if length == 1 && isArrayOrSlice(valueAt(0)) {
+ element := valueAt(0)
+ value := reflect.ValueOf(element)
+ length = value.Len()
+ valueAt = func(i int) interface{} {
+ return value.Index(i).Interface()
+ }
+ }
+
+ var lastError error
+ for i := 0; i < length; i++ {
+ matcher := &EqualMatcher{Expected: valueAt(i)}
+ success, err := matcher.Match(actual)
+ if err != nil {
+ lastError = err
+ continue
+ }
+ if success {
+ return true, nil
+ }
+ }
+
+ return false, lastError
+}
+
+func (matcher *BeElementOfMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to be an element of", matcher.Elements)
+}
+
+func (matcher *BeElementOfMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to be an element of", matcher.Elements)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
index 8b00311b0..527c1a1c1 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
index 97ab20a4e..263627f40 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
index 91d3b779e..e326c0157 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_identical_to.go b/vendor/github.com/onsi/gomega/matchers/be_identical_to.go
index fdcda4d1f..631ce11e3 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_identical_to.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_identical_to.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go
index 7ee84fe1b..551d99d74 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import "github.com/onsi/gomega/format"
diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
index 9f4f77eec..f72591a1a 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 4
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go
index 302dd1a0a..cf582a3fc 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 3
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
index cb7c038ef..dec4db024 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 3
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
index ec57c5db4..60bc1e3fa 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of.go b/vendor/github.com/onsi/gomega/matchers/consist_of.go
index 7b0e08868..cbbf61802 100644
--- a/vendor/github.com/onsi/gomega/matchers/consist_of.go
+++ b/vendor/github.com/onsi/gomega/matchers/consist_of.go
@@ -1,3 +1,5 @@
+// untested sections: 3
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go
index 4159335d0..8d6c44c7a 100644
--- a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
@@ -22,19 +24,21 @@ func (matcher *ContainElementMatcher) Match(actual interface{}) (success bool, e
}
value := reflect.ValueOf(actual)
- var keys []reflect.Value
+ var valueAt func(int) interface{}
if isMap(actual) {
- keys = value.MapKeys()
+ keys := value.MapKeys()
+ valueAt = func(i int) interface{} {
+ return value.MapIndex(keys[i]).Interface()
+ }
+ } else {
+ valueAt = func(i int) interface{} {
+ return value.Index(i).Interface()
+ }
}
+
var lastError error
for i := 0; i < value.Len(); i++ {
- var success bool
- var err error
- if isMap(actual) {
- success, err = elemMatcher.Match(value.MapIndex(keys[i]).Interface())
- } else {
- success, err = elemMatcher.Match(value.Index(i).Interface())
- }
+ success, err := elemMatcher.Match(valueAt(i))
if err != nil {
lastError = err
continue
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
index f8dc41e74..e725f8c27 100644
--- a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go
index 7ace93dc3..9856752f1 100644
--- a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
index ea5b92336..00cffec70 100644
--- a/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 6
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
index 06355b1e9..4c5916804 100644
--- a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
@@ -1,3 +1,5 @@
+// untested sections:10
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go
index bef00ae21..5bcfdd2ad 100644
--- a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 2
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
index 2018a6128..1936a2ba5 100644
--- a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
@@ -1,3 +1,5 @@
+// untested sections: 3
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
index 639295684..1369c1e87 100644
--- a/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
+++ b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
@@ -1,3 +1,5 @@
+// untested sections: 5
+
package matchers
import (
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go
index 8aaf8759d..108f28586 100644
--- a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go
@@ -1,6 +1,5 @@
package bipartitegraph
-import "errors"
import "fmt"
import . "github.com/onsi/gomega/matchers/support/goraph/node"
@@ -28,7 +27,7 @@ func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(in
for j, rightValue := range rightValues {
neighbours, err := neighbours(leftValue, rightValue)
if err != nil {
- return nil, errors.New(fmt.Sprintf("error determining adjacency for %v and %v: %s", leftValue, rightValue, err.Error()))
+ return nil, fmt.Errorf("error determining adjacency for %v and %v: %s", leftValue, rightValue, err.Error())
}
if neighbours {
diff --git a/vendor/github.com/onsi/gomega/matchers/type_support.go b/vendor/github.com/onsi/gomega/matchers/type_support.go
index 75afcd844..dced2419e 100644
--- a/vendor/github.com/onsi/gomega/matchers/type_support.go
+++ b/vendor/github.com/onsi/gomega/matchers/type_support.go
@@ -6,6 +6,9 @@ See the docs for Gomega for documentation on the matchers
http://onsi.github.io/gomega/
*/
+
+// untested sections: 11
+
package matchers
import (
diff --git a/vendor/github.com/spf13/pflag/.travis.yml b/vendor/github.com/spf13/pflag/.travis.yml
index f8a63b308..00d04cb9b 100644
--- a/vendor/github.com/spf13/pflag/.travis.yml
+++ b/vendor/github.com/spf13/pflag/.travis.yml
@@ -3,8 +3,9 @@ sudo: false
language: go
go:
- - 1.7.3
- - 1.8.1
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
- tip
matrix:
@@ -12,7 +13,7 @@ matrix:
- go: tip
install:
- - go get github.com/golang/lint/golint
+ - go get golang.org/x/lint/golint
- export PATH=$GOPATH/bin:$PATH
- go install ./...
diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md
index b052414d1..7eacc5bdb 100644
--- a/vendor/github.com/spf13/pflag/README.md
+++ b/vendor/github.com/spf13/pflag/README.md
@@ -86,8 +86,8 @@ fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar)
```
-There are helpers function to get values later if you have the FlagSet but
-it was difficult to keep up with all of the flag pointers in your code.
+There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
+it difficult to keep up with all of the pointers in your code.
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
can use GetInt() to get the int value. But notice that 'flagname' must exist
and it must be an int. GetString("flagname") will fail.
diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go
index 5af02f1a7..3731370d6 100644
--- a/vendor/github.com/spf13/pflag/bool_slice.go
+++ b/vendor/github.com/spf13/pflag/bool_slice.go
@@ -71,6 +71,44 @@ func (s *boolSliceValue) String() string {
return "[" + out + "]"
}
+func (s *boolSliceValue) fromString(val string) (bool, error) {
+ return strconv.ParseBool(val)
+}
+
+func (s *boolSliceValue) toString(val bool) string {
+ return strconv.FormatBool(val)
+}
+
+func (s *boolSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *boolSliceValue) Replace(val []string) error {
+ out := make([]bool, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *boolSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func boolSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go
index aa126e44d..a0b2679f7 100644
--- a/vendor/github.com/spf13/pflag/count.go
+++ b/vendor/github.com/spf13/pflag/count.go
@@ -46,7 +46,7 @@ func (f *FlagSet) GetCount(name string) (int, error) {
// CountVar defines a count flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag.
-// A count flag will add 1 to its value evey time it is found on the command line
+// A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) CountVar(p *int, name string, usage string) {
f.CountVarP(p, name, "", usage)
}
@@ -69,7 +69,7 @@ func CountVarP(p *int, name, shorthand string, usage string) {
// Count defines a count flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag.
-// A count flag will add 1 to its value evey time it is found on the command line
+// A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) Count(name string, usage string) *int {
p := new(int)
f.CountVarP(p, name, "", usage)
diff --git a/vendor/github.com/spf13/pflag/duration_slice.go b/vendor/github.com/spf13/pflag/duration_slice.go
index 52c6b6dc1..badadda53 100644
--- a/vendor/github.com/spf13/pflag/duration_slice.go
+++ b/vendor/github.com/spf13/pflag/duration_slice.go
@@ -51,6 +51,44 @@ func (s *durationSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *durationSliceValue) fromString(val string) (time.Duration, error) {
+ return time.ParseDuration(val)
+}
+
+func (s *durationSliceValue) toString(val time.Duration) string {
+ return fmt.Sprintf("%s", val)
+}
+
+func (s *durationSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *durationSliceValue) Replace(val []string) error {
+ out := make([]time.Duration, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *durationSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go
index 9beeda8ec..24a5036e9 100644
--- a/vendor/github.com/spf13/pflag/flag.go
+++ b/vendor/github.com/spf13/pflag/flag.go
@@ -57,9 +57,9 @@ that give one-letter shorthands for flags. You can use these by appending
var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool
func init() {
- flag.BoolVarP("boolname", "b", true, "help message")
+ flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
}
- flag.VarP(&flagVar, "varname", "v", 1234, "help message")
+ flag.VarP(&flagval, "varname", "v", "help message")
Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags.
@@ -190,6 +190,18 @@ type Value interface {
Type() string
}
+// SliceValue is a secondary interface to all flags which hold a list
+// of values. This allows full control over the value of list flags,
+// and avoids complicated marshalling and unmarshalling to csv.
+type SliceValue interface {
+ // Append adds the specified value to the end of the flag value list.
+ Append(string) error
+ // Replace will fully overwrite any data currently in the flag value list.
+ Replace([]string) error
+ // GetSlice returns the flag value list as an array of strings.
+ GetSlice() []string
+}
+
// sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
list := make(sort.StringSlice, len(flags))
diff --git a/vendor/github.com/spf13/pflag/float32_slice.go b/vendor/github.com/spf13/pflag/float32_slice.go
new file mode 100644
index 000000000..caa352741
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/float32_slice.go
@@ -0,0 +1,174 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- float32Slice Value
+type float32SliceValue struct {
+ value *[]float32
+ changed bool
+}
+
+func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue {
+ isv := new(float32SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *float32SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]float32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 float64
+ temp64, err = strconv.ParseFloat(d, 32)
+ if err != nil {
+ return err
+ }
+ out[i] = float32(temp64)
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *float32SliceValue) Type() string {
+ return "float32Slice"
+}
+
+func (s *float32SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%f", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *float32SliceValue) fromString(val string) (float32, error) {
+ t64, err := strconv.ParseFloat(val, 32)
+ if err != nil {
+ return 0, err
+ }
+ return float32(t64), nil
+}
+
+func (s *float32SliceValue) toString(val float32) string {
+ return fmt.Sprintf("%f", val)
+}
+
+func (s *float32SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *float32SliceValue) Replace(val []string) error {
+ out := make([]float32, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *float32SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func float32SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []float32{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]float32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 float64
+ temp64, err = strconv.ParseFloat(d, 32)
+ if err != nil {
+ return nil, err
+ }
+ out[i] = float32(temp64)
+
+ }
+ return out, nil
+}
+
+// GetFloat32Slice return the []float32 value of a flag with the given name
+func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) {
+ val, err := f.getFlagType(name, "float32Slice", float32SliceConv)
+ if err != nil {
+ return []float32{}, err
+ }
+ return val.([]float32), nil
+}
+
+// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string.
+// The argument p points to a []float32 variable in which to store the value of the flag.
+func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
+ f.VarP(newFloat32SliceValue(value, p), name, "", usage)
+}
+
+// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
+ f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string.
+// The argument p points to a float32[] variable in which to store the value of the flag.
+func Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
+ CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage)
+}
+
+// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
+ CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
+// The return value is the address of a []float32 variable that stores the value of the flag.
+func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 {
+ p := []float32{}
+ f.Float32SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
+ p := []float32{}
+ f.Float32SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
+// The return value is the address of a []float32 variable that stores the value of the flag.
+func Float32Slice(name string, value []float32, usage string) *[]float32 {
+ return CommandLine.Float32SliceP(name, "", value, usage)
+}
+
+// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
+func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
+ return CommandLine.Float32SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/float64_slice.go b/vendor/github.com/spf13/pflag/float64_slice.go
new file mode 100644
index 000000000..85bf3073d
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/float64_slice.go
@@ -0,0 +1,166 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- float64Slice Value
+type float64SliceValue struct {
+ value *[]float64
+ changed bool
+}
+
+func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue {
+ isv := new(float64SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *float64SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]float64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseFloat(d, 64)
+ if err != nil {
+ return err
+ }
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *float64SliceValue) Type() string {
+ return "float64Slice"
+}
+
+func (s *float64SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%f", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *float64SliceValue) fromString(val string) (float64, error) {
+ return strconv.ParseFloat(val, 64)
+}
+
+func (s *float64SliceValue) toString(val float64) string {
+ return fmt.Sprintf("%f", val)
+}
+
+func (s *float64SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *float64SliceValue) Replace(val []string) error {
+ out := make([]float64, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *float64SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func float64SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []float64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]float64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseFloat(d, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ }
+ return out, nil
+}
+
+// GetFloat64Slice return the []float64 value of a flag with the given name
+func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) {
+ val, err := f.getFlagType(name, "float64Slice", float64SliceConv)
+ if err != nil {
+ return []float64{}, err
+ }
+ return val.([]float64), nil
+}
+
+// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string.
+// The argument p points to a []float64 variable in which to store the value of the flag.
+func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
+ f.VarP(newFloat64SliceValue(value, p), name, "", usage)
+}
+
+// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
+ f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string.
+// The argument p points to a float64[] variable in which to store the value of the flag.
+func Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
+ CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage)
+}
+
+// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
+ CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
+// The return value is the address of a []float64 variable that stores the value of the flag.
+func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 {
+ p := []float64{}
+ f.Float64SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
+ p := []float64{}
+ f.Float64SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
+// The return value is the address of a []float64 variable that stores the value of the flag.
+func Float64Slice(name string, value []float64, usage string) *[]float64 {
+ return CommandLine.Float64SliceP(name, "", value, usage)
+}
+
+// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
+func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
+ return CommandLine.Float64SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/go.mod b/vendor/github.com/spf13/pflag/go.mod
new file mode 100644
index 000000000..b2287eec1
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/go.mod
@@ -0,0 +1,3 @@
+module github.com/spf13/pflag
+
+go 1.12
diff --git a/vendor/github.com/spf13/pflag/go.sum b/vendor/github.com/spf13/pflag/go.sum
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/go.sum
diff --git a/vendor/github.com/spf13/pflag/int32_slice.go b/vendor/github.com/spf13/pflag/int32_slice.go
new file mode 100644
index 000000000..ff128ff06
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/int32_slice.go
@@ -0,0 +1,174 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- int32Slice Value
+type int32SliceValue struct {
+ value *[]int32
+ changed bool
+}
+
+func newInt32SliceValue(val []int32, p *[]int32) *int32SliceValue {
+ isv := new(int32SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *int32SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]int32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 int64
+ temp64, err = strconv.ParseInt(d, 0, 32)
+ if err != nil {
+ return err
+ }
+ out[i] = int32(temp64)
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *int32SliceValue) Type() string {
+ return "int32Slice"
+}
+
+func (s *int32SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%d", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *int32SliceValue) fromString(val string) (int32, error) {
+ t64, err := strconv.ParseInt(val, 0, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(t64), nil
+}
+
+func (s *int32SliceValue) toString(val int32) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *int32SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *int32SliceValue) Replace(val []string) error {
+ out := make([]int32, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *int32SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func int32SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []int32{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]int32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 int64
+ temp64, err = strconv.ParseInt(d, 0, 32)
+ if err != nil {
+ return nil, err
+ }
+ out[i] = int32(temp64)
+
+ }
+ return out, nil
+}
+
+// GetInt32Slice return the []int32 value of a flag with the given name
+func (f *FlagSet) GetInt32Slice(name string) ([]int32, error) {
+ val, err := f.getFlagType(name, "int32Slice", int32SliceConv)
+ if err != nil {
+ return []int32{}, err
+ }
+ return val.([]int32), nil
+}
+
+// Int32SliceVar defines a int32Slice flag with specified name, default value, and usage string.
+// The argument p points to a []int32 variable in which to store the value of the flag.
+func (f *FlagSet) Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
+ f.VarP(newInt32SliceValue(value, p), name, "", usage)
+}
+
+// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
+ f.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int32SliceVar defines a int32[] flag with specified name, default value, and usage string.
+// The argument p points to a int32[] variable in which to store the value of the flag.
+func Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
+ CommandLine.VarP(newInt32SliceValue(value, p), name, "", usage)
+}
+
+// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
+ CommandLine.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
+// The return value is the address of a []int32 variable that stores the value of the flag.
+func (f *FlagSet) Int32Slice(name string, value []int32, usage string) *[]int32 {
+ p := []int32{}
+ f.Int32SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
+ p := []int32{}
+ f.Int32SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
+// The return value is the address of a []int32 variable that stores the value of the flag.
+func Int32Slice(name string, value []int32, usage string) *[]int32 {
+ return CommandLine.Int32SliceP(name, "", value, usage)
+}
+
+// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
+func Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
+ return CommandLine.Int32SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/int64_slice.go b/vendor/github.com/spf13/pflag/int64_slice.go
new file mode 100644
index 000000000..25464638f
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/int64_slice.go
@@ -0,0 +1,166 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- int64Slice Value
+type int64SliceValue struct {
+ value *[]int64
+ changed bool
+}
+
+func newInt64SliceValue(val []int64, p *[]int64) *int64SliceValue {
+ isv := new(int64SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *int64SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]int64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseInt(d, 0, 64)
+ if err != nil {
+ return err
+ }
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *int64SliceValue) Type() string {
+ return "int64Slice"
+}
+
+func (s *int64SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%d", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *int64SliceValue) fromString(val string) (int64, error) {
+ return strconv.ParseInt(val, 0, 64)
+}
+
+func (s *int64SliceValue) toString(val int64) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *int64SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *int64SliceValue) Replace(val []string) error {
+ out := make([]int64, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *int64SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func int64SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []int64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]int64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseInt(d, 0, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ }
+ return out, nil
+}
+
+// GetInt64Slice return the []int64 value of a flag with the given name
+func (f *FlagSet) GetInt64Slice(name string) ([]int64, error) {
+ val, err := f.getFlagType(name, "int64Slice", int64SliceConv)
+ if err != nil {
+ return []int64{}, err
+ }
+ return val.([]int64), nil
+}
+
+// Int64SliceVar defines a int64Slice flag with specified name, default value, and usage string.
+// The argument p points to a []int64 variable in which to store the value of the flag.
+func (f *FlagSet) Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
+ f.VarP(newInt64SliceValue(value, p), name, "", usage)
+}
+
+// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
+ f.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int64SliceVar defines a int64[] flag with specified name, default value, and usage string.
+// The argument p points to a int64[] variable in which to store the value of the flag.
+func Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
+ CommandLine.VarP(newInt64SliceValue(value, p), name, "", usage)
+}
+
+// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
+ CommandLine.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
+// The return value is the address of a []int64 variable that stores the value of the flag.
+func (f *FlagSet) Int64Slice(name string, value []int64, usage string) *[]int64 {
+ p := []int64{}
+ f.Int64SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
+ p := []int64{}
+ f.Int64SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
+// The return value is the address of a []int64 variable that stores the value of the flag.
+func Int64Slice(name string, value []int64, usage string) *[]int64 {
+ return CommandLine.Int64SliceP(name, "", value, usage)
+}
+
+// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
+func Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
+ return CommandLine.Int64SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go
index 1e7c9edde..e71c39d91 100644
--- a/vendor/github.com/spf13/pflag/int_slice.go
+++ b/vendor/github.com/spf13/pflag/int_slice.go
@@ -51,6 +51,36 @@ func (s *intSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *intSliceValue) Append(val string) error {
+ i, err := strconv.Atoi(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *intSliceValue) Replace(val []string) error {
+ out := make([]int, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = strconv.Atoi(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *intSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = strconv.Itoa(d)
+ }
+ return out
+}
+
func intSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go
index 7dd196fe3..775faae4f 100644
--- a/vendor/github.com/spf13/pflag/ip_slice.go
+++ b/vendor/github.com/spf13/pflag/ip_slice.go
@@ -72,9 +72,47 @@ func (s *ipSliceValue) String() string {
return "[" + out + "]"
}
+func (s *ipSliceValue) fromString(val string) (net.IP, error) {
+ return net.ParseIP(strings.TrimSpace(val)), nil
+}
+
+func (s *ipSliceValue) toString(val net.IP) string {
+ return val.String()
+}
+
+func (s *ipSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *ipSliceValue) Replace(val []string) error {
+ out := make([]net.IP, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *ipSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func ipSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
- // Emtpy string would cause a slice with one (empty) entry
+ // Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []net.IP{}, nil
}
diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go
index fa7bc6018..4894af818 100644
--- a/vendor/github.com/spf13/pflag/string_array.go
+++ b/vendor/github.com/spf13/pflag/string_array.go
@@ -23,6 +23,32 @@ func (s *stringArrayValue) Set(val string) error {
return nil
}
+func (s *stringArrayValue) Append(val string) error {
+ *s.value = append(*s.value, val)
+ return nil
+}
+
+func (s *stringArrayValue) Replace(val []string) error {
+ out := make([]string, len(val))
+ for i, d := range val {
+ var err error
+ out[i] = d
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *stringArrayValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = d
+ }
+ return out
+}
+
func (s *stringArrayValue) Type() string {
return "stringArray"
}
diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go
index 0cd3ccc08..3cb2e69db 100644
--- a/vendor/github.com/spf13/pflag/string_slice.go
+++ b/vendor/github.com/spf13/pflag/string_slice.go
@@ -62,6 +62,20 @@ func (s *stringSliceValue) String() string {
return "[" + str + "]"
}
+func (s *stringSliceValue) Append(val string) error {
+ *s.value = append(*s.value, val)
+ return nil
+}
+
+func (s *stringSliceValue) Replace(val []string) error {
+ *s.value = val
+ return nil
+}
+
+func (s *stringSliceValue) GetSlice() []string {
+ return *s.value
+}
+
func stringSliceConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
// An empty string would cause a slice with one (empty) string
@@ -84,7 +98,7 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
@@ -100,7 +114,7 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) {
@@ -116,7 +130,7 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
@@ -136,7 +150,7 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string {
diff --git a/vendor/github.com/spf13/pflag/string_to_int64.go b/vendor/github.com/spf13/pflag/string_to_int64.go
new file mode 100644
index 000000000..a807a04a0
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/string_to_int64.go
@@ -0,0 +1,149 @@
+package pflag
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- stringToInt64 Value
+type stringToInt64Value struct {
+ value *map[string]int64
+ changed bool
+}
+
+func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value {
+ ssv := new(stringToInt64Value)
+ ssv.value = p
+ *ssv.value = val
+ return ssv
+}
+
+// Format: a=1,b=2
+func (s *stringToInt64Value) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make(map[string]int64, len(ss))
+ for _, pair := range ss {
+ kv := strings.SplitN(pair, "=", 2)
+ if len(kv) != 2 {
+ return fmt.Errorf("%s must be formatted as key=value", pair)
+ }
+ var err error
+ out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
+ if err != nil {
+ return err
+ }
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ for k, v := range out {
+ (*s.value)[k] = v
+ }
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *stringToInt64Value) Type() string {
+ return "stringToInt64"
+}
+
+func (s *stringToInt64Value) String() string {
+ var buf bytes.Buffer
+ i := 0
+ for k, v := range *s.value {
+ if i > 0 {
+ buf.WriteRune(',')
+ }
+ buf.WriteString(k)
+ buf.WriteRune('=')
+ buf.WriteString(strconv.FormatInt(v, 10))
+ i++
+ }
+ return "[" + buf.String() + "]"
+}
+
+func stringToInt64Conv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // An empty string would cause an empty map
+ if len(val) == 0 {
+ return map[string]int64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make(map[string]int64, len(ss))
+ for _, pair := range ss {
+ kv := strings.SplitN(pair, "=", 2)
+ if len(kv) != 2 {
+ return nil, fmt.Errorf("%s must be formatted as key=value", pair)
+ }
+ var err error
+ out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return out, nil
+}
+
+// GetStringToInt64 return the map[string]int64 value of a flag with the given name
+func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) {
+ val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv)
+ if err != nil {
+ return map[string]int64{}, err
+ }
+ return val.(map[string]int64), nil
+}
+
+// StringToInt64Var defines a string flag with specified name, default value, and usage string.
+// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags.
+// The value of each argument will not try to be separated by comma
+func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
+ f.VarP(newStringToInt64Value(value, p), name, "", usage)
+}
+
+// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
+ f.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
+}
+
+// StringToInt64Var defines a string flag with specified name, default value, and usage string.
+// The argument p point64s to a map[string]int64 variable in which to store the value of the flag.
+// The value of each argument will not try to be separated by comma
+func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
+ CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage)
+}
+
+// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
+func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
+ CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
+}
+
+// StringToInt64 defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a map[string]int64 variable that stores the value of the flag.
+// The value of each argument will not try to be separated by comma
+func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
+ p := map[string]int64{}
+ f.StringToInt64VarP(&p, name, "", value, usage)
+ return &p
+}
+
+// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
+ p := map[string]int64{}
+ f.StringToInt64VarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// StringToInt64 defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a map[string]int64 variable that stores the value of the flag.
+// The value of each argument will not try to be separated by comma
+func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
+ return CommandLine.StringToInt64P(name, "", value, usage)
+}
+
+// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
+func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
+ return CommandLine.StringToInt64P(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go
index edd94c600..5fa924835 100644
--- a/vendor/github.com/spf13/pflag/uint_slice.go
+++ b/vendor/github.com/spf13/pflag/uint_slice.go
@@ -50,6 +50,48 @@ func (s *uintSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *uintSliceValue) fromString(val string) (uint, error) {
+ t, err := strconv.ParseUint(val, 10, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uint(t), nil
+}
+
+func (s *uintSliceValue) toString(val uint) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *uintSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *uintSliceValue) Replace(val []string) error {
+ out := make([]uint, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *uintSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func uintSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go
index aa1c2b95c..e0364e9e7 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_format.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go
@@ -113,6 +113,17 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
return Error(t, err, append([]interface{}{msg}, args...)...)
}
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
@@ -157,6 +168,31 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
return FileExists(t, path, append([]interface{}{msg}, args...)...)
}
+// Greaterf asserts that the first element is greater than the second
+//
+// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
+// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
@@ -289,6 +325,14 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
@@ -300,6 +344,31 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
+// Lessf asserts that the first element is less than the second
+//
+// assert.Lessf(t, 1, 2, "error message %s", "formatted")
+// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
+// assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
// Nilf asserts that the specified object is nil.
//
// assert.Nilf(t, err, "error message %s", "formatted")
@@ -444,6 +513,19 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
+// Samef asserts that two pointers reference the same object.
+//
+// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
// Subsetf asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
index de39f794e..26830403a 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
@@ -215,6 +215,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
return Errorf(a.t, err, msg, args...)
}
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
// Exactly asserts that two objects are equal in value and type.
//
// a.Exactly(int32(123), int64(123))
@@ -303,6 +325,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b
return FileExistsf(a.t, path, msg, args...)
}
+// Greater asserts that the first element is greater than the second
+//
+// a.Greater(2, 1)
+// a.Greater(float64(2), float64(1))
+// a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqual(2, 1)
+// a.GreaterOrEqual(2, 2)
+// a.GreaterOrEqual("b", "a")
+// a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// a.Greaterf(2, 1, "error message %s", "formatted")
+// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
+// a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greaterf(a.t, e1, e2, msg, args...)
+}
+
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
@@ -567,6 +639,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
return JSONEqf(a.t, expected, actual, msg, args...)
}
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
@@ -589,6 +677,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
return Lenf(a.t, object, length, msg, args...)
}
+// Less asserts that the first element is less than the second
+//
+// a.Less(1, 2)
+// a.Less(float64(1), float64(2))
+// a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqual(1, 2)
+// a.LessOrEqual(2, 2)
+// a.LessOrEqual("a", "b")
+// a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqualf(1, 2, "error message %s", "formatted")
+// a.LessOrEqualf(2, 2, "error message %s", "formatted")
+// a.LessOrEqualf("a", "b", "error message %s", "formatted")
+// a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// a.Lessf(1, 2, "error message %s", "formatted")
+// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
+// a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Lessf(a.t, e1, e2, msg, args...)
+}
+
// Nil asserts that the specified object is nil.
//
// a.Nil(err)
@@ -877,6 +1015,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
return Regexpf(a.t, rx, str, msg, args...)
}
+// Same asserts that two pointers reference the same object.
+//
+// a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Samef(a.t, expected, actual, msg, args...)
+}
+
// Subset asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go
new file mode 100644
index 000000000..15a486ca6
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go
@@ -0,0 +1,309 @@
+package assert
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
+ switch kind {
+ case reflect.Int:
+ {
+ intobj1 := obj1.(int)
+ intobj2 := obj2.(int)
+ if intobj1 > intobj2 {
+ return -1, true
+ }
+ if intobj1 == intobj2 {
+ return 0, true
+ }
+ if intobj1 < intobj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int8:
+ {
+ int8obj1 := obj1.(int8)
+ int8obj2 := obj2.(int8)
+ if int8obj1 > int8obj2 {
+ return -1, true
+ }
+ if int8obj1 == int8obj2 {
+ return 0, true
+ }
+ if int8obj1 < int8obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int16:
+ {
+ int16obj1 := obj1.(int16)
+ int16obj2 := obj2.(int16)
+ if int16obj1 > int16obj2 {
+ return -1, true
+ }
+ if int16obj1 == int16obj2 {
+ return 0, true
+ }
+ if int16obj1 < int16obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int32:
+ {
+ int32obj1 := obj1.(int32)
+ int32obj2 := obj2.(int32)
+ if int32obj1 > int32obj2 {
+ return -1, true
+ }
+ if int32obj1 == int32obj2 {
+ return 0, true
+ }
+ if int32obj1 < int32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int64:
+ {
+ int64obj1 := obj1.(int64)
+ int64obj2 := obj2.(int64)
+ if int64obj1 > int64obj2 {
+ return -1, true
+ }
+ if int64obj1 == int64obj2 {
+ return 0, true
+ }
+ if int64obj1 < int64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint:
+ {
+ uintobj1 := obj1.(uint)
+ uintobj2 := obj2.(uint)
+ if uintobj1 > uintobj2 {
+ return -1, true
+ }
+ if uintobj1 == uintobj2 {
+ return 0, true
+ }
+ if uintobj1 < uintobj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint8:
+ {
+ uint8obj1 := obj1.(uint8)
+ uint8obj2 := obj2.(uint8)
+ if uint8obj1 > uint8obj2 {
+ return -1, true
+ }
+ if uint8obj1 == uint8obj2 {
+ return 0, true
+ }
+ if uint8obj1 < uint8obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint16:
+ {
+ uint16obj1 := obj1.(uint16)
+ uint16obj2 := obj2.(uint16)
+ if uint16obj1 > uint16obj2 {
+ return -1, true
+ }
+ if uint16obj1 == uint16obj2 {
+ return 0, true
+ }
+ if uint16obj1 < uint16obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint32:
+ {
+ uint32obj1 := obj1.(uint32)
+ uint32obj2 := obj2.(uint32)
+ if uint32obj1 > uint32obj2 {
+ return -1, true
+ }
+ if uint32obj1 == uint32obj2 {
+ return 0, true
+ }
+ if uint32obj1 < uint32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint64:
+ {
+ uint64obj1 := obj1.(uint64)
+ uint64obj2 := obj2.(uint64)
+ if uint64obj1 > uint64obj2 {
+ return -1, true
+ }
+ if uint64obj1 == uint64obj2 {
+ return 0, true
+ }
+ if uint64obj1 < uint64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Float32:
+ {
+ float32obj1 := obj1.(float32)
+ float32obj2 := obj2.(float32)
+ if float32obj1 > float32obj2 {
+ return -1, true
+ }
+ if float32obj1 == float32obj2 {
+ return 0, true
+ }
+ if float32obj1 < float32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Float64:
+ {
+ float64obj1 := obj1.(float64)
+ float64obj2 := obj2.(float64)
+ if float64obj1 > float64obj2 {
+ return -1, true
+ }
+ if float64obj1 == float64obj2 {
+ return 0, true
+ }
+ if float64obj1 < float64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.String:
+ {
+ stringobj1 := obj1.(string)
+ stringobj2 := obj2.(string)
+ if stringobj1 > stringobj2 {
+ return -1, true
+ }
+ if stringobj1 == stringobj2 {
+ return 0, true
+ }
+ if stringobj1 < stringobj2 {
+ return 1, true
+ }
+ }
+ }
+
+ return 0, false
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// assert.Greater(t, 2, 1)
+// assert.Greater(t, float64(2), float64(1))
+// assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != -1 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqual(t, 2, 1)
+// assert.GreaterOrEqual(t, 2, 2)
+// assert.GreaterOrEqual(t, "b", "a")
+// assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != -1 && res != 0 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// Less asserts that the first element is less than the second
+//
+// assert.Less(t, 1, 2)
+// assert.Less(t, float64(1), float64(2))
+// assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != 1 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqual(t, 1, 2)
+// assert.LessOrEqual(t, 2, 2)
+// assert.LessOrEqual(t, "a", "b")
+// assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != 1 && res != 0 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go
index 9bd4a80e4..044da8b01 100644
--- a/vendor/github.com/stretchr/testify/assert/assertions.go
+++ b/vendor/github.com/stretchr/testify/assert/assertions.go
@@ -18,6 +18,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
+ yaml "gopkg.in/yaml.v2"
)
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
@@ -350,6 +351,37 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
}
+// Same asserts that two pointers reference the same object.
+//
+// assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
+ if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
+ return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
+ }
+
+ expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
+ if expectedType != actualType {
+ return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
+ expectedType, actualType), msgAndArgs...)
+ }
+
+ if expected != actual {
+ return Fail(t, fmt.Sprintf("Not same: \n"+
+ "expected: %p %#v\n"+
+ "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
+ }
+
+ return true
+}
+
// formatUnequalValues takes two values of arbitrary types and returns string
// representations appropriate to be presented to the user.
//
@@ -479,14 +511,14 @@ func isEmpty(object interface{}) bool {
// collection types are empty when they have no element
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
- // pointers are empty if nil or if the value they point to is empty
+ // pointers are empty if nil or if the value they point to is empty
case reflect.Ptr:
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
- // for all other types, compare against the zero value
+ // for all other types, compare against the zero value
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
@@ -629,7 +661,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
func includeElement(list interface{}, element interface{}) (ok, found bool) {
listValue := reflect.ValueOf(list)
- elementValue := reflect.ValueOf(element)
+ listKind := reflect.TypeOf(list).Kind()
defer func() {
if e := recover(); e != nil {
ok = false
@@ -637,11 +669,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
}
}()
- if reflect.TypeOf(list).Kind() == reflect.String {
+ if listKind == reflect.String {
+ elementValue := reflect.ValueOf(element)
return true, strings.Contains(listValue.String(), elementValue.String())
}
- if reflect.TypeOf(list).Kind() == reflect.Map {
+ if listKind == reflect.Map {
mapKeys := listValue.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
@@ -1337,6 +1370,24 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
}
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
+
+ if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+ }
+
+ if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
+ }
+
+ return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
+}
+
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
t := reflect.TypeOf(v)
k := t.Kind()
@@ -1371,8 +1422,8 @@ func diff(expected interface{}, actual interface{}) string {
e = spewConfig.Sdump(expected)
a = spewConfig.Sdump(actual)
} else {
- e = expected.(string)
- a = actual.(string)
+ e = reflect.ValueOf(expected).String()
+ a = reflect.ValueOf(actual).String()
}
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
@@ -1414,3 +1465,34 @@ var spewConfig = spew.ConfigState{
type tHelper interface {
Helper()
}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ timer := time.NewTimer(waitFor)
+ ticker := time.NewTicker(tick)
+ checkPassed := make(chan bool)
+ defer timer.Stop()
+ defer ticker.Stop()
+ defer close(checkPassed)
+ for {
+ select {
+ case <-timer.C:
+ return Fail(t, "Condition never satisfied", msgAndArgs...)
+ case result := <-checkPassed:
+ if result {
+ return true
+ }
+ case <-ticker.C:
+ go func() {
+ checkPassed <- condition()
+ }()
+ }
+ }
+}
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
index 535f29349..c5903f5db 100644
--- a/vendor/github.com/stretchr/testify/require/require.go
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -14,23 +14,23 @@ import (
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
- if assert.Condition(t, comp, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Condition(t, comp, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
- if assert.Conditionf(t, comp, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Conditionf(t, comp, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -41,12 +41,12 @@ func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interfac
// assert.Contains(t, ["Hello", "World"], "World")
// assert.Contains(t, {"Hello": "World"}, "Hello")
func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
- if assert.Contains(t, s, contains, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Contains(t, s, contains, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -57,34 +57,34 @@ func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...int
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
- if assert.Containsf(t, s, contains, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Containsf(t, s, contains, msg, args...) {
+ return
+ }
t.FailNow()
}
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
- if assert.DirExists(t, path, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.DirExists(t, path, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
- if assert.DirExistsf(t, path, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.DirExistsf(t, path, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -94,12 +94,12 @@ func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
//
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
- if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -109,12 +109,12 @@ func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs
//
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
- if assert.ElementsMatchf(t, listA, listB, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.ElementsMatchf(t, listA, listB, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -123,12 +123,12 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string
//
// assert.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
- if assert.Empty(t, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Empty(t, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -137,12 +137,12 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
//
// assert.Emptyf(t, obj, "error message %s", "formatted")
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
- if assert.Emptyf(t, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Emptyf(t, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -154,12 +154,12 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
- if assert.Equal(t, expected, actual, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Equal(t, expected, actual, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -169,12 +169,12 @@ func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...i
// actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString)
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
- if assert.EqualError(t, theError, errString, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.EqualError(t, theError, errString, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -184,12 +184,12 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
// actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
- if assert.EqualErrorf(t, theError, errString, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.EqualErrorf(t, theError, errString, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -198,12 +198,12 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
//
// assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
- if assert.EqualValues(t, expected, actual, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.EqualValues(t, expected, actual, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -212,12 +212,12 @@ func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArg
//
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
- if assert.EqualValuesf(t, expected, actual, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.EqualValuesf(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -229,12 +229,12 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
- if assert.Equalf(t, expected, actual, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Equalf(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -245,12 +245,12 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
// assert.Equal(t, expectedError, err)
// }
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
- if assert.Error(t, err, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Error(t, err, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -261,9 +261,37 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) {
// assert.Equal(t, expectedErrorf, err)
// }
func Errorf(t TestingT, err error, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if assert.Errorf(t, err, msg, args...) {
return
}
+ t.FailNow()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
+ return
+ }
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ t.FailNow()
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
+ return
+ }
if h, ok := t.(tHelper); ok {
h.Helper()
}
@@ -274,12 +302,12 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) {
//
// assert.Exactly(t, int32(123), int64(123))
func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
- if assert.Exactly(t, expected, actual, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Exactly(t, expected, actual, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -287,56 +315,56 @@ func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ..
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
- if assert.Exactlyf(t, expected, actual, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Exactlyf(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
- if assert.Fail(t, failureMessage, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Fail(t, failureMessage, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
- if assert.FailNow(t, failureMessage, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.FailNow(t, failureMessage, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
- if assert.FailNowf(t, failureMessage, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.FailNowf(t, failureMessage, msg, args...) {
+ return
+ }
t.FailNow()
}
// Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
- if assert.Failf(t, failureMessage, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Failf(t, failureMessage, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -344,12 +372,12 @@ func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
//
// assert.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
- if assert.False(t, value, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.False(t, value, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -357,34 +385,96 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) {
//
// assert.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
- if assert.Falsef(t, value, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Falsef(t, value, msg, args...) {
+ return
+ }
t.FailNow()
}
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
- if assert.FileExists(t, path, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.FileExists(t, path, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if assert.FileExistsf(t, path, msg, args...) {
return
}
+ t.FailNow()
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// assert.Greater(t, 2, 1)
+// assert.Greater(t, float64(2), float64(1))
+// assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Greater(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqual(t, 2, 1)
+// assert.GreaterOrEqual(t, 2, 2)
+// assert.GreaterOrEqual(t, "b", "a")
+// assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.GreaterOrEqualf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
+// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Greaterf(t, e1, e2, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -395,12 +485,12 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
- if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -411,12 +501,12 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
- if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -427,12 +517,12 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
- if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -443,12 +533,12 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
- if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -458,12 +548,12 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
- if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -473,12 +563,12 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string,
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
- if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -488,12 +578,12 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
- if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -503,12 +593,12 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
- if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -518,12 +608,12 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
- if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -533,12 +623,12 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
- if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -546,12 +636,12 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
- if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -559,12 +649,12 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
//
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
- if assert.Implementsf(t, interfaceObject, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Implementsf(t, interfaceObject, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -572,56 +662,56 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
//
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
- if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
- if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
- if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
+ return
+ }
t.FailNow()
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
- if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
- if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -629,78 +719,78 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f
//
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
- if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
+ return
+ }
t.FailNow()
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
- if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
- if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
- if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
+ return
+ }
t.FailNow()
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
- if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
+ return
+ }
t.FailNow()
}
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
- if assert.IsType(t, expectedType, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.IsType(t, expectedType, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// IsTypef asserts that the specified objects are of the same type.
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
- if assert.IsTypef(t, expectedType, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.IsTypef(t, expectedType, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -708,12 +798,12 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
- if assert.JSONEq(t, expected, actual, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.JSONEq(t, expected, actual, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -721,12 +811,34 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
//
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if assert.JSONEqf(t, expected, actual, msg, args...) {
return
}
+ t.FailNow()
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.YAMLEqf(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -735,12 +847,12 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
//
// assert.Len(t, mySlice, 3)
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
- if assert.Len(t, object, length, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Len(t, object, length, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -749,12 +861,74 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
//
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if assert.Lenf(t, object, length, msg, args...) {
return
}
+ t.FailNow()
+}
+
+// Less asserts that the first element is less than the second
+//
+// assert.Less(t, 1, 2)
+// assert.Less(t, float64(1), float64(2))
+// assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Less(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqual(t, 1, 2)
+// assert.LessOrEqual(t, 2, 2)
+// assert.LessOrEqual(t, "a", "b")
+// assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.LessOrEqual(t, e1, e2, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.LessOrEqualf(t, e1, e2, msg, args...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// assert.Lessf(t, 1, 2, "error message %s", "formatted")
+// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
+// assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Lessf(t, e1, e2, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -762,12 +936,12 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
//
// assert.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
- if assert.Nil(t, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Nil(t, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -775,12 +949,12 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
//
// assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
- if assert.Nilf(t, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Nilf(t, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -791,12 +965,12 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
// assert.Equal(t, expectedObj, actualObj)
// }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
- if assert.NoError(t, err, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NoError(t, err, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -807,12 +981,12 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
// assert.Equal(t, expectedObj, actualObj)
// }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
- if assert.NoErrorf(t, err, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NoErrorf(t, err, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -823,12 +997,12 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
// assert.NotContains(t, ["Hello", "World"], "Earth")
// assert.NotContains(t, {"Hello": "World"}, "Earth")
func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
- if assert.NotContains(t, s, contains, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotContains(t, s, contains, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -839,12 +1013,12 @@ func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
- if assert.NotContainsf(t, s, contains, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotContainsf(t, s, contains, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -855,12 +1029,12 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
// assert.Equal(t, "two", obj[1])
// }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
- if assert.NotEmpty(t, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotEmpty(t, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -871,12 +1045,12 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
// assert.Equal(t, "two", obj[1])
// }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
- if assert.NotEmptyf(t, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotEmptyf(t, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -887,12 +1061,12 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{})
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
- if assert.NotEqual(t, expected, actual, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotEqual(t, expected, actual, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -903,12 +1077,12 @@ func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs .
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
- if assert.NotEqualf(t, expected, actual, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotEqualf(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -916,12 +1090,12 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string,
//
// assert.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
- if assert.NotNil(t, object, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotNil(t, object, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -929,12 +1103,12 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
//
// assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
- if assert.NotNilf(t, object, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotNilf(t, object, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -942,12 +1116,12 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
//
// assert.NotPanics(t, func(){ RemainCalm() })
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
- if assert.NotPanics(t, f, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotPanics(t, f, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -955,12 +1129,12 @@ func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
//
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
- if assert.NotPanicsf(t, f, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotPanicsf(t, f, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -969,12 +1143,12 @@ func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interfac
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
- if assert.NotRegexp(t, rx, str, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotRegexp(t, rx, str, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -983,12 +1157,12 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
- if assert.NotRegexpf(t, rx, str, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotRegexpf(t, rx, str, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -997,12 +1171,12 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
//
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
- if assert.NotSubset(t, list, subset, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotSubset(t, list, subset, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1011,34 +1185,34 @@ func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...i
//
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
- if assert.NotSubsetf(t, list, subset, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotSubsetf(t, list, subset, msg, args...) {
+ return
+ }
t.FailNow()
}
// NotZero asserts that i is not the zero value for its type.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
- if assert.NotZero(t, i, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotZero(t, i, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
- if assert.NotZerof(t, i, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.NotZerof(t, i, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1046,12 +1220,12 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
//
// assert.Panics(t, func(){ GoCrazy() })
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
- if assert.Panics(t, f, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Panics(t, f, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1060,12 +1234,12 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
//
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
- if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1074,12 +1248,12 @@ func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, m
//
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
- if assert.PanicsWithValuef(t, expected, f, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.PanicsWithValuef(t, expected, f, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1087,12 +1261,12 @@ func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc,
//
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
- if assert.Panicsf(t, f, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Panicsf(t, f, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1101,12 +1275,12 @@ func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
- if assert.Regexp(t, rx, str, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Regexp(t, rx, str, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1115,12 +1289,44 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if assert.Regexpf(t, rx, str, msg, args...) {
return
}
+ t.FailNow()
+}
+
+// Same asserts that two pointers reference the same object.
+//
+// assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if assert.Same(t, expected, actual, msgAndArgs...) {
+ return
+ }
+ t.FailNow()
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Samef(t, expected, actual, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1129,12 +1335,12 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
//
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
- if assert.Subset(t, list, subset, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Subset(t, list, subset, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1143,12 +1349,12 @@ func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...inte
//
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
- if assert.Subsetf(t, list, subset, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Subsetf(t, list, subset, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1156,12 +1362,12 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args
//
// assert.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
- if assert.True(t, value, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.True(t, value, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1169,12 +1375,12 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) {
//
// assert.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) {
- if assert.Truef(t, value, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Truef(t, value, msg, args...) {
+ return
+ }
t.FailNow()
}
@@ -1182,12 +1388,12 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) {
//
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
- if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
@@ -1195,33 +1401,33 @@ func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time
//
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
- if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
+ return
+ }
t.FailNow()
}
// Zero asserts that i is the zero value for its type.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
- if assert.Zero(t, i, msgAndArgs...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Zero(t, i, msgAndArgs...) {
+ return
+ }
t.FailNow()
}
// Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
- if assert.Zerof(t, i, msg, args...) {
- return
- }
if h, ok := t.(tHelper); ok {
h.Helper()
}
+ if assert.Zerof(t, i, msg, args...) {
+ return
+ }
t.FailNow()
}
diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl
index 6ffc751b5..55e42ddeb 100644
--- a/vendor/github.com/stretchr/testify/require/require.go.tmpl
+++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl
@@ -1,6 +1,6 @@
{{.Comment}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
- if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
if h, ok := t.(tHelper); ok { h.Helper() }
+ if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
t.FailNow()
}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
index 9fe41dbdc..804fae035 100644
--- a/vendor/github.com/stretchr/testify/require/require_forward.go
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -216,6 +216,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
Errorf(a.t, err, msg, args...)
}
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
// Exactly asserts that two objects are equal in value and type.
//
// a.Exactly(int32(123), int64(123))
@@ -304,6 +326,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
FileExistsf(a.t, path, msg, args...)
}
+// Greater asserts that the first element is greater than the second
+//
+// a.Greater(2, 1)
+// a.Greater(float64(2), float64(1))
+// a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqual(2, 1)
+// a.GreaterOrEqual(2, 2)
+// a.GreaterOrEqual("b", "a")
+// a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// a.Greaterf(2, 1, "error message %s", "formatted")
+// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
+// a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Greaterf(a.t, e1, e2, msg, args...)
+}
+
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
@@ -568,6 +640,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
JSONEqf(a.t, expected, actual, msg, args...)
}
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
@@ -590,6 +678,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
Lenf(a.t, object, length, msg, args...)
}
+// Less asserts that the first element is less than the second
+//
+// a.Less(1, 2)
+// a.Less(float64(1), float64(2))
+// a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqual(1, 2)
+// a.LessOrEqual(2, 2)
+// a.LessOrEqual("a", "b")
+// a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqualf(1, 2, "error message %s", "formatted")
+// a.LessOrEqualf(2, 2, "error message %s", "formatted")
+// a.LessOrEqualf("a", "b", "error message %s", "formatted")
+// a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// a.Lessf(1, 2, "error message %s", "formatted")
+// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
+// a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Lessf(a.t, e1, e2, msg, args...)
+}
+
// Nil asserts that the specified object is nil.
//
// a.Nil(err)
@@ -878,6 +1016,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
Regexpf(a.t, rx, str, msg, args...)
}
+// Same asserts that two pointers reference the same object.
+//
+// a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ Samef(a.t, expected, actual, msg, args...)
+}
+
// Subset asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//
diff --git a/vendor/github.com/uber/jaeger-client-go/.travis.yml b/vendor/github.com/uber/jaeger-client-go/.travis.yml
index acdc2a010..0d7bdd9ab 100644
--- a/vendor/github.com/uber/jaeger-client-go/.travis.yml
+++ b/vendor/github.com/uber/jaeger-client-go/.travis.yml
@@ -10,14 +10,17 @@ matrix:
- go: 1.12.x
env:
- TESTS=true
+ - USE_DEP=true
- COVERAGE=true
- go: 1.12.x
env:
+ - USE_DEP=true
- CROSSDOCK=true
- go: 1.12.x
env:
- TESTS=true
- - USE_DEP=true
+ - USE_DEP=false
+ - USE_GLIDE=true
- go: 1.11.x
env:
- TESTS=true
@@ -30,7 +33,6 @@ services:
env:
global:
- DOCKER_COMPOSE_VERSION=1.8.0
- - GO15VENDOREXPERIMENT=1
- COMMIT=${TRAVIS_COMMIT::8}
# DOCKER_PASS
- secure: "CnjVyxNvMC/dhr/eR7C+FiWucZ4/O5LfAuz9YU0qlnV6XLR7XXRtzZlfFKIImJT6xHp+OptTqAIXqUbvwK2OXDP1ZsLiWRm+2elb9/isGusWXjs3g817lX8njSUcIFILbfi+vAE7UD2BKjHxpmvWmCZidisU1rcaZ9OQNPqMnNIDxVx0FOTwYx+2hfkdjnN5dikzafBDQ6ZZV/mGbcaTG45GGFU6DHyVLzf9qCPXyXnz2+VDhcoPQsYkzE56XHCmHxvEfXxgfqYefJNUlFPhniAQySVsCNVDJ8QcCV6uHaXoIzxJKx9FdUnWKI1/AtpQsTZPgEm4Ujnt+kGJsXopXy2Xx4MZxmcTCBwAMjZxPMF7KoojbtDeOZgEMtf1tGPN6DTNc3NpVmr0BKZ44lhqk+vnd8HAiC1tHDEoSb1Esl7dMUUf1qZAh3MtT+NYi3mTwyx/ilXUS7KPyy7x0ezB3kGuMoLhvR2hrprqRr5NOV2hrd1au+IXmb+4IanFOsBlceBfs8P0JFMO/aw15r+HimSZpQsJx//IT0LReCZYXLe0/WVsF/8+HDwHKlO99gGpk4iXlNKKvdPWabihMp3I3peMrvL+jnlwh47RqHs/0Q71xsKjVWTn+Svq3FpVP0Pgyxhg+oG4WEByBiLnBQcZwSBhWexkJrNI73GzaZiIldk="
@@ -38,7 +40,7 @@ env:
- secure: "bpBSmypHzI4PnteM4cwLiMC2163Sj/4mEl+1dj+6NWl2tr1hREeVXKhsWBpah25n6BDyr2A4yhBZcWLaNKrsCKT3U37csAQTOFVeQ9x5xhPq+ohANd/OsspFsxNZaKwx161LizH/uTDotMxxevZacsyYWGNv/cRFkwcQ8upLkReRR6puJ+jNQC0BFpKWBJY/zpm5J7xFb7FO20LvQVyRgsgzqWmg9oRNVw9uwOfSY3btacftYctDLUbAr8YRNHd2C6dZnMAi8KdDTLXKTqjKmp6WidOmi92Ml7tOjB+bV6TOaVAhrcI5Rdje4rRWG4MucAjPMP0ZBW36KTfcGqFUcDhX7UqISe2WxoI+8ZD6fJ+nNtD3bk4YAUJB4BSs2sQdiYyjpHyGJR6RW50+3uRz2YbXpzVr9wqv2lZSl/xy3wC5Hag55uqzVlSiDw2pK8lctT3dnQveE7PqAI577PjF2NrHlgrBbykOwwUCNbRTmykzqoDnkxclmiZ+rflEeWsSYglePK/d6Gj9+N7wJZM5heprdJJMFTrzMWZ21Ll9ZGY9updCBKmJA8pBYiLHbu0lWOp+9QUGC+621Zq0d1PHhN6L4eXk/f3RNoZTr//cX6WdNmmO7tBbaGpmp/UYiYTY1WO9vP7tCDsT75k285HCfnIrlGRdbCZZbfuYNGPKIQ0="
install:
- - make install-ci
+ - make install-ci USE_DEP=$USE_DEP
- if [ "$CROSSDOCK" == true ]; then bash ./travis/install-crossdock-deps.sh ; fi
script:
diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
index 05216d5a8..31b22e40c 100644
--- a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
+++ b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
@@ -1,6 +1,37 @@
Changes by Version
==================
+2.19.0 (2019-09-23)
+-------------------
+
+- Upgrade jaeger-lib to 2.2 and unpin Prom client (#434) -- Yuri Shkuro
+
+
+2.18.1 (2019-09-16)
+-------------------
+
+- Remove go.mod / go.sum that interfere with `go get` (#432)
+
+
+2.18.0 (2019-09-09)
+-------------------
+
+- Add option "noDebugFlagOnForcedSampling" for tracer initialization [resolves #422] (#423) <Jun Guo>
+
+
+2.17.0 (2019-08-30)
+-------------------
+
+- Add a flag for firehose mode (#419) <Prithvi Raj>
+- Default sampling server URL to agent (#414) <Bryan Boreham>
+- Update default sampling rate when sampling strategy is refreshed (#413) <Bryan Boreham>
+- Support "Self" Span Reference (#411) <dm03514>
+- Don't complain about blank service name if tracing is Disabled (#410) Yuri <Shkuro>
+- Use IP address from tag if exist (#402) <NikoKVCS>
+- Expose span data to custom reporters [fixes #394] (#399) <Curtis Allen>
+- Fix the span allocation in the pool (#381) <Dmitry Ponomarev>
+
+
2.16.0 (2019-03-24)
-------------------
diff --git a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md
index 7cf014a51..41e2154cf 100644
--- a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md
+++ b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md
@@ -19,7 +19,7 @@ file for details.
## Getting Started
-This library uses [glide](https://github.com/Masterminds/glide) to manage dependencies.
+This library uses [dep](https://golang.github.io/dep/) to manage dependencies.
To get started, make sure you clone the Git repository into the correct location
`github.com/uber/jaeger-client-go` relative to `$GOPATH`:
@@ -29,13 +29,13 @@ mkdir -p $GOPATH/src/github.com/uber
cd $GOPATH/src/github.com/uber
git clone git@github.com:jaegertracing/jaeger-client-go.git jaeger-client-go
cd jaeger-client-go
+git submodule update --init --recursive
```
Then install dependencies and run the tests:
```
-git submodule update --init --recursive
-glide install
+make install
make test
```
@@ -45,13 +45,13 @@ This projects follows the following pattern for grouping imports in Go files:
* imports from standard library
* imports from other projects
* imports from `jaeger-client-go` project
-
+
For example:
```go
import (
"fmt"
-
+
"github.com/uber/jaeger-lib/metrics"
"go.uber.org/zap"
diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
index 55d9ac030..1ed86f4a7 100644
--- a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
+++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
@@ -2,12 +2,12 @@
[[projects]]
- branch = "master"
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = "UT"
- revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
+ revision = "37c8de3658fcb183f997c4e13e8337516ab753e6"
+ version = "v1.0.1"
[[projects]]
branch = "master"
@@ -38,12 +38,12 @@
version = "v1.1.1"
[[projects]]
- digest = "1:318f1c959a8a740366fce4b1e1eb2fd914036b4af58fbd0a003349b305f118ad"
+ digest = "1:573ca21d3669500ff845bdebee890eb7fc7f0f50c59f2132f2a0c6b03d85086a"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = "UT"
- revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
- version = "v1.3.1"
+ revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
+ version = "v1.3.2"
[[projects]]
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
@@ -83,12 +83,15 @@
version = "v1.0.0"
[[projects]]
- digest = "1:b6221ec0f8903b556e127c449e7106b63e6867170c2d10a7c058623d086f2081"
+ digest = "1:7097829edd12fd7211fca0d29496b44f94ef9e6d72f88fb64f3d7b06315818ad"
name = "github.com/prometheus/client_golang"
- packages = ["prometheus"]
+ packages = [
+ "prometheus",
+ "prometheus/internal",
+ ]
pruneopts = "UT"
- revision = "c5b7fccd204277076155f10851dad72b76a49317"
- version = "v0.8.0"
+ revision = "170205fb58decfd011f1550d4cfb737230d7ae4f"
+ version = "v1.1.0"
[[projects]]
branch = "master"
@@ -96,10 +99,10 @@
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
- revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
+ revision = "14fe0d1b01d4d5fc031dd4bec1823bd3ebbe8016"
[[projects]]
- digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
+ digest = "1:f119e3205d3a1f0f19dbd7038eb37528e2c6f0933269dc344e305951fb87d632"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@@ -107,25 +110,23 @@
"model",
]
pruneopts = "UT"
- revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
- version = "v0.2.0"
+ revision = "287d3e634a1e550c9e463dd7e5a75a422c614505"
+ version = "v0.7.0"
[[projects]]
- branch = "master"
- digest = "1:c31163bd62461e0c5f7ddc7363e39ef8d9e929693e77b5c11c709b05f9cb9219"
+ digest = "1:a210815b437763623ecca8eb91e6a0bf4f2d6773c5a6c9aec0e28f19e5fd6deb"
name = "github.com/prometheus/procfs"
packages = [
".",
+ "internal/fs",
"internal/util",
- "iostats",
- "nfs",
- "xfs",
]
pruneopts = "UT"
- revision = "55ae3d9d557340b5bc24cd8aa5f6fa2c2ab31352"
+ revision = "499c85531f756d1129edd26485a5f73871eeb308"
+ version = "v0.0.5"
[[projects]]
- digest = "1:8ff03ccc603abb0d7cce94d34b613f5f6251a9e1931eba1a3f9888a9029b055c"
+ digest = "1:0496f0e99014b7fd0a560c539f51d0882731137b85494142f47e550e4657176a"
name = "github.com/stretchr/testify"
packages = [
"assert",
@@ -133,19 +134,19 @@
"suite",
]
pruneopts = "UT"
- revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
- version = "v1.3.0"
+ revision = "221dbe5ed46703ee255b1da0dec05086f5035f62"
+ version = "v1.4.0"
[[projects]]
- digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
+ digest = "1:a5158647b553c61877aa9ae74f4015000294e47981e6b8b07525edcbb0747c81"
name = "github.com/uber-go/atomic"
packages = ["."]
pruneopts = "UT"
- revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
- version = "v1.3.2"
+ revision = "df976f2515e274675050de7b3f42545de80594fd"
+ version = "v1.4.0"
[[projects]]
- digest = "1:f5c5ad1e08141e18aee1b9c37729d93d06805840421ccfc9d407787ffe969ce6"
+ digest = "1:0ec60ffd594af00ba1660bc746aa0e443d27dd4003dee55f9d08a0b4ff5431a3"
name = "github.com/uber/jaeger-lib"
packages = [
"metrics",
@@ -153,16 +154,16 @@
"metrics/prometheus",
]
pruneopts = "UT"
- revision = "0e30338a695636fe5bcf7301e8030ce8dd2a8530"
- version = "v2.0.0"
+ revision = "a87ae9d84fb038a8d79266298970720be7c80fcd"
+ version = "v2.2.0"
[[projects]]
- digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
+ digest = "1:a5158647b553c61877aa9ae74f4015000294e47981e6b8b07525edcbb0747c81"
name = "go.uber.org/atomic"
packages = ["."]
pruneopts = "UT"
- revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
- version = "v1.3.2"
+ revision = "df976f2515e274675050de7b3f42545de80594fd"
+ version = "v1.4.0"
[[projects]]
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
@@ -173,7 +174,7 @@
version = "v1.1.0"
[[projects]]
- digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
+ digest = "1:676160e6a4722b08e0e26b11521d575c2cb2b6f0c679e1ee6178c5d8dee51e5e"
name = "go.uber.org/zap"
packages = [
".",
@@ -184,8 +185,8 @@
"zapcore",
]
pruneopts = "UT"
- revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
- version = "v1.9.1"
+ revision = "27376062155ad36be76b0f12cf1572a221d3a48c"
+ version = "v1.10.0"
[[projects]]
branch = "master"
@@ -196,7 +197,23 @@
"context/ctxhttp",
]
pruneopts = "UT"
- revision = "addf6b3196f61cd44ce5a76657913698c73479d0"
+ revision = "aa69164e4478b84860dc6769c710c699c67058a3"
+
+[[projects]]
+ branch = "master"
+ digest = "1:712252802d318c8107d8f2136b99aa10feb17eca715245ed915199fbfc260155"
+ name = "golang.org/x/sys"
+ packages = ["windows"]
+ pruneopts = "UT"
+ revision = "0a153f010e6963173baba2306531d173aa843137"
+
+[[projects]]
+ digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
+ name = "gopkg.in/yaml.v2"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
+ version = "v2.2.2"
[solve-meta]
analyzer-name = "dep"
diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
index 067f15a92..3e6ac35ae 100644
--- a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
+++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
@@ -8,7 +8,7 @@
[[constraint]]
name = "github.com/prometheus/client_golang"
- version = "0.8.0"
+ version = "^1"
[[constraint]]
name = "github.com/stretchr/testify"
@@ -20,7 +20,7 @@
[[constraint]]
name = "github.com/uber/jaeger-lib"
- version = "^2.0"
+ version = "^2.2"
[[constraint]]
name = "go.uber.org/zap"
diff --git a/vendor/github.com/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile
index 1b10c0964..74e11787a 100644
--- a/vendor/github.com/uber/jaeger-client-go/Makefile
+++ b/vendor/github.com/uber/jaeger-client-go/Makefile
@@ -1,14 +1,14 @@
PROJECT_ROOT=github.com/uber/jaeger-client-go
-PACKAGES := $(shell glide novendor | grep -v -e ./thrift-gen/... -e ./thrift/...)
+PACKAGES := $(shell go list ./... | awk -F/ 'NR>1 {print "./"$$4"/..."}' | grep -v -e ./thrift-gen/... -e ./thrift/... | sort -u)
# all .go files that don't exist in hidden directories
ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e ./thrift/ \
-e ".*/\..*" \
-e ".*/_.*" \
-e ".*/mocks.*")
--include crossdock/rules.mk
+USE_DEP := true
-export GO15VENDOREXPERIMENT=1
+-include crossdock/rules.mk
RACE=-race
GOTEST=go test -v $(RACE)
@@ -58,19 +58,24 @@ lint:
.PHONY: install
install:
- glide --version || go get github.com/Masterminds/glide
+ @echo install: USE_DEP=$(USE_DEP) USE_GLIDE=$(USE_GLIDE)
ifeq ($(USE_DEP),true)
+ dep version || make install-dep
dep ensure
-else
+endif
+ifeq ($(USE_GLIDE),true)
+ glide --version || go get github.com/Masterminds/glide
glide install
endif
.PHONY: cover
cover:
- ./scripts/cover.sh $(shell go list $(PACKAGES))
- go tool cover -html=cover.out -o cover.html
+ $(GOTEST) -cover -coverprofile cover.out $(PACKAGES)
+.PHONY: cover-html
+cover-html: cover
+ go tool cover -html=cover.out -o cover.html
# This is not part of the regular test target because we don't want to slow it
# down.
@@ -101,21 +106,20 @@ idl-submodule:
thrift-image:
$(THRIFT) -version
-.PHONY: install-dep-ci
-install-dep-ci:
+.PHONY: install-dep
+install-dep:
- curl -L -s https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 -o $$GOPATH/bin/dep
- chmod +x $$GOPATH/bin/dep
.PHONY: install-ci
-install-ci: install-dep-ci install
+install-ci: install
go get github.com/wadey/gocovmerge
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
go get golang.org/x/lint/golint
.PHONY: test-ci
-test-ci:
- @./scripts/cover.sh $(shell go list $(PACKAGES))
+test-ci: cover
ifeq ($(CI_SKIP_LINT),true)
echo 'skipping lint'
else
diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md
index 6d9546e5b..604d4b571 100644
--- a/vendor/github.com/uber/jaeger-client-go/README.md
+++ b/vendor/github.com/uber/jaeger-client-go/README.md
@@ -3,7 +3,7 @@
# Jaeger Bindings for Go OpenTracing API
Instrumentation library that implements an
-[OpenTracing](http://opentracing.io) Tracer for Jaeger (https://jaegertracing.io).
+[OpenTracing Go](https://github.com/opentracing/opentracing-go) Tracer for Jaeger (https://jaegertracing.io).
**IMPORTANT**: The library's import path is based on its original location under `github.com/uber`. Do not try to import it as `github.com/jaegertracing`, it will not compile. We might revisit this in the next major release.
* :white_check_mark: `import "github.com/uber/jaeger-client-go"`
@@ -15,19 +15,20 @@ Please see [CONTRIBUTING.md](CONTRIBUTING.md).
## Installation
-We recommended using a dependency manager like [glide](https://github.com/Masterminds/glide)
+We recommended using a dependency manager like [dep](https://golang.github.io/dep/)
and [semantic versioning](http://semver.org/) when including this library into an application.
For example, Jaeger backend imports this library like this:
-```yaml
-- package: github.com/uber/jaeger-client-go
- version: ^2.7.0
+```toml
+[[constraint]]
+ name = "github.com/uber/jaeger-client-go"
+ version = "2.17"
```
If you instead want to use the latest version in `master`, you can pull it via `go get`.
Note that during `go get` you may see build errors due to incompatible dependencies, which is why
we recommend using semantic versions for dependencies. The error may be fixed by running
-`make install` (it will install `glide` if you don't have it):
+`make install` (it will install `dep` if you don't have it):
```shell
go get -u github.com/uber/jaeger-client-go/
@@ -222,7 +223,7 @@ import (
)
span := opentracing.SpanFromContext(ctx)
-ext.SamplingPriority.Set(span, 1)
+ext.SamplingPriority.Set(span, 1)
```
#### Via HTTP Headers
@@ -253,6 +254,24 @@ by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction wi
However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up.
+## SelfRef
+
+Jaeger Tracer supports an additional [reference](https://github.com/opentracing/specification/blob/1.1/specification.md#references-between-spans)
+type call `Self`. This allows a caller to provide an already established `SpanContext`.
+This allows loading and continuing spans/traces from offline (ie log-based) storage. The `Self` reference
+bypasses trace and span id generation.
+
+
+Usage requires passing in a `SpanContext` and the jaeger `Self` reference type:
+```
+span := tracer.StartSpan(
+ "continued_span",
+ SelfRef(yourSpanContext),
+)
+...
+defer span.finish()
+```
+
## License
[Apache 2.0 License](LICENSE).
diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go
index 320125087..6bce1b3b0 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/config.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/config.go
@@ -181,13 +181,14 @@ func (c Configuration) New(
// NewTracer returns a new tracer based on the current configuration, using the given options,
// and a closer func that can be used to flush buffers before shutdown.
func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Closer, error) {
+ if c.Disabled {
+ return &opentracing.NoopTracer{}, &nullCloser{}, nil
+ }
+
if c.ServiceName == "" {
return nil, nil, errors.New("no service name provided")
}
- if c.Disabled {
- return &opentracing.NoopTracer{}, &nullCloser{}, nil
- }
opts := applyOptions(options...)
tracerMetrics := jaeger.NewMetrics(opts.metrics, nil)
if c.RPCMetrics {
@@ -234,6 +235,7 @@ func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Clos
jaeger.TracerOptions.PoolSpans(opts.poolSpans),
jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan),
jaeger.TracerOptions.MaxTagValueLength(opts.maxTagValueLength),
+ jaeger.TracerOptions.NoDebugFlagOnForcedSampling(opts.noDebugFlagOnForcedSampling),
}
for _, tag := range opts.tags {
diff --git a/vendor/github.com/uber/jaeger-client-go/config/config_env.go b/vendor/github.com/uber/jaeger-client-go/config/config_env.go
index ff70ae12c..14d69b11d 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/config_env.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/config_env.go
@@ -110,6 +110,9 @@ func samplerConfigFromEnv() (*SamplerConfig, error) {
if e := os.Getenv(envSamplerManagerHostPort); e != "" {
sc.SamplingServerURL = e
+ } else if e := os.Getenv(envAgentHost); e != "" {
+ // Fallback if we know the agent host - try the sampling endpoint there
+ sc.SamplingServerURL = fmt.Sprintf("http://%s:%d/sampling", e, jaeger.DefaultSamplingServerPort)
}
if e := os.Getenv(envSamplerMaxOperations); e != "" {
diff --git a/vendor/github.com/uber/jaeger-client-go/config/options.go b/vendor/github.com/uber/jaeger-client-go/config/options.go
index 322691bea..e0e50e834 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/options.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/options.go
@@ -26,19 +26,20 @@ type Option func(c *Options)
// Options control behavior of the client.
type Options struct {
- metrics metrics.Factory
- logger jaeger.Logger
- reporter jaeger.Reporter
- sampler jaeger.Sampler
- contribObservers []jaeger.ContribObserver
- observers []jaeger.Observer
- gen128Bit bool
- poolSpans bool
- zipkinSharedRPCSpan bool
- maxTagValueLength int
- tags []opentracing.Tag
- injectors map[interface{}]jaeger.Injector
- extractors map[interface{}]jaeger.Extractor
+ metrics metrics.Factory
+ logger jaeger.Logger
+ reporter jaeger.Reporter
+ sampler jaeger.Sampler
+ contribObservers []jaeger.ContribObserver
+ observers []jaeger.Observer
+ gen128Bit bool
+ poolSpans bool
+ zipkinSharedRPCSpan bool
+ maxTagValueLength int
+ noDebugFlagOnForcedSampling bool
+ tags []opentracing.Tag
+ injectors map[interface{}]jaeger.Injector
+ extractors map[interface{}]jaeger.Extractor
}
// Metrics creates an Option that initializes Metrics in the tracer,
@@ -117,6 +118,14 @@ func MaxTagValueLength(maxTagValueLength int) Option {
}
}
+// NoDebugFlagOnForcedSampling can be used to decide whether debug flag will be set or not
+// when calling span.setSamplingPriority to force sample a span.
+func NoDebugFlagOnForcedSampling(noDebugFlagOnForcedSampling bool) Option {
+ return func(c *Options) {
+ c.noDebugFlagOnForcedSampling = noDebugFlagOnForcedSampling
+ }
+}
+
// Tag creates an option that adds a tracer-level tag.
func Tag(key string, value interface{}) Option {
return func(c *Options) {
diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go
index aa2d43fc8..e95b2ba09 100644
--- a/vendor/github.com/uber/jaeger-client-go/constants.go
+++ b/vendor/github.com/uber/jaeger-client-go/constants.go
@@ -14,9 +14,15 @@
package jaeger
+import (
+ "fmt"
+
+ "github.com/opentracing/opentracing-go"
+)
+
const (
// JaegerClientVersion is the version of the client library reported as Span tag.
- JaegerClientVersion = "Go-2.16.0"
+ JaegerClientVersion = "Go-2.19.0"
// JaegerClientVersionTagKey is the name of the tag used to report client version.
JaegerClientVersionTagKey = "jaeger.version"
@@ -83,6 +89,18 @@ const (
// DefaultUDPSpanServerPort is the default port to send the spans to, via UDP
DefaultUDPSpanServerPort = 6831
+ // DefaultSamplingServerPort is the default port to fetch sampling config from, via http
+ DefaultSamplingServerPort = 5778
+
// DefaultMaxTagValueLength is the default max length of byte array or string allowed in the tag value.
DefaultMaxTagValueLength = 256
+
+ // SelfRefType is a jaeger specific reference type that supports creating a span
+ // with an already defined context.
+ selfRefType opentracing.SpanReferenceType = 99
+)
+
+var (
+ // DefaultSamplingServerURL is the default url to fetch sampling config from, via http
+ DefaultSamplingServerURL = fmt.Sprintf("http://localhost:%d/sampling", DefaultSamplingServerPort)
)
diff --git a/vendor/github.com/uber/jaeger-client-go/context.go b/vendor/github.com/uber/jaeger-client-go/context.go
index 90045f4fc..43553655a 100644
--- a/vendor/github.com/uber/jaeger-client-go/context.go
+++ b/vendor/github.com/uber/jaeger-client-go/context.go
@@ -22,8 +22,9 @@ import (
)
const (
- flagSampled = byte(1)
- flagDebug = byte(2)
+ flagSampled = byte(1)
+ flagDebug = byte(2)
+ flagFirehose = byte(8)
)
var (
@@ -88,6 +89,11 @@ func (c SpanContext) IsDebug() bool {
return (c.flags & flagDebug) == flagDebug
}
+// IsFirehose indicates whether the firehose flag was set
+func (c SpanContext) IsFirehose() bool {
+ return (c.flags & flagFirehose) == flagFirehose
+}
+
// IsValid indicates whether this context actually represents a valid trace.
func (c SpanContext) IsValid() bool {
return c.traceID.IsValid() && c.spanID != 0
diff --git a/vendor/github.com/uber/jaeger-client-go/glide.lock b/vendor/github.com/uber/jaeger-client-go/glide.lock
index af659ca0e..c16d6d43f 100644
--- a/vendor/github.com/uber/jaeger-client-go/glide.lock
+++ b/vendor/github.com/uber/jaeger-client-go/glide.lock
@@ -1,8 +1,8 @@
-hash: 92cc8f956428fc65bee07d809a752f34376aece141c934eff02aefa08d450b72
-updated: 2019-03-23T18:26:09.960887-04:00
+hash: a4a449cfc060c2d7be850a69b171e4382a3bd00d1a0a72cfc944facc3fe263bf
+updated: 2019-09-23T17:10:15.213856-04:00
imports:
- name: github.com/beorn7/perks
- version: 3a771d992973f24aa725d07868b467d1ddfceafb
+ version: 37c8de3658fcb183f997c4e13e8337516ab753e6
subpackages:
- quantile
- name: github.com/codahale/hdrhistogram
@@ -17,11 +17,11 @@ imports:
subpackages:
- spew
- name: github.com/golang/protobuf
- version: bbd03ef6da3a115852eaf24c8a1c46aeb39aa175
+ version: 1680a479a2cfb3fa22b972af7e36d0a0fde47bf8
subpackages:
- proto
- name: github.com/matttproud/golang_protobuf_extensions
- version: c12348ce28de40eed0136aa2b644d0ee0650e56c
+ version: c182affec369e30f25d3eb8cd8a478dee585ae7d
subpackages:
- pbutil
- name: github.com/opentracing/opentracing-go
@@ -33,47 +33,49 @@ imports:
- name: github.com/pkg/errors
version: ba968bfe8b2f7e042a574c888954fccecfa385b4
- name: github.com/pmezard/go-difflib
- version: 792786c7400a136282c1664665ae0a8db921c6c2
+ version: 5d4384ee4fb2527b0a1256a821ebfc92f91efefc
subpackages:
- difflib
- name: github.com/prometheus/client_golang
- version: c5b7fccd204277076155f10851dad72b76a49317
+ version: 170205fb58decfd011f1550d4cfb737230d7ae4f
subpackages:
- prometheus
+ - prometheus/internal
- name: github.com/prometheus/client_model
- version: 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c
+ version: 14fe0d1b01d4d5fc031dd4bec1823bd3ebbe8016
subpackages:
- go
- name: github.com/prometheus/common
- version: 38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a
+ version: 287d3e634a1e550c9e463dd7e5a75a422c614505
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
- version: 780932d4fbbe0e69b84c34c20f5c8d0981e109ea
+ version: de25ac347ef9305868b04dc42425c973b863b18c
subpackages:
+ - internal/fs
- internal/util
- - nfs
- - xfs
- name: github.com/stretchr/testify
- version: f35b8ab0b5a2cef36673838d662e249dd9c94686
+ version: 85f2b59c4459e5bf57488796be8c3667cb8246d6
subpackages:
- assert
- require
- suite
+- name: github.com/uber-go/atomic
+ version: df976f2515e274675050de7b3f42545de80594fd
- name: github.com/uber/jaeger-lib
- version: 0e30338a695636fe5bcf7301e8030ce8dd2a8530
+ version: a87ae9d84fb038a8d79266298970720be7c80fcd
subpackages:
- metrics
- metrics/metricstest
- metrics/prometheus
- name: go.uber.org/atomic
- version: 1ea20fb1cbb1cc08cbd0d913a96dead89aa18289
+ version: df976f2515e274675050de7b3f42545de80594fd
- name: go.uber.org/multierr
version: 3c4937480c32f4c13a875a1829af76c98ca3d40a
- name: go.uber.org/zap
- version: ff33455a0e382e8a81d14dd7c922020b6b5e7982
+ version: 27376062155ad36be76b0f12cf1572a221d3a48c
subpackages:
- buffer
- internal/bufferpool
@@ -81,10 +83,14 @@ imports:
- internal/exit
- zapcore
- name: golang.org/x/net
- version: 49bb7cea24b1df9410e1712aa6433dae904ff66a
+ version: aa69164e4478b84860dc6769c710c699c67058a3
subpackages:
- context
- context/ctxhttp
-testImports:
-- name: github.com/uber-go/atomic
- version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8
+- name: golang.org/x/sys
+ version: 0a153f010e6963173baba2306531d173aa843137
+ subpackages:
+ - windows
+- name: gopkg.in/yaml.v2
+ version: 51d6538a90f86fe93ac480b35f37b2be17fef232
+testImports: []
diff --git a/vendor/github.com/uber/jaeger-client-go/glide.yaml b/vendor/github.com/uber/jaeger-client-go/glide.yaml
index b3e5b80bc..3c7b5c379 100644
--- a/vendor/github.com/uber/jaeger-client-go/glide.yaml
+++ b/vendor/github.com/uber/jaeger-client-go/glide.yaml
@@ -12,11 +12,16 @@ import:
- metrics
- package: github.com/pkg/errors
version: ~0.8.0
+- package: go.uber.org/zap
+ source: https://github.com/uber-go/zap.git
+ version: ^1
+- package: github.com/uber-go/atomic
+ version: ^1
+- package: github.com/prometheus/client_golang
+ version: ^1
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert
- require
- suite
-- package: github.com/prometheus/client_golang
- version: v0.8.0
diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go
index fe6288c4b..27163ebe4 100644
--- a/vendor/github.com/uber/jaeger-client-go/reporter.go
+++ b/vendor/github.com/uber/jaeger-client-go/reporter.go
@@ -93,13 +93,14 @@ func NewInMemoryReporter() *InMemoryReporter {
// Report implements Report() method of Reporter by storing the span in the buffer.
func (r *InMemoryReporter) Report(span *Span) {
r.lock.Lock()
- r.spans = append(r.spans, span)
+ // Need to retain the span otherwise it will be released
+ r.spans = append(r.spans, span.Retain())
r.lock.Unlock()
}
-// Close implements Close() method of Reporter by doing nothing.
+// Close implements Close() method of Reporter
func (r *InMemoryReporter) Close() {
- // no-op
+ r.Reset()
}
// SpansSubmitted returns the number of spans accumulated in the buffer.
@@ -122,7 +123,12 @@ func (r *InMemoryReporter) GetSpans() []opentracing.Span {
func (r *InMemoryReporter) Reset() {
r.lock.Lock()
defer r.lock.Unlock()
- r.spans = nil
+
+ // Before reset the collection need to release Span memory
+ for _, span := range r.spans {
+ span.(*Span).Release()
+ }
+ r.spans = r.spans[:0]
}
// ------------------------------
@@ -218,7 +224,8 @@ func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter {
// because some of them may still be successfully added to the queue.
func (r *remoteReporter) Report(span *Span) {
select {
- case r.queue <- reporterQueueItem{itemType: reporterQueueItemSpan, span: span}:
+ // Need to retain the span otherwise it will be released
+ case r.queue <- reporterQueueItem{itemType: reporterQueueItemSpan, span: span.Retain()}:
atomic.AddInt64(&r.queueLength, 1)
default:
r.metrics.ReporterDropped.Inc(1)
@@ -278,6 +285,7 @@ func (r *remoteReporter) processQueue() {
// to reduce the number of gauge stats, we only emit queue length on flush
r.metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength))
}
+ span.Release()
case reporterQueueItemClose:
timer.Stop()
flush()
diff --git a/vendor/github.com/uber/jaeger-client-go/sampler.go b/vendor/github.com/uber/jaeger-client-go/sampler.go
index 3e1630953..ea6984e02 100644
--- a/vendor/github.com/uber/jaeger-client-go/sampler.go
+++ b/vendor/github.com/uber/jaeger-client-go/sampler.go
@@ -28,7 +28,6 @@ import (
)
const (
- defaultSamplingServerURL = "http://localhost:5778/sampling"
defaultSamplingRefreshInterval = time.Minute
defaultMaxOperations = 2000
)
@@ -348,24 +347,27 @@ func (s *adaptiveSampler) Equal(other Sampler) bool {
func (s *adaptiveSampler) update(strategies *sampling.PerOperationSamplingStrategies) {
s.Lock()
defer s.Unlock()
+ newSamplers := map[string]*GuaranteedThroughputProbabilisticSampler{}
for _, strategy := range strategies.PerOperationStrategies {
operation := strategy.Operation
samplingRate := strategy.ProbabilisticSampling.SamplingRate
lowerBound := strategies.DefaultLowerBoundTracesPerSecond
if sampler, ok := s.samplers[operation]; ok {
sampler.update(lowerBound, samplingRate)
+ newSamplers[operation] = sampler
} else {
sampler := newGuaranteedThroughputProbabilisticSampler(
lowerBound,
samplingRate,
)
- s.samplers[operation] = sampler
+ newSamplers[operation] = sampler
}
}
s.lowerBound = strategies.DefaultLowerBoundTracesPerSecond
if s.defaultSampler.SamplingRate() != strategies.DefaultSamplingProbability {
s.defaultSampler = newProbabilisticSampler(strategies.DefaultSamplingProbability)
}
+ s.samplers = newSamplers
}
// -----------------------
@@ -432,7 +434,7 @@ func applySamplerOptions(opts ...SamplerOption) samplerOptions {
options.maxOperations = defaultMaxOperations
}
if options.samplingServerURL == "" {
- options.samplingServerURL = defaultSamplingServerURL
+ options.samplingServerURL = DefaultSamplingServerURL
}
if options.metrics == nil {
options.metrics = NewNullMetrics()
diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go
index f0b497a90..9df8b6017 100644
--- a/vendor/github.com/uber/jaeger-client-go/span.go
+++ b/vendor/github.com/uber/jaeger-client-go/span.go
@@ -16,6 +16,7 @@ package jaeger
import (
"sync"
+ "sync/atomic"
"time"
"github.com/opentracing/opentracing-go"
@@ -25,6 +26,10 @@ import (
// Span implements opentracing.Span
type Span struct {
+ // referenceCounter used to increase the lifetime of
+ // the object before return it into the pool.
+ referenceCounter int32
+
sync.RWMutex
tracer *Tracer
@@ -91,6 +96,38 @@ func (s *Span) SetTag(key string, value interface{}) opentracing.Span {
return s
}
+// SpanContext returns span context
+func (s *Span) SpanContext() SpanContext {
+ s.Lock()
+ defer s.Unlock()
+ return s.context
+}
+
+// StartTime returns span start time
+func (s *Span) StartTime() time.Time {
+ s.Lock()
+ defer s.Unlock()
+ return s.startTime
+}
+
+// Duration returns span duration
+func (s *Span) Duration() time.Duration {
+ s.Lock()
+ defer s.Unlock()
+ return s.duration
+}
+
+// Tags returns tags for span
+func (s *Span) Tags() opentracing.Tags {
+ s.Lock()
+ defer s.Unlock()
+ var result = make(opentracing.Tags)
+ for _, tag := range s.tags {
+ result[tag.key] = tag.value
+ }
+ return result
+}
+
func (s *Span) setTagNoLocking(key string, value interface{}) {
s.tags = append(s.tags, Tag{key: key, value: value})
}
@@ -174,6 +211,8 @@ func (s *Span) BaggageItem(key string) string {
}
// Finish implements opentracing.Span API
+// After finishing the Span object it returns back to the allocator unless the reporter retains it again,
+// so after that, the Span object should no longer be used because it won't be valid anymore.
func (s *Span) Finish() {
s.FinishWithOptions(opentracing.FinishOptions{})
}
@@ -197,6 +236,7 @@ func (s *Span) FinishWithOptions(options opentracing.FinishOptions) {
}
s.Unlock()
// call reportSpan even for non-sampled traces, to return span to the pool
+ // and update metrics counter
s.tracer.reportSpan(s)
}
@@ -225,25 +265,66 @@ func (s *Span) OperationName() string {
return s.operationName
}
+// Retain increases object counter to increase the lifetime of the object
+func (s *Span) Retain() *Span {
+ atomic.AddInt32(&s.referenceCounter, 1)
+ return s
+}
+
+// Release decrements object counter and return to the
+// allocator manager when counter will below zero
+func (s *Span) Release() {
+ if atomic.AddInt32(&s.referenceCounter, -1) == -1 {
+ s.tracer.spanAllocator.Put(s)
+ }
+}
+
+// reset span state and release unused data
+func (s *Span) reset() {
+ s.firstInProcess = false
+ s.context = emptyContext
+ s.operationName = ""
+ s.tracer = nil
+ s.startTime = time.Time{}
+ s.duration = 0
+ s.observer = nil
+ atomic.StoreInt32(&s.referenceCounter, 0)
+
+ // Note: To reuse memory we can save the pointers on the heap
+ s.tags = s.tags[:0]
+ s.logs = s.logs[:0]
+ s.references = s.references[:0]
+}
+
func (s *Span) serviceName() string {
return s.tracer.serviceName
}
// setSamplingPriority returns true if the flag was updated successfully, false otherwise.
func setSamplingPriority(s *Span, value interface{}) bool {
- s.Lock()
- defer s.Unlock()
val, ok := value.(uint16)
if !ok {
return false
}
+ s.Lock()
+ defer s.Unlock()
if val == 0 {
s.context.flags = s.context.flags & (^flagSampled)
return true
}
- if s.tracer.isDebugAllowed(s.operationName) {
+ if s.tracer.options.noDebugFlagOnForcedSampling {
+ s.context.flags = s.context.flags | flagSampled
+ return true
+ } else if s.tracer.isDebugAllowed(s.operationName) {
s.context.flags = s.context.flags | flagDebug | flagSampled
return true
}
return false
}
+
+// EnableFirehose enables firehose flag on the span context
+func EnableFirehose(s *Span) {
+ s.Lock()
+ defer s.Unlock()
+ s.context.flags |= flagFirehose
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/span_allocator.go b/vendor/github.com/uber/jaeger-client-go/span_allocator.go
new file mode 100644
index 000000000..6fe0cd0ce
--- /dev/null
+++ b/vendor/github.com/uber/jaeger-client-go/span_allocator.go
@@ -0,0 +1,56 @@
+// Copyright (c) 2019 The Jaeger Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jaeger
+
+import "sync"
+
+// SpanAllocator abstraction of managign span allocations
+type SpanAllocator interface {
+ Get() *Span
+ Put(*Span)
+}
+
+type syncPollSpanAllocator struct {
+ spanPool sync.Pool
+}
+
+func newSyncPollSpanAllocator() SpanAllocator {
+ return &syncPollSpanAllocator{
+ spanPool: sync.Pool{New: func() interface{} {
+ return &Span{}
+ }},
+ }
+}
+
+func (pool *syncPollSpanAllocator) Get() *Span {
+ return pool.spanPool.Get().(*Span)
+}
+
+func (pool *syncPollSpanAllocator) Put(span *Span) {
+ span.reset()
+ pool.spanPool.Put(span)
+}
+
+type simpleSpanAllocator struct{}
+
+func (pool simpleSpanAllocator) Get() *Span {
+ return &Span{}
+}
+
+func (pool simpleSpanAllocator) Put(span *Span) {
+ // @comment https://github.com/jaegertracing/jaeger-client-go/pull/381#issuecomment-475904351
+ // since finished spans are not reused, no need to reset them
+ // span.reset()
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go
index d87fb10be..745a0c38a 100644
--- a/vendor/github.com/uber/jaeger-client-go/tracer.go
+++ b/vendor/github.com/uber/jaeger-client-go/tracer.go
@@ -47,15 +47,15 @@ type Tracer struct {
randomNumber func() uint64
options struct {
- poolSpans bool
- gen128Bit bool // whether to generate 128bit trace IDs
- zipkinSharedRPCSpan bool
- highTraceIDGenerator func() uint64 // custom high trace ID generator
- maxTagValueLength int
+ gen128Bit bool // whether to generate 128bit trace IDs
+ zipkinSharedRPCSpan bool
+ highTraceIDGenerator func() uint64 // custom high trace ID generator
+ maxTagValueLength int
+ noDebugFlagOnForcedSampling bool
// more options to come
}
- // pool for Span objects
- spanPool sync.Pool
+ // allocator of Span objects
+ spanAllocator SpanAllocator
injectors map[interface{}]Injector
extractors map[interface{}]Extractor
@@ -81,15 +81,13 @@ func NewTracer(
options ...TracerOption,
) (opentracing.Tracer, io.Closer) {
t := &Tracer{
- serviceName: serviceName,
- sampler: sampler,
- reporter: reporter,
- injectors: make(map[interface{}]Injector),
- extractors: make(map[interface{}]Extractor),
- metrics: *NewNullMetrics(),
- spanPool: sync.Pool{New: func() interface{} {
- return &Span{}
- }},
+ serviceName: serviceName,
+ sampler: sampler,
+ reporter: reporter,
+ injectors: make(map[interface{}]Injector),
+ extractors: make(map[interface{}]Extractor),
+ metrics: *NewNullMetrics(),
+ spanAllocator: simpleSpanAllocator{},
}
for _, option := range options {
@@ -148,7 +146,15 @@ func NewTracer(
if hostname, err := os.Hostname(); err == nil {
t.tags = append(t.tags, Tag{key: TracerHostnameTagKey, value: hostname})
}
- if ip, err := utils.HostIP(); err == nil {
+ if ipval, ok := t.getTag(TracerIPTagKey); ok {
+ ipv4, err := utils.ParseIPToUint32(ipval.(string))
+ if err != nil {
+ t.hostIPv4 = 0
+ t.logger.Error("Unable to convert the externally provided ip to uint32: " + err.Error())
+ } else {
+ t.hostIPv4 = ipv4
+ }
+ } else if ip, err := utils.HostIP(); err == nil {
t.tags = append(t.tags, Tag{key: TracerIPTagKey, value: ip.String()})
t.hostIPv4 = utils.PackIPAsUint32(ip)
} else {
@@ -217,20 +223,30 @@ func (t *Tracer) startSpanWithOptions(
var references []Reference
var parent SpanContext
var hasParent bool // need this because `parent` is a value, not reference
+ var ctx SpanContext
+ var isSelfRef bool
for _, ref := range options.References {
- ctx, ok := ref.ReferencedContext.(SpanContext)
+ ctxRef, ok := ref.ReferencedContext.(SpanContext)
if !ok {
t.logger.Error(fmt.Sprintf(
"Reference contains invalid type of SpanReference: %s",
reflect.ValueOf(ref.ReferencedContext)))
continue
}
- if !isValidReference(ctx) {
+ if !isValidReference(ctxRef) {
+ continue
+ }
+
+ if ref.Type == selfRefType {
+ isSelfRef = true
+ ctx = ctxRef
continue
}
- references = append(references, Reference{Type: ref.Type, Context: ctx})
+
+ references = append(references, Reference{Type: ref.Type, Context: ctxRef})
+
if !hasParent {
- parent = ctx
+ parent = ctxRef
hasParent = ref.Type == opentracing.ChildOfRef
}
}
@@ -246,42 +262,43 @@ func (t *Tracer) startSpanWithOptions(
}
var samplerTags []Tag
- var ctx SpanContext
newTrace := false
- if !hasParent || !parent.IsValid() {
- newTrace = true
- ctx.traceID.Low = t.randomID()
- if t.options.gen128Bit {
- ctx.traceID.High = t.options.highTraceIDGenerator()
- }
- ctx.spanID = SpanID(ctx.traceID.Low)
- ctx.parentID = 0
- ctx.flags = byte(0)
- if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) {
- ctx.flags |= (flagSampled | flagDebug)
- samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}}
- } else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled {
- ctx.flags |= flagSampled
- samplerTags = tags
- }
- } else {
- ctx.traceID = parent.traceID
- if rpcServer && t.options.zipkinSharedRPCSpan {
- // Support Zipkin's one-span-per-RPC model
- ctx.spanID = parent.spanID
- ctx.parentID = parent.parentID
+ if !isSelfRef {
+ if !hasParent || !parent.IsValid() {
+ newTrace = true
+ ctx.traceID.Low = t.randomID()
+ if t.options.gen128Bit {
+ ctx.traceID.High = t.options.highTraceIDGenerator()
+ }
+ ctx.spanID = SpanID(ctx.traceID.Low)
+ ctx.parentID = 0
+ ctx.flags = byte(0)
+ if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) {
+ ctx.flags |= (flagSampled | flagDebug)
+ samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}}
+ } else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled {
+ ctx.flags |= flagSampled
+ samplerTags = tags
+ }
} else {
- ctx.spanID = SpanID(t.randomID())
- ctx.parentID = parent.spanID
+ ctx.traceID = parent.traceID
+ if rpcServer && t.options.zipkinSharedRPCSpan {
+ // Support Zipkin's one-span-per-RPC model
+ ctx.spanID = parent.spanID
+ ctx.parentID = parent.parentID
+ } else {
+ ctx.spanID = SpanID(t.randomID())
+ ctx.parentID = parent.spanID
+ }
+ ctx.flags = parent.flags
}
- ctx.flags = parent.flags
- }
- if hasParent {
- // copy baggage items
- if l := len(parent.baggage); l > 0 {
- ctx.baggage = make(map[string]string, len(parent.baggage))
- for k, v := range parent.baggage {
- ctx.baggage[k] = v
+ if hasParent {
+ // copy baggage items
+ if l := len(parent.baggage); l > 0 {
+ ctx.baggage = make(map[string]string, len(parent.baggage))
+ for k, v := range parent.baggage {
+ ctx.baggage[k] = v
+ }
}
}
}
@@ -350,18 +367,20 @@ func (t *Tracer) Tags() []opentracing.Tag {
return tags
}
+// getTag returns the value of specific tag, if not exists, return nil.
+func (t *Tracer) getTag(key string) (interface{}, bool) {
+ for _, tag := range t.tags {
+ if tag.key == key {
+ return tag.value, true
+ }
+ }
+ return nil, false
+}
+
// newSpan returns an instance of a clean Span object.
// If options.PoolSpans is true, the spans are retrieved from an object pool.
func (t *Tracer) newSpan() *Span {
- if !t.options.poolSpans {
- return &Span{}
- }
- sp := t.spanPool.Get().(*Span)
- sp.context = emptyContext
- sp.tracer = nil
- sp.tags = nil
- sp.logs = nil
- return sp
+ return t.spanAllocator.Get()
}
func (t *Tracer) startSpanInternal(
@@ -416,12 +435,15 @@ func (t *Tracer) startSpanInternal(
func (t *Tracer) reportSpan(sp *Span) {
t.metrics.SpansFinished.Inc(1)
+
+ // Note: if the reporter is processing Span asynchronously need to Retain() it
+ // otherwise, in the racing condition will be rewritten span data before it will be sent
+ // * To remove object use method span.Release()
if sp.context.IsSampled() {
t.reporter.Report(sp)
}
- if t.options.poolSpans {
- t.spanPool.Put(sp)
- }
+
+ sp.Release()
}
// randomID generates a random trace/span ID, using tracer.random() generator.
@@ -443,3 +465,13 @@ func (t *Tracer) setBaggage(sp *Span, key, value string) {
func (t *Tracer) isDebugAllowed(operation string) bool {
return t.debugThrottler.IsAllowed(operation)
}
+
+// SelfRef creates an opentracing compliant SpanReference from a jaeger
+// SpanContext. This is a factory function in order to encapsulate jaeger specific
+// types.
+func SelfRef(ctx SpanContext) opentracing.SpanReference {
+ return opentracing.SpanReference{
+ Type: selfRefType,
+ ReferencedContext: ctx,
+ }
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/tracer_options.go b/vendor/github.com/uber/jaeger-client-go/tracer_options.go
index b4176cc72..469685bb4 100644
--- a/vendor/github.com/uber/jaeger-client-go/tracer_options.go
+++ b/vendor/github.com/uber/jaeger-client-go/tracer_options.go
@@ -81,7 +81,11 @@ func (tracerOptions) RandomNumber(randomNumber func() uint64) TracerOption {
// that can access parent spans after those spans have been finished.
func (tracerOptions) PoolSpans(poolSpans bool) TracerOption {
return func(tracer *Tracer) {
- tracer.options.poolSpans = poolSpans
+ if poolSpans {
+ tracer.spanAllocator = newSyncPollSpanAllocator()
+ } else {
+ tracer.spanAllocator = simpleSpanAllocator{}
+ }
}
}
@@ -122,6 +126,12 @@ func (tracerOptions) Gen128Bit(gen128Bit bool) TracerOption {
}
}
+func (tracerOptions) NoDebugFlagOnForcedSampling(noDebugFlagOnForcedSampling bool) TracerOption {
+ return func(tracer *Tracer) {
+ tracer.options.noDebugFlagOnForcedSampling = noDebugFlagOnForcedSampling
+ }
+}
+
func (tracerOptions) HighTraceIDGenerator(highTraceIDGenerator func() uint64) TracerOption {
return func(tracer *Tracer) {
tracer.options.highTraceIDGenerator = highTraceIDGenerator
diff --git a/vendor/gopkg.in/yaml.v2/decode.go b/vendor/gopkg.in/yaml.v2/decode.go
index e4e56e28e..91679b5b4 100644
--- a/vendor/gopkg.in/yaml.v2/decode.go
+++ b/vendor/gopkg.in/yaml.v2/decode.go
@@ -229,6 +229,10 @@ type decoder struct {
mapType reflect.Type
terrors []string
strict bool
+
+ decodeCount int
+ aliasCount int
+ aliasDepth int
}
var (
@@ -315,6 +319,13 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm
}
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
+ d.decodeCount++
+ if d.aliasDepth > 0 {
+ d.aliasCount++
+ }
+ if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > 0.99 {
+ failf("document contains excessive aliasing")
+ }
switch n.kind {
case documentNode:
return d.document(n, out)
@@ -353,7 +364,9 @@ func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
failf("anchor '%s' value contains itself", n.value)
}
d.aliases[n] = true
+ d.aliasDepth++
good = d.unmarshal(n.alias, out)
+ d.aliasDepth--
delete(d.aliases, n)
return good
}
diff --git a/vendor/gopkg.in/yaml.v2/resolve.go b/vendor/gopkg.in/yaml.v2/resolve.go
index 6c151db6f..4120e0c91 100644
--- a/vendor/gopkg.in/yaml.v2/resolve.go
+++ b/vendor/gopkg.in/yaml.v2/resolve.go
@@ -81,7 +81,7 @@ func resolvableTag(tag string) bool {
return false
}
-var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
+var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
func resolve(tag string, in string) (rtag string, out interface{}) {
if !resolvableTag(tag) {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3a27eea12..1d92a249d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -43,7 +43,7 @@ github.com/containernetworking/cni/pkg/version
github.com/containernetworking/cni/libcni
github.com/containernetworking/cni/pkg/invoke
github.com/containernetworking/cni/pkg/types/020
-# github.com/containernetworking/plugins v0.8.1
+# github.com/containernetworking/plugins v0.8.2
github.com/containernetworking/plugins/pkg/ns
github.com/containernetworking/plugins/pkg/ip
github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator
@@ -109,7 +109,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
github.com/containers/psgo/internal/host
-# github.com/containers/storage v1.13.3
+# github.com/containers/storage v1.13.4
github.com/containers/storage
github.com/containers/storage/pkg/archive
github.com/containers/storage/pkg/chrootarchive
@@ -213,7 +213,7 @@ github.com/docker/docker/api/types/time
github.com/docker/docker/api/types/volume
github.com/docker/docker/api/types/blkiodev
github.com/docker/docker/api/types/strslice
-# github.com/docker/docker-credential-helpers v0.6.2
+# github.com/docker/docker-credential-helpers v0.6.3
github.com/docker/docker-credential-helpers/credentials
github.com/docker/docker-credential-helpers/client
# github.com/docker/go-connections v0.4.0
@@ -308,7 +308,7 @@ github.com/modern-go/reflect2
github.com/mrunalp/fileutils
# github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c
github.com/mtrmac/gpgme
-# github.com/onsi/ginkgo v1.8.0
+# github.com/onsi/ginkgo v1.10.1
github.com/onsi/ginkgo/ginkgo
github.com/onsi/ginkgo
github.com/onsi/ginkgo/config
@@ -335,7 +335,7 @@ github.com/onsi/ginkgo/internal/containernode
github.com/onsi/ginkgo/internal/leafnodes
github.com/onsi/ginkgo/internal/spec
github.com/onsi/ginkgo/internal/specrunner
-# github.com/onsi/gomega v1.5.0
+# github.com/onsi/gomega v1.7.0
github.com/onsi/gomega
github.com/onsi/gomega/gexec
github.com/onsi/gomega/internal/assertion
@@ -424,16 +424,16 @@ github.com/sirupsen/logrus
github.com/sirupsen/logrus/hooks/syslog
# github.com/spf13/cobra v0.0.5
github.com/spf13/cobra
-# github.com/spf13/pflag v1.0.3
+# github.com/spf13/pflag v1.0.5
github.com/spf13/pflag
-# github.com/stretchr/testify v1.3.0
+# github.com/stretchr/testify v1.4.0
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
# github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/syndtr/gocapability/capability
# github.com/tchap/go-patricia v2.3.0+incompatible
github.com/tchap/go-patricia/patricia
-# github.com/uber/jaeger-client-go v2.16.0+incompatible
+# github.com/uber/jaeger-client-go v2.19.0+incompatible
github.com/uber/jaeger-client-go
github.com/uber/jaeger-client-go/config
github.com/uber/jaeger-client-go/internal/baggage
@@ -549,7 +549,7 @@ gopkg.in/fsnotify.v1
gopkg.in/inf.v0
# gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
gopkg.in/tomb.v1
-# gopkg.in/yaml.v2 v2.2.2
+# gopkg.in/yaml.v2 v2.2.3
gopkg.in/yaml.v2
# k8s.io/api v0.0.0-20190813020757-36bff7324fb7
k8s.io/api/core/v1
diff --git a/version/version.go b/version/version.go
index 348a69594..2c4d69b78 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,7 +4,7 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "1.6.0-dev"
+const Version = "1.6.2-dev"
// RemoteAPIVersion is the version for the remote
// client API. It is used to determine compatibility