Compare commits

...

95 Commits

Author SHA1 Message Date
Daniel J Walsh
1119299c4b Bump to v0.2.0
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-09 08:51:37 -04:00
Miloslav Trmač
2d91b93ad0 Merge pull request #893 from edsantiago/podman_info_broke
Fix for yet another breaking podman change
2020-04-09 14:30:21 +02:00
Ed Santiago
cf4dff471c Fix for yet another breaking podman change
'podman info' changed format, again, without preserving backward
compatibility. Basically, some keys that used to be lower-case
are now upper-case-first-letter.

These tests need to work with new podman on rawhide, and
old podman on f31/f32 and possibly RHEL. We must therefore
add a revolting workaround for the change.

Signed-off-by: Ed Santiago <santiago@redhat.com>
2020-04-08 15:32:44 -06:00
Daniel J Walsh
101901ab40 Merge pull request #891 from mtrmac/vendor-tidy
Run (go mod tidy) before (go mod vendor)
2020-04-08 14:54:20 -04:00
Miloslav Trmač
17848a1868 Run (go mod tidy) before (go mod vendor)
This is conceptually consistent: First change the set of
dependencies, then update the vendored copy.

(Due to (go mod verify) afterwards, and CI running this again,
this should not make a difference in practice, so this is just
a clean-up.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-04-08 20:01:51 +02:00
Miloslav Trmač
9d21b48f8b Merge pull request #892 from mtrmac/revert-urfave-cli
Revert "Bump github.com/urfave/cli from 1.22.1 to 1.22.4"
2020-04-08 20:01:27 +02:00
Miloslav Trmač
2873d8ec91 Revert "Bump github.com/urfave/cli from 1.22.1 to 1.22.4"
This reverts commit 8c8d9bd23f.

When correctly vendored, this breaks tests.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-04-08 17:15:39 +02:00
Daniel J Walsh
9d63c7cd54 Merge pull request #881 from containers/dependabot/go_modules/github.com/urfave/cli-1.22.4
Bump github.com/urfave/cli from 1.22.1 to 1.22.4
2020-04-08 09:59:59 -04:00
Miloslav Trmač
1f321dfc69 Merge pull request #890 from mtrmac/make-vendor
Fix (make vendor)
2020-04-08 15:20:59 +02:00
Miloslav Trmač
702165af46 Fix (make vendor)
(export a=b command args) does not run (command args) with a=b,
it sets $a to b, and marks variables $a $command $args as exported,
i.e. (command args) is not run.

So, before https://github.com/containers/skopeo/pull/888 we were not actually
running (go mod tidy), and now we are not running (go mod vendor).

Just use $(GO), which already sets GO111MODULE=on, without the extra export.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-04-08 14:25:51 +02:00
Daniel J Walsh
8c8d9bd23f Bump github.com/urfave/cli from 1.22.1 to 1.22.4
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-08 07:07:43 -04:00
Miloslav Trmač
6ac3dce04e Merge pull request #889 from rhatdan/vendor
Bump containers/image to v5.4.3
2020-04-07 22:38:37 +02:00
Daniel J Walsh
5b479b1090 Bump containers/image to v5.4.3
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-07 16:20:29 -04:00
Daniel J Walsh
b2033f3f9d Merge pull request #888 from vrothberg/tidy
make vendor: run `tidy` after `vendor`
2020-04-07 16:18:20 -04:00
Valentin Rothberg
f68b53afcd make vendor: run tidy after vendor
Run `go mod tidy` after `go mod vendor` to properly clean up the
dependencies.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-04-07 15:43:03 +02:00
Daniel J Walsh
71a8ff0122 Merge pull request #887 from vrothberg/image
vendor c/image v5.4.2
2020-04-07 09:40:17 -04:00
Valentin Rothberg
6569236642 vendor c/image v5.4.2
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-04-07 12:25:12 +02:00
Daniel J Walsh
8fa332618b Merge pull request #884 from containers/dependabot/go_modules/github.com/containers/image/v5-5.4.1
Bump github.com/containers/image/v5 from 5.4.0 to 5.4.1
2020-04-06 15:33:53 -04:00
dependabot-preview[bot]
0eef946e55 Bump github.com/containers/image/v5 from 5.4.0 to 5.4.1
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.4.0 to 5.4.1.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.4.0...v5.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-06 15:08:23 -04:00
Daniel J Walsh
5d512e265a Merge pull request #879 from mtrmac/drop-buildah
Remove dependency on buildah
2020-03-31 18:07:36 -04:00
Miloslav Trmač
82e79e3f43 Remove dependency on buildah
We no longer need it only to keep other dependencies
up to date.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-31 23:17:34 +02:00
Miloslav Trmač
3e9d8ae731 Merge pull request #877 from containers/dependabot/go_modules/github.com/containers/image/v5-5.4.0
Bump github.com/containers/image/v5 from 5.3.1 to 5.4.0
2020-03-31 22:56:06 +02:00
dependabot-preview[bot]
325327dc3f Bump github.com/containers/image/v5 from 5.3.1 to 5.4.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.3.1...v5.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-31 22:19:09 +02:00
Miloslav Trmač
bd20786c38 Merge pull request #873 from edsantiago/runc_only_on_cgroupsv1
Update on #834: force runc only when cgroupsv1
2020-03-31 15:17:44 +02:00
Ed Santiago
6e3f4c99be Update on #834: force runc only when cgroupsv1
PR 834 broke Fedora gating tests, because "--runtime runc"
doesn't work so well on Rawhide. Let's try to be smarter
about when we add that override.

Signed-off-by: Ed Santiago <santiago@redhat.com>
2020-03-31 05:14:35 -06:00
Daniel J Walsh
6db5626c3b Merge pull request #868 from rhatdan/tmpdir
Skopeo should support for BigFilesTemporaryDir (SystemContext)
2020-03-30 14:17:38 -04:00
Miloslav Trmač
eb199dce9c Merge pull request #872 from mtrmac/revert-downgrades
Revert the removal of buildah dependency
2020-03-30 16:30:51 +02:00
Miloslav Trmač
27b330f6f1 Revert the removal of buildah dependency
We currently need it to drag in recent versions of other dependencies,
per https://github.com/containers/skopeo/issues/796 .

I'll work to update the relevant dependencies in c/image, but that will
only propagate to skopeo in the next c/image release; in the meantime,
this at least undoes the downgrades.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-30 16:04:24 +02:00
Daniel J Walsh
f231b7776b Update docs/skopeo.1.md
Co-Authored-By: Miloslav Trmač <mitr@redhat.com>
2020-03-30 09:53:50 -04:00
Miloslav Trmač
018a0108b1 Merge pull request #870 from PhilippHomann/master
Sync: Add example with repository
2020-03-30 14:54:35 +02:00
Philipp Homann
55044627cc Add example with repository
Fixes #854

Signed-off-by: Philipp Homann <homann.philipp@googlemail.com>
2020-03-30 08:31:19 +02:00
Daniel J Walsh
aa20fbfdf5 Skopeo should support for BigFilesTemporaryDir (SystemContext)
Enhancement request: https://github.com/containers/skopeo/issues/805

Also sorted commands and options on skopeo man page and skopeo --help

Originally submitted by  Michel Belleau <michel.belleau@malaiwah.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-29 06:00:47 -04:00
Daniel J Walsh
a6f5ef18c5 Merge pull request #867 from rhatdan/vendor
Update containers/image to v5.3.1
2020-03-28 07:19:08 -04:00
Daniel J Walsh
274efdf28f Update containers/image v5.3.1
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-28 06:28:49 -04:00
Daniel J Walsh
501452a500 Merge pull request #864 from containers/dependabot/go_modules/github.com/containers/storage-1.16.6
Bump github.com/containers/storage from 1.16.5 to 1.16.6
2020-03-25 09:16:26 -04:00
dependabot-preview[bot]
336164246b Bump github.com/containers/storage from 1.16.5 to 1.16.6
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.5 to 1.16.6.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.5...v1.16.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-25 08:24:03 -04:00
Miloslav Trmač
e31d5a0e8f Merge pull request #793 from JirkaChadima/feat-override-variant
Adds the --override-variant command line flag
2020-03-20 16:10:56 +01:00
Valentin Rothberg
ed883c5230 Merge branch 'master' into feat-override-variant 2020-03-20 15:43:39 +01:00
Daniel J Walsh
7fee7d5019 Merge pull request #861 from containers/dependabot/go_modules/github.com/containers/image/v5-5.3.0
Bump github.com/containers/image/v5 from 5.2.1 to 5.3.0
2020-03-20 09:43:17 -04:00
dependabot-preview[bot]
970af7d1b4 Bump github.com/containers/image/v5 from 5.2.1 to 5.3.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.2.1 to 5.3.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.2.1...v5.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-19 22:23:16 +01:00
Miloslav Trmač
12865fdfb8 Merge pull request #862 from edsantiago/registry_fqin
Use fully-qualified image names
2020-03-19 22:22:36 +01:00
Ed Santiago
1e7fe55be0 Use fully-qualified image names
Replace shortnames with FQINs; this should allow tests to
run regardless of the state of registries.conf.

And, fix one broken new test that invoked 'jq' (without dot).
This usage works in Fedora, but not in RHEL.

Signed-off-by: Ed Santiago <santiago@redhat.com>
2020-03-19 14:13:18 -06:00
Miloslav Trmač
7170702ee4 Merge pull request #860 from containers/dependabot/go_modules/github.com/containers/common-0.6.1
Bump github.com/containers/common from 0.5.0 to 0.6.1
2020-03-19 13:29:50 +01:00
dependabot-preview[bot]
081e4834d5 Bump github.com/containers/common from 0.5.0 to 0.6.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.5.0 to 0.6.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.5.0...v0.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-19 06:52:08 -04:00
Miloslav Trmač
b541fef300 Merge pull request #855 from containers/dependabot/go_modules/github.com/containers/storage-1.16.5
Bump github.com/containers/storage from 1.16.3 to 1.16.5
2020-03-18 12:08:56 +01:00
dependabot-preview[bot]
bd59677a84 Bump github.com/containers/storage from 1.16.3 to 1.16.5
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.3 to 1.16.5.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.3...v1.16.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-03-17 21:37:14 +01:00
Daniel J Walsh
7a0a8c25a2 Merge pull request #848 from containers/dependabot/go_modules/github.com/containers/common-0.5.0
Bump github.com/containers/common from 0.4.4 to 0.5.0
2020-03-13 10:49:10 -04:00
Daniel J Walsh
a7ff66f09e Merge pull request #829 from rhatdan/REGISTRY_AUTH_FILE
add support for REGISTRY_AUTH_FILE
2020-03-13 09:21:24 -04:00
dependabot-preview[bot]
dda59750e6 Bump github.com/containers/common from 0.4.4 to 0.5.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.4.4 to 0.5.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.4.4...v0.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-13 09:19:24 -04:00
Miloslav Trmač
a99450c002 Merge pull request #847 from containers/dependabot/go_modules/github.com/containers/storage-1.16.3
Bump github.com/containers/storage from 1.16.2 to 1.16.3
2020-03-13 00:22:38 +01:00
dependabot-preview[bot]
ebeb1c3f59 Bump github.com/containers/storage from 1.16.2 to 1.16.3
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.2 to 1.16.3.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.2...v1.16.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-13 00:00:20 +01:00
Miloslav Trmač
cd1ffbdb90 Merge pull request #846 from containers/dependabot/go_modules/github.com/containers/common-0.4.4
Bump github.com/containers/common from 0.4.3 to 0.4.4
2020-03-12 23:51:42 +01:00
dependabot-preview[bot]
33ebce0880 Bump github.com/containers/common from 0.4.3 to 0.4.4
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.4.3...v0.4.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-12 23:23:27 +01:00
Daniel J Walsh
cc43fd50d7 Merge pull request #844 from containers/dependabot/go_modules/github.com/containers/common-0.4.3
Bump github.com/containers/common from 0.4.2 to 0.4.3
2020-03-11 06:57:16 -04:00
dependabot-preview[bot]
0752e837e5 Bump github.com/containers/common from 0.4.2 to 0.4.3
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.4.2 to 0.4.3.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.4.2...v0.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-03-11 10:28:24 +01:00
Miloslav Trmač
2e9a426a78 Merge pull request #842 from containers/dependabot/go_modules/github.com/containers/storage-1.16.2
Bump github.com/containers/storage from 1.16.1 to 1.16.2
2020-03-09 19:09:22 +01:00
dependabot-preview[bot]
406d3eb134 Bump github.com/containers/storage from 1.16.1 to 1.16.2
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.1 to 1.16.2.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.1...v1.16.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-03-09 11:29:00 +01:00
Daniel J Walsh
14e9834d55 Merge pull request #840 from saschagrunert/install-debian
Add Ubuntu/Debian install instructions
2020-03-05 09:37:42 -05:00
Sascha Grunert
bae3378171 Add Ubuntu/Debian install instructions
Signed-off-by: Sascha Grunert <sgrunert@suse.com>
2020-03-05 15:12:04 +01:00
Miloslav Trmač
71c382c043 Merge pull request #838 from containers/dependabot/go_modules/github.com/containers/storage-1.16.1
Bump github.com/containers/storage from 1.16.0 to 1.16.1
2020-03-05 00:57:08 +01:00
dependabot-preview[bot]
7dcfc18309 Bump github.com/containers/storage from 1.16.0 to 1.16.1
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.16.0 to 1.16.1.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.16.0...v1.16.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-03-04 09:24:57 -05:00
Daniel J Walsh
9b984e8eba Merge pull request #835 from mtrmac/rhel-rpm
Mention CentOS/RHEL in installation instructions
2020-03-03 14:07:33 -05:00
Miloslav Trmač
4e45fcc584 Mention CentOS/RHEL in installation instructions
apparently the Fedora reference is not obviously relevant.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-03-03 19:09:19 +01:00
Giuseppe Scrivano
0d84f81305 Merge pull request #836 from vrothberg/force-runc
CI: force Podman to use runc
2020-03-03 11:49:58 +01:00
Valentin Rothberg
2e65e64c06 CI: force Podman to use runc
crun had a regression running on cgroupsv1 in containers.  It has been
fixed upstream but did not yet bubble up into the packages.  Force using
runc to unblock Skopeo's CI.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-03-03 11:09:31 +01:00
Miloslav Trmač
4c4a4b611e Merge pull request #834 from containers/dependabot/go_modules/github.com/containers/common-0.4.2
Bump github.com/containers/common from 0.2.1 to 0.4.2
2020-02-26 14:03:16 +01:00
dependabot-preview[bot]
ef1b005c95 Bump github.com/containers/common from 0.2.1 to 0.4.2
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.2.1 to 0.4.2.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.2.1...v0.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-02-25 22:53:25 +01:00
Miloslav Trmač
fcbc889abf Merge pull request #831 from containers/dependabot/go_modules/github.com/stretchr/testify-1.5.1
Bump github.com/stretchr/testify from 1.5.0 to 1.5.1
2020-02-25 22:46:58 +01:00
dependabot-preview[bot]
7be2a1bf3b Bump github.com/stretchr/testify from 1.5.0 to 1.5.1
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.5.0...v1.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-02-25 22:26:37 +01:00
Miloslav Trmač
c05fbf4573 Merge pull request #833 from slofurno/fix-docker-build
build from ubuntu 19.10
2020-02-25 22:06:46 +01:00
Miloslav Trmač
d7a2bd7230 Merge pull request #716 from zhill/tag_list
Adds "docker-list-tags" command to list tags
2020-02-25 21:58:24 +01:00
Steve LoFurno
f489ba7bfc bump to a supported ubuntu release 2020-02-25 00:10:35 +00:00
Zach Hill
0a91c00ebe Merge branch 'master' into tag_list 2020-02-24 12:12:36 -08:00
Daniel J Walsh
df2966b766 add support for REGISTRY_AUTH_FILE
Fix cli to use REGISTRY_AUTH_FILE if set and to display the
default location to use for authfiles in the `skopeo copy --help`

Modify tests to verify the different settings.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-02-22 07:44:01 -05:00
Daniel J Walsh
7c29094b51 Merge pull request #820 from containers/dependabot/go_modules/github.com/containers/storage-1.16.0
Bump github.com/containers/storage from 1.15.8 to 1.16.0
2020-02-21 10:21:28 -05:00
Daniel J Walsh
88f6057eaa Merge pull request #814 from harche/partial_enc
Partial image encryption support
2020-02-21 10:20:49 -05:00
Daniel J Walsh
c2fa78096b Merge pull request #821 from containers/dependabot/go_modules/github.com/stretchr/testify-1.5.0
Bump github.com/stretchr/testify from 1.4.0 to 1.5.0
2020-02-21 10:19:30 -05:00
Harshal Patil
8d1a4649f2 Partial image encryption support
Signed-off-by: Harshal Patil <harshal.patil@in.ibm.com>
2020-02-20 07:53:26 +05:30
dependabot-preview[bot]
377ba25c6b Bump github.com/stretchr/testify from 1.4.0 to 1.5.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.4.0...v1.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-02-19 11:44:08 +01:00
dependabot-preview[bot]
1d136f0541 Bump github.com/containers/storage from 1.15.8 to 1.16.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.15.8 to 1.16.0.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](https://github.com/containers/storage/compare/v1.15.8...v1.16.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-02-19 11:43:12 +01:00
dependabot-preview[bot]
7b9629d6dc Bump github.com/containers/common from 0.2.0 to 0.2.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.2.0...v0.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-02-19 11:39:58 +01:00
Zach Hill
07c89b49ff Fix wrong import of docker reference
Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 14:05:55 -08:00
Zach Hill
a9854e1173 Remove the list_tags integration test since it does not cover much not already tested by the upstream container/images repo or local unit tests
Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 00:03:34 -08:00
Zach Hill
36fdc062ba Updates based on code review to simplify logic and tests
Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 00:03:34 -08:00
Zach Hill
5554964a8f Fix inconsistency in manpage example for list-tags
Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 00:03:34 -08:00
Zach Hill
b0cfab1d45 Fix formatting on test
Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 00:03:34 -08:00
Zach Hill
cce44c45d5 Adds "list-tags" command to list tags with no known tag required. Fixes #276
Example: skopeo list-tags docker://docker.io/library/centos
Returns response:
{
  Repository": "docker.io/library/centos",
  "Tags": [
    "6",
    "7",
    ...
  ]
}

Signed-off-by: Zach Hill <zach@anchore.com>
2020-02-12 00:03:34 -08:00
Miloslav Trmač
c8e0250903 Merge pull request #817 from containers/dependabot/go_modules/github.com/containers/common-0.2.0
Bump github.com/containers/common from 0.1.4 to 0.2.0
2020-02-11 20:34:15 +01:00
dependabot-preview[bot]
f830265034 Bump github.com/containers/common from 0.1.4 to 0.2.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.1.4 to 0.2.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.1.4...v0.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-02-11 12:57:11 +01:00
Daniel J Walsh
fea7ada700 Merge pull request #816 from TomSweeneyRedHat/coc
Add Code of Conduct
2020-02-10 08:23:27 -05:00
TomSweeneyRedHat
ba8417edf3 Add Code of Conduct
Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2020-02-08 18:09:23 -05:00
Daniel J Walsh
2eb86a3be7 Merge pull request #815 from vrothberg/release
v0.1.41
2020-02-07 08:39:22 -05:00
Valentin Rothberg
759dc98b32 bump to v0.1.42-dev
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-02-07 12:18:42 +01:00
Jirka Chadima
c6a731bb2e Adds override-variant to man pages
Signed-off-by: Jirka Chadima <chadima.jiri@gmail.com>
2020-01-09 15:13:28 +01:00
Jirka Chadima
222beaf4c7 Adds the --override-variant command line flag
Signed-off-by: Jirka Chadima <chadima.jiri@gmail.com>
2020-01-09 15:13:28 +01:00
516 changed files with 32175 additions and 93762 deletions

3
CODE-OF-CONDUCT.md Normal file
View File

@@ -0,0 +1,3 @@
## The skopeo Project Community Code of Conduct
The skopeo project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).

View File

@@ -9,7 +9,7 @@ RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-md2ma
gnupg \
# OpenShift deps
which tar wget hostname util-linux bsdtar socat ethtool device-mapper iptables tree findutils nmap-ncat e2fsprogs xfsprogs lsof docker iproute \
bats jq podman \
bats jq podman runc \
golint \
&& dnf clean all

View File

@@ -1,4 +1,4 @@
FROM ubuntu:18.10
FROM ubuntu:19.10
RUN apt-get update && apt-get install -y \
golang \

View File

@@ -184,10 +184,9 @@ test-unit-local:
$(GPGME_ENV) $(GO) test $(MOD_VENDOR) -tags "$(BUILDTAGS)" $$($(GO) list $(MOD_VENDOR) -tags "$(BUILDTAGS)" -e ./... | grep -v '^github\.com/containers/skopeo/\(integration\|vendor/.*\)$$')
vendor:
export GO111MODULE=on \
$(GO) mod tidy && \
$(GO) mod vendor && \
$(GO) mod verify
$(GO) mod tidy
$(GO) mod vendor
$(GO) mod verify
vendor-in-container:
podman run --privileged --rm --env HOME=/root -v `pwd`:/src -w /src docker.io/library/golang:1.13 make vendor

View File

@@ -149,85 +149,9 @@ you'll get an error. You can fix this by either logging in (via `docker login`)
Obtaining skopeo
-
`skopeo` may already be packaged in your distribution, for example on Fedora 23 and later you can install it using
```sh
$ sudo dnf install skopeo
```
for openSUSE:
```sh
$ sudo zypper install skopeo
```
on alpine:
```sh
$ sudo apk add skopeo
```
Otherwise, read on for building and installing it from source:
To build the `skopeo` binary you need at least Go 1.9.
There are two ways to build skopeo: in a container, or locally without a container. Choose the one which better matches your needs and environment.
### Building without a container
Building without a container requires a bit more manual work and setup in your environment, but it is more flexible:
- It should work in more environments (e.g. for native macOS builds)
- It does not require root privileges (after dependencies are installed)
- It is faster, therefore more convenient for developing `skopeo`.
Install the necessary dependencies:
```sh
# Fedora:
sudo dnf install gpgme-devel libassuan-devel btrfs-progs-devel device-mapper-devel
# Ubuntu (`libbtrfs-dev` requires Ubuntu 18.10 and above):
sudo apt install libgpgme-dev libassuan-dev libbtrfs-dev libdevmapper-dev
# macOS:
brew install gpgme
# openSUSE
sudo zypper install libgpgme-devel device-mapper-devel libbtrfs-devel glib2-devel
```
Make sure to clone this repository in your `GOPATH` - otherwise compilation fails.
```sh
$ git clone https://github.com/containers/skopeo $GOPATH/src/github.com/containers/skopeo
$ cd $GOPATH/src/github.com/containers/skopeo && make binary-local
```
### Building in a container
Building in a container is simpler, but more restrictive:
- It requires the `docker` command and the ability to run Linux containers
- The created executable is a Linux executable, and depends on dynamic libraries which may only be available only in a container of a similar Linux distribution.
```sh
$ make binary # Or (make all) to also build documentation, see below.
```
To build a pure-Go static binary (disables devicemapper, btrfs, and gpgme):
```sh
$ make binary-static DISABLE_CGO=1
```
### Building documentation
To build the manual you will need go-md2man.
```sh
Debian$ sudo apt-get install go-md2man
Fedora$ sudo dnf install go-md2man
```
Then
```sh
$ make docs
```
### Installation
Finally, after the binary and documentation is built:
```sh
$ sudo make install
```
For a detailed description how to install or build skopeo, see
[install.md](./install.md).
TODO
-

View File

@@ -28,6 +28,7 @@ type copyOptions struct {
format optionalString // Force conversion of the image to a specified format
quiet bool // Suppress output information when copying images
all bool // Copy all of the images if the source is a list
encryptLayer cli.IntSlice // The list of layers to encrypt
encryptionKeys cli.StringSlice // Keys needed to encrypt the image
decryptionKeys cli.StringSlice // Keys needed to decrypt the image
}
@@ -92,6 +93,11 @@ func copyCmd(global *globalOptions) cli.Command {
Usage: "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)",
Value: &opts.encryptionKeys,
},
cli.IntSliceFlag{
Name: "encrypt-layer",
Usage: "*Experimental* the 0-indexed layer indices, with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer)",
Value: &opts.encryptLayer,
},
cli.StringSliceFlag{
Name: "decryption-key",
Usage: "*Experimental* key needed to decrypt the image",
@@ -180,9 +186,14 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
var encConfig *encconfig.EncryptConfig
var decConfig *encconfig.DecryptConfig
if len(opts.encryptLayer.Value()) > 0 && len(opts.encryptionKeys.Value()) == 0 {
return fmt.Errorf("--encrypt-layer can only be used with --encryption-key")
}
if len(opts.encryptionKeys.Value()) > 0 {
// encryption
encLayers = &[]int{}
p := opts.encryptLayer.Value()
encLayers = &p
encryptionKeys := opts.encryptionKeys.Value()
ecc, err := enchelpers.CreateCryptoConfig(encryptionKeys, []string{})
if err != nil {

136
cmd/skopeo/list_tags.go Normal file
View File

@@ -0,0 +1,136 @@
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/pkg/errors"
"github.com/urfave/cli"
"strings"
"io"
)
// tagListOutput is the output format of (skopeo list-tags), primarily so that we can format it with a simple json.MarshalIndent.
type tagListOutput struct {
Repository string
Tags []string
}
type tagsOptions struct {
global *globalOptions
image *imageOptions
}
func tagsCmd(global *globalOptions) cli.Command {
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, "", "")
opts := tagsOptions{
global: global,
image: imageOpts,
}
return cli.Command{
Name: "list-tags",
Usage: "List tags in the transport/repository specified by the REPOSITORY-NAME",
Description: `
Return the list of tags from the transport/repository "REPOSITORY-NAME"
Supported transports:
docker
See skopeo-list-tags(1) section "REPOSITORY NAMES" for the expected format
`,
ArgsUsage: "REPOSITORY-NAME",
Flags: append(sharedFlags, imageFlags...),
Action: commandAction(opts.run),
}
}
// Customized version of the alltransports.ParseImageName and docker.ParseReference that does not place a default tag in the reference
// Would really love to not have this, but needed to enforce tag-less and digest-less names
func parseDockerRepositoryReference(refString string) (types.ImageReference, error) {
if !strings.HasPrefix(refString, docker.Transport.Name()+"://") {
return nil, errors.Errorf("docker: image reference %s does not start with %s://", refString, docker.Transport.Name())
}
parts := strings.SplitN(refString, ":", 2)
if len(parts) != 2 {
return nil, errors.Errorf(`Invalid image name "%s", expected colon-separated transport:reference`, refString)
}
ref, err := reference.ParseNormalizedNamed(strings.TrimPrefix(parts[1], "//"))
if err != nil {
return nil, err
}
if !reference.IsNameOnly(ref) {
return nil, errors.New(`No tag or digest allowed in reference`)
}
// Checks ok, now return a reference. This is a hack because the tag listing code expects a full image reference even though the tag is ignored
return docker.NewReference(reference.TagNameOnly(ref))
}
// List the tags from a repository contained in the imgRef reference. Any tag value in the reference is ignored
func listDockerTags(ctx context.Context, sys *types.SystemContext, imgRef types.ImageReference) (string, []string, error) {
repositoryName := imgRef.DockerReference().Name()
tags, err := docker.GetRepositoryTags(ctx, sys, imgRef)
if err != nil {
return ``, nil, fmt.Errorf("Error listing repository tags: %v", err)
}
return repositoryName, tags, nil
}
func (opts *tagsOptions) run(args []string, stdout io.Writer) (retErr error) {
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
if len(args) != 1 {
return errorShouldDisplayUsage{errors.New("Exactly one non-option argument expected")}
}
sys, err := opts.image.newSystemContext()
if err != nil {
return err
}
transport := alltransports.TransportFromImageName(args[0])
if transport == nil {
return fmt.Errorf("Invalid %q: does not specify a transport", args[0])
}
if transport.Name() != docker.Transport.Name() {
return fmt.Errorf("Unsupported transport '%v' for tag listing. Only '%v' currently supported", transport.Name(), docker.Transport.Name())
}
// Do transport-specific parsing and validation to get an image reference
imgRef, err := parseDockerRepositoryReference(args[0])
if err != nil {
return err
}
repositoryName, tagListing, err := listDockerTags(ctx, sys, imgRef)
if err != nil {
return err
}
outputData := tagListOutput{
Repository: repositoryName,
Tags: tagListing,
}
out, err := json.MarshalIndent(outputData, "", " ")
if err != nil {
return err
}
_, err = fmt.Fprintf(stdout, "%s\n", string(out))
return err
}

View File

@@ -0,0 +1,56 @@
package main
import (
"github.com/containers/image/v5/transports/alltransports"
"github.com/stretchr/testify/assert"
"testing"
)
// Tests the kinds of inputs allowed and expected to the command
func TestDockerRepositoryReferenceParser(t *testing.T) {
for _, test := range [][]string{
{"docker://myhost.com:1000/nginx"}, //no tag
{"docker://myhost.com/nginx"}, //no port or tag
{"docker://somehost.com"}, // Valid default expansion
{"docker://nginx"}, // Valid default expansion
} {
ref, err := parseDockerRepositoryReference(test[0])
expected, err := alltransports.ParseImageName(test[0])
if assert.NoError(t, err, "Could not parse, got error on %v", test[0]) {
assert.Equal(t, expected.DockerReference().Name(), ref.DockerReference().Name(), "Mismatched parse result for input %v", test[0])
}
}
for _, test := range [][]string{
{"oci://somedir"},
{"dir:/somepath"},
{"docker-archive:/tmp/dir"},
{"container-storage:myhost.com/someimage"},
{"docker-daemon:myhost.com/someimage"},
{"docker://myhost.com:1000/nginx:foobar:foobar"}, // Invalid repository ref
{"docker://somehost.com:5000/"}, // no repo
{"docker://myhost.com:1000/nginx:latest"}, //tag not allowed
{"docker://myhost.com:1000/nginx@sha256:abcdef1234567890"}, //digest not allowed
} {
_, err := parseDockerRepositoryReference(test[0])
assert.Error(t, err, test[0])
}
}
func TestDockerRepositoryReferenceParserDrift(t *testing.T) {
for _, test := range [][]string{
{"docker://myhost.com:1000/nginx", "myhost.com:1000/nginx"}, //no tag
{"docker://myhost.com/nginx", "myhost.com/nginx"}, //no port or tag
{"docker://somehost.com", "docker.io/library/somehost.com"}, // Valid default expansion
{"docker://nginx", "docker.io/library/nginx"}, // Valid default expansion
} {
ref, err := parseDockerRepositoryReference(test[0])
ref2, err2 := alltransports.ParseImageName(test[0])
if assert.NoError(t, err, "Could not parse, got error on %v", test[0]) && assert.NoError(t, err2, "Could not parse with regular parser, got error on %v", test[0]) {
assert.Equal(t, ref.DockerReference().String(), ref2.DockerReference().String(), "Different parsing output for input %v. Repo parse = %v, regular parser = %v", test[0], ref, ref2)
}
}
}

View File

@@ -25,8 +25,10 @@ type globalOptions struct {
registriesDirPath string // Path to a "registries.d" registry configuration directory
overrideArch string // Architecture to use for choosing images, instead of the runtime one
overrideOS string // OS to use for choosing images, instead of the runtime one
overrideVariant string // Architecture variant to use for choosing images, instead of the runtime one
commandTimeout time.Duration // Timeout for the command execution
registriesConfPath string // Path to the "registries.conf" file
tmpDir string // Path to use for big temporary files
}
// createApp returns a cli.App, and the underlying globalOptions object, to be run or tested.
@@ -43,32 +45,21 @@ func createApp() (*cli.App, *globalOptions) {
}
app.Usage = "Various operations with container images and container image registries"
app.Flags = []cli.Flag{
cli.DurationFlag{
Name: "command-timeout",
Usage: "timeout for the command execution",
Destination: &opts.commandTimeout,
},
cli.BoolFlag{
Name: "debug",
Usage: "enable debug output",
Destination: &opts.debug,
},
cli.GenericFlag{
Name: "tls-verify",
Usage: "require HTTPS and verify certificates when talking to container registries (defaults to true)",
Hidden: true,
Value: newOptionalBoolValue(&opts.tlsVerify),
},
cli.StringFlag{
Name: "policy",
Usage: "Path to a trust policy file",
Destination: &opts.policyPath,
},
cli.BoolFlag{
Name: "insecure-policy",
Usage: "run the tool without any policy check",
Destination: &opts.insecurePolicy,
},
cli.StringFlag{
Name: "registries.d",
Usage: "use registry configuration files in `DIR` (e.g. for container signature storage)",
Destination: &opts.registriesDirPath,
},
cli.StringFlag{
Name: "override-arch",
Usage: "use `ARCH` instead of the architecture of the machine for choosing images",
@@ -79,10 +70,15 @@ func createApp() (*cli.App, *globalOptions) {
Usage: "use `OS` instead of the running OS for choosing images",
Destination: &opts.overrideOS,
},
cli.DurationFlag{
Name: "command-timeout",
Usage: "timeout for the command execution",
Destination: &opts.commandTimeout,
cli.StringFlag{
Name: "override-variant",
Usage: "use `VARIANT` instead of the running architecture variant for choosing images",
Destination: &opts.overrideVariant,
},
cli.StringFlag{
Name: "policy",
Usage: "Path to a trust policy file",
Destination: &opts.policyPath,
},
cli.StringFlag{
Name: "registries-conf",
@@ -90,17 +86,34 @@ func createApp() (*cli.App, *globalOptions) {
Destination: &opts.registriesConfPath,
Hidden: true,
},
cli.StringFlag{
Name: "registries.d",
Usage: "use registry configuration files in `DIR` (e.g. for container signature storage)",
Destination: &opts.registriesDirPath,
},
cli.GenericFlag{
Name: "tls-verify",
Usage: "require HTTPS and verify certificates when talking to container registries (defaults to true)",
Hidden: true,
Value: newOptionalBoolValue(&opts.tlsVerify),
},
cli.StringFlag{
Name: "tmpdir",
Usage: "directory used to store temporary files",
Destination: &opts.tmpDir,
},
}
app.Before = opts.before
app.Commands = []cli.Command{
copyCmd(&opts),
deleteCmd(&opts),
inspectCmd(&opts),
layersCmd(&opts),
deleteCmd(&opts),
tagsCmd(&opts),
manifestDigestCmd(),
syncCmd(&opts),
standaloneSignCmd(),
standaloneVerifyCmd(),
syncCmd(&opts),
untrustedSignatureDumpCmd(),
}
return app, &opts

View File

@@ -1,8 +1,8 @@
package main
import (
"github.com/containers/common/pkg/unshare"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/storage/pkg/unshare"
"github.com/pkg/errors"
"github.com/syndtr/gocapability/capability"
)

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"io"
"os"
"strings"
"github.com/containers/image/v5/pkg/compression"
@@ -44,7 +45,8 @@ func sharedImageFlags() ([]cli.Flag, *sharedImageOptions) {
return []cli.Flag{
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
Usage: "path of the authentication file. Example: ${XDG_RUNTIME_DIR}/containers/auth.json",
Value: os.Getenv("REGISTRY_AUTH_FILE"),
Destination: &opts.authFilePath,
},
}, &opts
@@ -94,7 +96,7 @@ func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, flagPre
flags = append(flags,
cli.GenericFlag{
Name: flagPrefix + "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
Usage: "path of the authentication file. Example: ${XDG_RUNTIME_DIR}/containers/auth.json",
Value: newOptionalStringValue(&opts.authFilePath),
},
)
@@ -149,12 +151,14 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
RegistriesDirPath: opts.global.registriesDirPath,
ArchitectureChoice: opts.global.overrideArch,
OSChoice: opts.global.overrideOS,
VariantChoice: opts.global.overrideVariant,
DockerCertPath: opts.dockerCertPath,
OCISharedBlobDirPath: opts.sharedBlobDir,
AuthFilePath: opts.shared.authFilePath,
DockerDaemonHost: opts.dockerDaemonHost,
DockerDaemonCertPath: opts.dockerCertPath,
SystemRegistriesConfPath: opts.global.registriesConfPath,
BigFilesTemporaryDir: opts.global.tmpDir,
}
if opts.dockerImageOptions.authFilePath.present {
ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value

View File

@@ -2,6 +2,7 @@ package main
import (
"flag"
"os"
"testing"
"github.com/containers/image/v5/types"
@@ -52,6 +53,8 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
"--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch",
"--override-os", "overridden-os",
"--override-variant", "overridden-variant",
"--tmpdir", "/srv",
}, []string{
"--authfile", "/srv/authfile",
"--dest-authfile", "/srv/dest-authfile",
@@ -68,6 +71,7 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
AuthFilePath: "/srv/dest-authfile",
ArchitectureChoice: "overridden-arch",
OSChoice: "overridden-os",
VariantChoice: "overridden-variant",
OCISharedBlobDirPath: "/srv/shared-blob-dir",
DockerCertPath: "/srv/cert-dir",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
@@ -75,6 +79,7 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
DockerDaemonCertPath: "/srv/cert-dir",
DockerDaemonHost: "daemon-host.example.com",
DockerDaemonInsecureSkipTLSVerify: true,
BigFilesTemporaryDir: "/srv",
}, res)
// Global/per-command tlsVerify behavior
@@ -137,19 +142,33 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{}, res)
oldXRD, hasXRD := os.LookupEnv("REGISTRY_AUTH_FILE")
defer func() {
if hasXRD {
os.Setenv("REGISTRY_AUTH_FILE", oldXRD)
} else {
os.Unsetenv("REGISTRY_AUTH_FILE")
}
}()
authFile := "/tmp/auth.json"
// Make sure when REGISTRY_AUTH_FILE is set the auth file is used
os.Setenv("REGISTRY_AUTH_FILE", authFile)
// Explicitly set everything to default, except for when the default is “not present”
opts = fakeImageDestOptions(t, "dest-", []string{}, []string{
"--dest-compress=false",
})
res, err = opts.newSystemContext()
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{}, res)
assert.Equal(t, &types.SystemContext{AuthFilePath: authFile}, res)
// Set everything to non-default values.
opts = fakeImageDestOptions(t, "dest-", []string{
"--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch",
"--override-os", "overridden-os",
"--override-variant", "overridden-variant",
"--tmpdir", "/srv",
}, []string{
"--authfile", "/srv/authfile",
"--dest-cert-dir", "/srv/cert-dir",
@@ -166,6 +185,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
AuthFilePath: "/srv/authfile",
ArchitectureChoice: "overridden-arch",
OSChoice: "overridden-os",
VariantChoice: "overridden-variant",
OCISharedBlobDirPath: "/srv/shared-blob-dir",
DockerCertPath: "/srv/cert-dir",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
@@ -174,6 +194,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
DockerDaemonHost: "daemon-host.example.com",
DockerDaemonInsecureSkipTLSVerify: true,
DirForceCompress: true,
BigFilesTemporaryDir: "/srv",
}, res)
// Invalid option values in imageOptions

View File

@@ -144,6 +144,20 @@ _skopeo_layers() {
_complete_ "$options_with_args" "$boolean_options"
}
_skopeo_list_repository_tags() {
local options_with_args="
--authfile
--creds
--cert-dir
"
local boolean_options="
--tls-verify
--no-creds
"
_complete_ "$options_with_args" "$boolean_options"
}
_skopeo_skopeo() {
# XXX: Changes here need to be refleceted in the manually expanded
# string in the `case` statement below as well.
@@ -152,7 +166,9 @@ _skopeo_skopeo() {
--registries.d
--override-arch
--override-os
--override-variant
--command-timeout
--tmpdir
"
local boolean_options="
--insecure-policy
@@ -163,7 +179,7 @@ _skopeo_skopeo() {
case "$prev" in
# XXX: Changes here need to be refleceted in $options_with_args as well.
--policy|--registries.d|--override-arch|--override-os|--command-timeout)
--policy|--registries.d|--override-arch|--override-os|--override-variant|--command-timeout)
return
;;
esac
@@ -194,7 +210,7 @@ _cli_bash_autocomplete() {
local counter=1
while [ $counter -lt "$cword" ]; do
case "${words[$counter]}" in
skopeo|copy|inspect|delete|manifest-digest|standalone-sign|standalone-verify|help|h)
skopeo|copy|inspect|delete|manifest-digest|standalone-sign|standalone-verify|help|h|list-repository-tags)
command="${words[$counter]//-/_}"
cpos=$counter
(( cpos++ ))

View File

@@ -20,7 +20,7 @@ Uses the system's trust policy to validate images, rejects images not trusted by
**--all**
If _source-image_ refers to a list of images, instead of copying just the image which matches the current OS and
architecture (subject to the use of the global --override-os and --override-arch options), attempt to copy all of
architecture (subject to the use of the global --override-os, --override-arch and --override-variant options), attempt to copy all of
the images in the list, and the list itself.
**--authfile** _path_
@@ -28,6 +28,9 @@ the images in the list, and the list itself.
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`
**--src-authfile** _path_
Path of the authentication file for the source registry. Uses path given by `--authfile`, if not provided.
@@ -98,12 +101,12 @@ To copy and sign an image:
To encrypt an image:
```sh
skopeo copy docker://docker.io/library/nginx:latest oci:local_nginx:latest
skopeo copy docker://docker.io/library/nginx:1.17.8 oci:local_nginx:1.17.8
openssl genrsa -out private.key 1024
openssl rsa -in private.key -pubout > public.key
skopeo copy --encryption-key jwe:./public.key oci:local_nginx:latest oci:try-encrypt:encrypted
skopeo copy --encryption-key jwe:./public.key oci:local_nginx:1.17.8 oci:try-encrypt:encrypted
```
To decrypt an image:
@@ -120,6 +123,14 @@ To decrypt an image that requires more than one key:
```sh
skopeo copy --decryption-key ./private1.key --decryption-key ./private2.key --decryption-key ./private3.key oci:try-encrypt:encrypted oci:try-decrypt:decrypted
```
Container images can also be partially encrypted by specifying the index of the layer. Layers are 0-indexed indices, with support for negative indexing. i.e. 0 is the first layer, -1 is the last layer.
Let's say out of 3 layers that the image `docker.io/library/nginx:1.17.8` is made up of, we only want to encrypt the 2nd layer,
```sh
skopeo copy --encryption-key jwe:./public.key --encrypt-layer 1 oci:local_nginx:1.17.8 oci:try-encrypt:encrypted
```
## SEE ALSO
skopeo(1), podman-login(1), docker-login(1)

102
docs/skopeo-list-tags.1.md Normal file
View File

@@ -0,0 +1,102 @@
% skopeo-list-tags(1)
## NAME
skopeo\-list\-tags - Return a list of tags the transport-specific image repository
## SYNOPSIS
**skopeo list-tags** _repository-name_
Return a list of tags from _repository-name_ in a registry.
_repository-name_ name of repository to retrieve tag listing from
**--authfile** _path_
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
**--creds** _username[:password]_ for accessing the registry
**--cert-dir** _path_ Use certificates at _path_ (\*.crt, \*.cert, \*.key) to connect to the registry
**--tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container registries (defaults to true)
**--no-creds** _bool-value_ Access the registry anonymously.
## REPOSITORY NAMES
Repository names are transport-specific references as each transport may have its own concept of a "repository" and "tags". Currently, only the Docker transport is supported.
This commands refers to repositories using a _transport_`:`_details_ format. The following formats are supported:
**docker://**_docker-repository-reference_
A repository in a registry implementing the "Docker Registry HTTP API V2". By default, uses the authorization state in either `$XDG_RUNTIME_DIR/containers/auth.json`, which is set using `(podman login)`. If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using `(docker login)`.
A _docker-repository-reference_ is of the form: **registryhost:port/repositoryname** which is similar to an _image-reference_ but with no tag or digest allowed as the last component (e.g no `:latest` or `@sha256:xyz`)
Examples of valid docker-repository-references:
"docker.io/myuser/myrepo"
"docker.io/nginx"
"docker.io/library/fedora"
"localhost:5000/myrepository"
Examples of invalid references:
"docker.io/nginx:latest"
"docker.io/myuser/myimage:v1.0"
"docker.io/myuser/myimage@sha256:f48c4cc192f4c3c6a069cb5cca6d0a9e34d6076ba7c214fd0cc3ca60e0af76bb"
## EXAMPLES
### Docker Transport
To get the list of tags in the "fedora" repository from the docker.io registry (the repository name expands to "library/fedora" per docker transport canonical form):
```sh
$ skopeo list-tags docker://docker.io/fedora
{
"Repository": "docker.io/library/fedora",
"Tags": [
"20",
"21",
"22",
"23",
"24",
"25",
"26-modular",
"26",
"27",
"28",
"29",
"30",
"31",
"32",
"branched",
"heisenbug",
"latest",
"modular",
"rawhide"
]
}
```
To list the tags in a local host docker/distribution registry on port 5000, in this case for the "fedora" repository:
```sh
$ skopeo list-tags docker://localhost:5000/fedora
{
"Repository": "localhost:5000/fedora",
"Tags": [
"latest",
"30",
"31"
]
}
```
# SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
## AUTHORS
Zach Hill <zach@anchore.com>

View File

@@ -105,8 +105,18 @@ skopeo sync --src docker --dest docker registry.example.com/busybox my-registry.
```
Destination registry content:
```
REPO TAGS
registry.example.com/busybox 1-glibc, 1-musl, 1-ubuntu, ..., latest
REPO TAGS
registry.local.lan/busybox 1-glibc, 1-musl, 1-ubuntu, ..., latest
```
### Synchronizing to a container registry keeping the repository
```
skopeo sync --src docker --dest docker registry.example.com/repo/busybox my-registry.local.lan/repo
```
Destination registry content:
```
REPO TAGS
registry.local.lan/repo/busybox 1-glibc, 1-musl, 1-ubuntu, ..., latest
```
### YAML file content (used _source_ for `**--src yaml**`)

View File

@@ -46,21 +46,25 @@ Most commands refer to container images, using a _transport_`:`_details_ format.
## OPTIONS
**--command-timeout** _duration_ Timeout for the command execution.
**--debug** enable debug output
**--policy** _path-to-policy_ Path to a policy.json file to use for verifying signatures and deciding whether an image is trusted, overriding the default trust policy file.
**--help**|**-h** Show help
**--insecure-policy** Adopt an insecure, permissive policy that allows anything. This obviates the need for a policy file.
**--registries.d** _dir_ use registry configuration files in _dir_ (e.g. for container signature storage), overriding the default path.
**--override-arch** _arch_ Use _arch_ instead of the architecture of the machine for choosing images.
**--override-os** _OS_ Use _OS_ instead of the running OS for choosing images.
**--command-timeout** _duration_ Timeout for the command execution.
**--override-variant** _VARIANT_ Use _VARIANT_ instead of the running architecture variant for choosing images.
**--help**|**-h** Show help
**--policy** _path-to-policy_ Path to a policy.json file to use for verifying signatures and deciding whether an image is trusted, overriding the default trust policy file.
**--registries.d** _dir_ use registry configuration files in _dir_ (e.g. for container signature storage), overriding the default path.
**--tmpdir** _dir_ used to store temporary files. Defaults to /var/tmp.
**--version**|**-v** print the version number
@@ -71,6 +75,7 @@ Most commands refer to container images, using a _transport_`:`_details_ format.
| [skopeo-copy(1)](skopeo-copy.1.md) | Copy an image (manifest, filesystem layers, signatures) from one location to another. |
| [skopeo-delete(1)](skopeo-delete.1.md) | Mark image-name for deletion. |
| [skopeo-inspect(1)](skopeo-inspect.1.md) | Return low-level information about image-name in a registry. |
| [skopeo-list-tags(1)](skopeo-list-tags.1.md) | List the tags for the given transport/repository. |
| [skopeo-manifest-digest(1)](skopeo-manifest-digest.1.md) | Compute a manifest digest of manifest-file and write it to standard output.|
| [skopeo-standalone-sign(1)](skopeo-standalone-sign.1.md) | Sign an image. |
| [skopeo-standalone-verify(1)](skopeo-standalone-verify.1.md)| Verify an image. |

17
go.mod
View File

@@ -3,25 +3,24 @@ module github.com/containers/skopeo
go 1.12
require (
github.com/containers/buildah v1.13.1 // indirect
github.com/containers/common v0.1.4
github.com/containers/image/v5 v5.2.1
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741
github.com/containers/storage v1.15.8
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23
github.com/containerd/containerd v1.3.0 // indirect
github.com/containers/image/v5 v5.4.3
github.com/containers/ocicrypt v1.0.2
github.com/containers/storage v1.18.2
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f
github.com/dsnet/compress v0.0.1 // indirect
github.com/go-check/check v0.0.0-20180628173108-788fd7840127
github.com/google/go-cmp v0.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/image-tools v0.0.0-20170926011501-6d941547fa1d
github.com/opencontainers/runtime-spec v1.0.0 // indirect
github.com/pkg/errors v0.9.1
github.com/russross/blackfriday v2.0.0+incompatible // indirect
github.com/sirupsen/logrus v1.4.2
github.com/stretchr/testify v1.4.0
github.com/sirupsen/logrus v1.5.0
github.com/stretchr/testify v1.5.1
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/urfave/cli v1.22.1
github.com/vbauerster/mpb v3.4.0+incompatible // indirect
go4.org v0.0.0-20190218023631-ce4c26f7be8e // indirect
gopkg.in/yaml.v2 v2.2.8
)

378
go.sum
View File

@@ -5,153 +5,69 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c h1:YMP6olTU903X3gxQJckdmiP8/zkSMq4kN3uipsU9XjU=
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c/go.mod h1:7xhjOwRV2+0HXGmM0jxaEu+ZiXJFoVZOTfL/dmqbrD8=
github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
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/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/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69 h1:rG1clvJbgsUcmb50J82YUJhUMopWNtZvyMZjb+4fqGw=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20180216233310-d8fb8589b0e8/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containers/buildah v1.11.5 h1:bVpkaVlvA7G+1mBDAcX6yf7jNZJ/ZrrAHDt4WCx2i8E=
github.com/containers/buildah v1.11.5/go.mod h1:bfNPqLO8GnI0qMPmI6MHSpQNK+a3TH9syYsRg+iqhRw=
github.com/containers/buildah v1.11.6 h1:PhlF++LAezRtOKHfKhBlo8DLvpMQIvU/K2VfAhknadE=
github.com/containers/buildah v1.11.6/go.mod h1:02+o3ZTICaPyP0QcQFoQd07obLMdAecSnFN2kDhcqNo=
github.com/containers/buildah v1.12.0 h1:bi/8ACl8qobazwfYgNze5y+aRuBIG+R7lMStFbnDOxE=
github.com/containers/buildah v1.12.0/go.mod h1:yzPuQ/mJTPsfSLCyBPbeaoXgBLanjnf36M2cDzyckMg=
github.com/containers/buildah v1.13.1 h1:EdhllQxXmOZ56mGFf68AkrpIj9XtEkkGq0WaPWFuGM0=
github.com/containers/buildah v1.13.1/go.mod h1:U0LcOzSqoYdyQC5L2hMeLbtCDuCCLxmZV1eb+SWY4GA=
github.com/containers/common v0.0.3 h1:C2Zshb0w720FqPa42MCRuiGfbW0kwbURRwvK1EWIC5I=
github.com/containers/common v0.0.3/go.mod h1:CaOgMRiwi2JJHISMZ6VPPZhQYFUDRv3YYVss2RqUCMg=
github.com/containers/common v0.0.7 h1:eKYZLKfJ2d/RNDgecLDFv45cHb4imYzIcrQHx1Y029M=
github.com/containers/common v0.0.7/go.mod h1:lhWV3MLhO1+KGE2x6v9+K38MxpjXGso+edmpkFnCOqI=
github.com/containers/common v0.1.4 h1:6tizbvX9BJTnJ0S3pe65Vcu8gJagbm6oFBCmwUIiOE4=
github.com/containers/common v0.1.4/go.mod h1:ss8uGpUsaDE4DPmaVFOjzKrlgf5eUnSAWL+d/PYGaoM=
github.com/containers/image/v5 v5.0.0/go.mod h1:MgiLzCfIeo8lrHi+4Lb8HP+rh513sm0Mlk6RrhjFOLY=
github.com/containers/image/v5 v5.0.1-0.20191126085826-502848a1358b h1:xUXa/0+KWQY1PAGuvfqXh1U18qTRYvHzhiys/BpZG4c=
github.com/containers/image/v5 v5.0.1-0.20191126085826-502848a1358b/go.mod h1:NNGElTgKPvARdKeiJIE/IF+ddvHmNwaLPBupsoZI8eI=
github.com/containers/image/v5 v5.1.0 h1:5FjAvPJniamuNNIQHkh4PnsL+n+xzs6Aonzaz5dqTEo=
github.com/containers/image/v5 v5.1.0/go.mod h1:BKlMD34WxRo1ruGHHEOrPQP0Qci7SWoPwU6fS7arsCU=
github.com/containers/image/v5 v5.2.0 h1:DowY5OII5x9Pb6Pt76vnHU79BgG4/jdwhZjeAj2R+t8=
github.com/containers/image/v5 v5.2.0/go.mod h1:IAub4gDGvXoxaIAdNy4e3FbVTDPVNMv9F0UfVVFbYCU=
github.com/containers/image/v5 v5.2.1 h1:rQR6QSUneWBoW1bTFpP9EJJTevQFv27YsKYQVJIzg+s=
github.com/containers/image/v5 v5.2.1/go.mod h1:TfhmLwH+v1/HBVPIWH7diLs8XwcOkP3c7t7JFgqaUEc=
github.com/containers/image/v5 v5.4.3 h1:zn2HR7uu4hpvT5QQHgjqonOzKDuM1I1UHUEmzZT5sbs=
github.com/containers/image/v5 v5.4.3/go.mod h1:pN0tvp3YbDd7BWavK2aE0mvJUqVd2HmhPjekyWSFm0U=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741 h1:8tQkOcednLJtUcZgK7sPglscXtxvMOnFOa6wd09VWLM=
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
github.com/containers/storage v1.13.2/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/containers/storage v1.13.4/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/containers/storage v1.13.5 h1:/SUzGeOP2HDijpF7Yur21Ch6WTZC1BNeZF917CWcp5c=
github.com/containers/storage v1.13.5/go.mod h1:HELz8Sn+UVbPaUZMI8RvIG9doD4y4z6Gtg4k7xdd2ZY=
github.com/containers/storage v1.14.0 h1:LbX6WZaDmkXt4DT4xWIg3YXAWd6oA4K9Fi6/KG1xt84=
github.com/containers/storage v1.14.0/go.mod h1:qGPsti/qC1xxX+xcpHfiTMT+8ThVE2Jf83wFHHqkDAY=
github.com/containers/storage v1.15.1 h1:yE0lkMG/sIj+dvc/FDGT9KmPi/wXTKGqoLJnNy1tL/c=
github.com/containers/storage v1.15.1/go.mod h1:6BYP6xBTstj0E9dY6mYFgn3BRBRPRSVqfhAqKIWkGpE=
github.com/containers/storage v1.15.2 h1:hLgafU4tuyQk/smMkXZfHTS8FtAQsqQvfWCp4bsgjuw=
github.com/containers/storage v1.15.2/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
github.com/containers/storage v1.15.3 h1:+lFSQZnnKUFyUEtguIgdoQLJfWSuYz+j/wg5GxLtsN4=
github.com/containers/storage v1.15.3/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
github.com/containers/storage v1.15.5 h1:dBZx9yRFHod9c8FVaXlVtRqr2cmlAhpl+9rt87cE7J4=
github.com/containers/storage v1.15.5/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
github.com/containers/storage v1.15.8 h1:ef7OfUMTpyq0PIVAhV7qfufEI92gAldk25nItrip+6Q=
github.com/containers/storage v1.15.8/go.mod h1:zhvjIIl/fR6wt/lgqQAC+xanHQ+8gUQ0GBVeXYN81qI=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/containers/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M=
github.com/containers/storage v1.18.2 h1:4cgFbrrgr9nR9xCeOmfpyxk1MtXYZGr7XGPJfAVkGmc=
github.com/containers/storage v1.18.2/go.mod h1:WTBMf+a9ZZ/LbmEVeLHH2TX4CikWbO1Bt+/m58ZHVPg=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
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=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.0.0-20180522102801-da99009bbb11/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23 h1:oqgGT9O61YAYvI41EBsLePOr+LE6roB0xY4gpkZuFSE=
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.0/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g=
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f h1:Sm8iD2lifO31DwXfkGzq8VgA7rwxPjRsYmeo0K/dF9Y=
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
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.0.0-20180212134524-7beb39f0b969/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
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.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316 h1:moehPjPiGUaWdwgOl92xRyFHJyaqXDHcCyW9M6nmCK4=
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsouza/go-dockerclient v1.6.0 h1:f7j+AX94143JL1H3TiqSMkM4EcLDI0De1qD4GGn3Hig=
github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v0.0.0-20161207003320-04f313413ffd/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
@@ -159,31 +75,15 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
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-openapi/swag v0.19.5/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-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gogo/protobuf v0.0.0-20170815085658-fcdc5011193f/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
@@ -192,60 +92,31 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v0.0.0-20170217192616-94e7d24fd285/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
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/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.7.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.8.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.3 h1:hkFELABwacUEgBfiguNeQydKv3M9pawBq8o24Ypw9+M=
github.com/klauspost/compress v1.9.3/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.8 h1:VMAMUUOh+gaxKTMk+zqbjsSjsIcUcL/LF4o63i82QyA=
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.3 h1:Ce2to9wvs/cuJ2b86/CKQoTYr9VHfpanYosZ0UBJqdw=
github.com/klauspost/pgzip v1.2.3/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -253,58 +124,23 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lumjjb/image/v5 v5.0.0-20191125184705-a298da5c535d h1:H050B1puFO2G3eZP0is6JjpH7OZf2A+2QmtqpTk4Gd0=
github.com/lumjjb/image/v5 v5.0.0-20191125184705-a298da5c535d/go.mod h1:NNGElTgKPvARdKeiJIE/IF+ddvHmNwaLPBupsoZI8eI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.9 h1:eaB5JspOwiKKcHdqcjbfe5lA9cNn/4NRRtddXJCimqk=
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c h1:xa+eQWKuJ9MbB9FBL/eoNvDFvveAkz2LQoz8PzX7Q/4=
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
github.com/mtrmac/gpgme v0.1.1 h1:a5ISnvahzTzBH0m/klhehN68N+9+/jLwhpPFtH3oPAQ=
github.com/mtrmac/gpgme v0.1.1/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
github.com/mtrmac/gpgme v0.1.2 h1:dNOmvYmsrakgW7LcgiprD0yfRuQQe8/C8F6Z+zogO3s=
github.com/mtrmac/gpgme v0.1.2/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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/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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
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=
@@ -314,40 +150,21 @@ github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod
github.com/opencontainers/image-tools v0.0.0-20170926011501-6d941547fa1d h1:X9WSFjjZNqYRqO2MenUgqE2nj/oydcfIzXJ0R/SVnnA=
github.com/opencontainers/image-tools v0.0.0-20170926011501-6d941547fa1d/go.mod h1:A9btVpZLzttF4iFaKNychhPyrhfOjJ1OF5KrA8GcLj4=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190827142921-dd075602f158 h1:/A6bAdnSZoTQmKml3MdHAnSEPnBAQeigNBl4sxnfaaQ=
github.com/opencontainers/runc v1.0.0-rc8.0.20190827142921-dd075602f158/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg=
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.3.1 h1:dn2Rc3wTEvTB6iVqoFrKKeMb0uZ38ZheeyMu2h5C1TI=
github.com/opencontainers/selinux v1.3.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316/go.mod h1:dv+J0b/HWai0QnMVb37/H0v36klkLBi2TNpPeWDxX10=
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible h1:s55wx8JIG/CKnewev892HifTBrtKzMdvgB3rm4rxC2s=
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I=
github.com/openshift/imagebuilder v1.1.1/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.5.1 h1:jskKwSMFYqyTrHEuJgQoUlTcId0av64S6EWObrIfn5Y=
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
@@ -365,167 +182,113 @@ github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkp
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4 h1:rOG9oHVIndNR14f3HRyBy9UPQYmIPniWqTU1TDdHhq4=
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4/go.mod h1:f/98/SnvAzhAEFQJ3u836FePXvcbE8BS0YGMQNn4mhA=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
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/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/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/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
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.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tLAD8IceomUCNw=
github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
github.com/vbauerster/mpb/v4 v4.11.1 h1:ZOYQSVHgmeanXsbyC44aDg76tBGCS/54Rk8VkL8dJGA=
github.com/vbauerster/mpb/v4 v4.11.1/go.mod h1:vMLa1J/ZKC83G2lB/52XpqT+ZZtFG4aZOdKhmpRL1uM=
github.com/vbauerster/mpb/v4 v4.11.2 h1:ynkUoKzi65DZ1UsQPx7sgi/KN6G9f7br+Us2nKm35AM=
github.com/vbauerster/mpb/v4 v4.11.2/go.mod h1:jIuIRCltGJUnm6DCyPVkwjlLUk4nHTH+m4eD14CdFF0=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vbauerster/mpb/v5 v5.0.3 h1:Ldt/azOkbThTk2loi6FrBd/3fhxGFQ24MxFAS88PoNY=
github.com/vbauerster/mpb/v5 v5.0.3/go.mod h1:h3YxU5CSr8rZP4Q3xZPVB3jJLhWPou63lHEdr9ytH4Y=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v0.0.0-20190816131739-be0936907f66/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go4.org v0.0.0-20190218023631-ce4c26f7be8e h1:m9LfARr2VIOW0vsV19kEKp/sWQvZnGobA8JHui/XJoY=
go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2 h1:/J2nHFg1MTqaRLFO7M+J78ASNsJoz3r0cvHBPQ77fsE=
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -533,61 +296,20 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190813020757-36bff7324fb7 h1:4uJOjRn9kWq4AqJRE8+qzmAy+lJd9rh8TY455dNef4U=
k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010 h1:pyoq062NftC1y/OcnbSvgolyZDJ8y4fmUPWMkdA6gfU=
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/client-go v0.0.0-20170217214107-bcde30fb7eae/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083 h1:+Qf/nITucAbm09aIdxvoA+7X0BwaXmQGVoR8k7Ynk9o=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

159
install.md Normal file
View File

@@ -0,0 +1,159 @@
# Installing from packages
`skopeo` may already be packaged in your distribution, for example on
RHEL/CentOS ≥ 8 or Fedora you can install it using:
```sh
$ sudo dnf install skopeo
```
on RHEL/CentOS ≤ 7.x:
```sh
$ sudo yum install skopeo
```
for openSUSE:
```sh
$ sudo zypper install skopeo
```
on alpine:
```sh
$ sudo apk add skopeo
```
Debian (10 and newer including Raspbian) and Ubuntu (18.04 and newer): Packages
are available via the [Kubic][0] project repositories:
[0]: https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable
```bash
# Debian Unstable/Sid:
$ echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_Unstable/Release.key -O- | sudo apt-key add -
```
```bash
# Debian Testing:
$ echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_Testing/Release.key -O- | sudo apt-key add -
```
```bash
# Debian 10:
$ echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_10/Release.key -O- | sudo apt-key add -
```
```bash
# Raspbian 10:
$ echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Raspbian_10/Release.key -O- | sudo apt-key add -
```
```bash
# Ubuntu (18.04, 19.04 and 19.10):
$ . /etc/os-release
$ sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/x${NAME}_${VERSION_ID}/Release.key -O- | sudo apt-key add -
```
```bash
$ sudo apt-get update -qq
$ sudo apt-get install skopeo
```
Otherwise, read on for building and installing it from source:
To build the `skopeo` binary you need at least Go 1.12.
There are two ways to build skopeo: in a container, or locally without a
container. Choose the one which better matches your needs and environment.
### Building without a container
Building without a container requires a bit more manual work and setup in your
environment, but it is more flexible:
- It should work in more environments (e.g. for native macOS builds)
- It does not require root privileges (after dependencies are installed)
- It is faster, therefore more convenient for developing `skopeo`.
Install the necessary dependencies:
```bash
# Fedora:
$ sudo dnf install gpgme-devel libassuan-devel btrfs-progs-devel device-mapper-devel
```
```bash
# Ubuntu (`libbtrfs-dev` requires Ubuntu 18.10 and above):
$ sudo apt install libgpgme-dev libassuan-dev libbtrfs-dev libdevmapper-dev
```
```bash
# macOS:
$ brew install gpgme
```
```bash
# openSUSE:
$ sudo zypper install libgpgme-devel device-mapper-devel libbtrfs-devel glib2-devel
```
Make sure to clone this repository in your `GOPATH` - otherwise compilation fails.
```bash
$ git clone https://github.com/containers/skopeo $GOPATH/src/github.com/containers/skopeo
$ cd $GOPATH/src/github.com/containers/skopeo && make binary-local
```
### Building in a container
Building in a container is simpler, but more restrictive:
- It requires the `podman` command and the ability to run Linux containers
- The created executable is a Linux executable, and depends on dynamic libraries
which may only be available only in a container of a similar Linux
distribution.
```bash
$ make binary # Or (make all) to also build documentation, see below.
```
To build a pure-Go static binary (disables devicemapper, btrfs, and gpgme):
```bash
$ make binary-static DISABLE_CGO=1
```
### Building documentation
To build the manual you will need go-md2man.
```bash
# Debian:
$ sudo apt-get install go-md2man
```
```
# Fedora:
$ sudo dnf install go-md2man
```
Then
```bash
$ make docs
```
### Installation
Finally, after the binary and documentation is built:
```bash
$ sudo make install
```

View File

@@ -469,7 +469,7 @@ func (s *CopySuite) TestCopyFailsWhenImageOSDoesntMatchRuntimeOS(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
assertSkopeoFails(c, `.*no image found in manifest list for architecture .*, OS .*`, "copy", knownWindowsOnlyImage, "containers-storage:"+storage+"test")
assertSkopeoFails(c, `.*no image found in manifest list for architecture .*, variant .*, OS .*`, "copy", knownWindowsOnlyImage, "containers-storage:"+storage+"test")
}
func (s *CopySuite) TestCopySucceedsWhenImageDoesntMatchRuntimeButWeOverride(c *check.C) {
@@ -553,6 +553,15 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
defer os.RemoveAll(keysDir)
undecryptedImgDir, err := ioutil.TempDir("", "copy-5")
defer os.RemoveAll(undecryptedImgDir)
multiLayerImageDir, err := ioutil.TempDir("", "copy-6")
c.Assert(err, check.IsNil)
defer os.RemoveAll(multiLayerImageDir)
partiallyEncryptedImgDir, err := ioutil.TempDir("", "copy-7")
c.Assert(err, check.IsNil)
defer os.RemoveAll(partiallyEncryptedImgDir)
partiallyDecryptedImgDir, err := ioutil.TempDir("", "copy-8")
c.Assert(err, check.IsNil)
defer os.RemoveAll(partiallyDecryptedImgDir)
// Create RSA key pair
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
@@ -577,7 +586,7 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
"oci:"+encryptedImgDir+":encrypted", "oci:"+decryptedImgDir+":decrypted")
// Copy a standard busybox image locally
assertSkopeoSucceeds(c, "", "copy", "docker://busybox", "oci:"+originalImageDir+":latest")
assertSkopeoSucceeds(c, "", "copy", "docker://busybox:1.31.1", "oci:"+originalImageDir+":latest")
// Encrypt the image
assertSkopeoSucceeds(c, "", "copy", "--encryption-key",
@@ -597,7 +606,7 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
assertSkopeoSucceeds(c, "", "copy", "oci:"+encryptedImgDir+":encrypted", "oci:"+undecryptedImgDir+":encrypted")
// Original busybox image has gzipped layers. But encrypted busybox layers should
// not be of gzip type
matchLayerBlobBinaryType(c, undecryptedImgDir+"/blobs/sha256", "application/x-gzip", false)
matchLayerBlobBinaryType(c, undecryptedImgDir+"/blobs/sha256", "application/x-gzip", 0)
// Decrypt the image
assertSkopeoSucceeds(c, "", "copy", "--decryption-key", keysDir+"/private.key",
@@ -605,13 +614,32 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
// After successful decryption we should find the gzipped layer from the
// busybox image
matchLayerBlobBinaryType(c, decryptedImgDir+"/blobs/sha256", "application/x-gzip", true)
matchLayerBlobBinaryType(c, decryptedImgDir+"/blobs/sha256", "application/x-gzip", 1)
// Copy a standard multi layer nginx image locally
assertSkopeoSucceeds(c, "", "copy", "docker://nginx:1.17.8", "oci:"+multiLayerImageDir+":latest")
// Partially encrypt the image
assertSkopeoSucceeds(c, "", "copy", "--encryption-key", "jwe:"+keysDir+"/public.key",
"--encrypt-layer", "1", "oci:"+multiLayerImageDir+":latest", "oci:"+partiallyEncryptedImgDir+":encrypted")
// Since the image is partially encrypted we should find layers that aren't encrypted
matchLayerBlobBinaryType(c, partiallyEncryptedImgDir+"/blobs/sha256", "application/x-gzip", 2)
// Decrypt the partically encrypted image
assertSkopeoSucceeds(c, "", "copy", "--decryption-key", keysDir+"/private.key",
"oci:"+partiallyEncryptedImgDir+":encrypted", "oci:"+partiallyDecryptedImgDir+":decrypted")
// After successful decryption we should find the gzipped layers from the nginx image
matchLayerBlobBinaryType(c, partiallyDecryptedImgDir+"/blobs/sha256", "application/x-gzip", 3)
}
func matchLayerBlobBinaryType(c *check.C, ociImageDirPath string, contentType string, shouldMatch bool) {
func matchLayerBlobBinaryType(c *check.C, ociImageDirPath string, contentType string, matchCount int) {
files, err := ioutil.ReadDir(ociImageDirPath)
c.Assert(err, check.IsNil)
blobFound := false
foundCount := 0
for _, f := range files {
fileContent, err := os.Open(ociImageDirPath + "/" + f.Name())
c.Assert(err, check.IsNil)
@@ -619,13 +647,11 @@ func matchLayerBlobBinaryType(c *check.C, ociImageDirPath string, contentType st
c.Assert(err, check.IsNil)
if layerContentType == contentType {
blobFound = true
break
foundCount = foundCount + 1
}
}
c.Assert(blobFound, check.Equals, shouldMatch)
c.Assert(foundCount, check.Equals, matchCount)
}
func getFileContentType(out *os.File) (string, error) {

View File

@@ -73,7 +73,7 @@ END_EXPECT
# 1) Get remote image values of environment variables (the value of 'Env')
# 2) Confirm substring in check_array and the value of 'Env' match.
check_array=(PATH=.* )
remote=$(echo "$inspect_remote" | jq '.Env[]')
remote=$(jq '.Env[]' <<<"$inspect_remote")
for substr in ${check_array[@]}; do
expect_output --from="$remote" --substring "$substr"
done
@@ -87,7 +87,16 @@ END_EXPECT
# 1) Get current platform arch
# 2) Inspect container image is different from current platform arch
# 3) Compare output w/ expected result
arch=$(podman info --format '{{.host.arch}}')
# Here we see a revolting workaround for a podman incompatibility
# change: in April 2020, podman info completely changed format
# of the keys. What worked until then now throws an error. We
# need to work with both old and new podman.
arch=$(podman info --format '{{.host.arch}}' || true)
if [[ -z "$arch" ]]; then
arch=$(podman info --format '{{.Host.Arch}}')
fi
case $arch in
"amd64")
diff_arch_list="s390x ppc64le"
@@ -106,10 +115,8 @@ END_EXPECT
for arch in $diff_arch_list; do
remote_image=docker://docker.io/$arch/golang
run_skopeo inspect --tls-verify=false --raw $remote_image
remote=$(echo "$output" | jq -r '.manifests[0]["platform"]')
expect=$(echo "{\"architecture\":\"$arch\",\"os\":\"linux\"}" | jq)
expect_output --from="$remote" --substring "$expect" \
"platform arch is not expected"
remote_arch=$(jq -r '.manifests[0]["platform"]["architecture"]' <<< "$output")
expect_output --from="$remote_arch" "$arch" "platform arch of $remote_image"
done
}

View File

@@ -14,7 +14,7 @@ function setup() {
# From remote, to dir1, to local, to dir2;
# compare dir1 and dir2, expect no changes
@test "copy: dir, round trip" {
local remote_image=docker://busybox:latest
local remote_image=docker://docker.io/library/busybox:latest
local localimg=docker://localhost:5000/busybox:unsigned
local dir1=$TESTDIR/dir1
@@ -30,7 +30,7 @@ function setup() {
# Same as above, but using 'oci:' instead of 'dir:' and with a :latest tag
@test "copy: oci, round trip" {
local remote_image=docker://busybox:latest
local remote_image=docker://docker.io/library/busybox:latest
local localimg=docker://localhost:5000/busybox:unsigned
local dir1=$TESTDIR/oci1
@@ -46,7 +46,7 @@ function setup() {
# Compression zstd
@test "copy: oci, round trip, zstd" {
local remote_image=docker://busybox:latest
local remote_image=docker://docker.io/library/busybox:latest
local dir=$TESTDIR/dir
@@ -61,7 +61,7 @@ function setup() {
# Same image, extracted once with :tag and once without
@test "copy: oci w/ and w/o tags" {
local remote_image=docker://busybox:latest
local remote_image=docker://docker.io/library/busybox:latest
local dir1=$TESTDIR/dir1
local dir2=$TESTDIR/dir2

View File

@@ -14,7 +14,7 @@ function setup() {
@test "local registry, with cert" {
# Push to local registry...
run_skopeo copy --dest-cert-dir=$TESTDIR/client-auth \
docker://busybox:latest \
docker://docker.io/library/busybox:latest \
docker://localhost:5000/busybox:unsigned
# ...and pull it back out

View File

@@ -43,7 +43,8 @@ function setup() {
# These should pass
run_skopeo copy --dest-tls-verify=false --dcreds=$testuser:$testpassword \
docker://busybox:latest docker://localhost:5000/busybox:mine
docker://docker.io/library/busybox:latest \
docker://localhost:5000/busybox:mine
run_skopeo inspect --tls-verify=false --creds=$testuser:$testpassword \
docker://localhost:5000/busybox:mine
expect_output --substring "localhost:5000/busybox"
@@ -54,7 +55,8 @@ function setup() {
podman login --tls-verify=false -u $testuser -p $testpassword localhost:5000
run_skopeo copy --dest-tls-verify=false \
docker://busybox:latest docker://localhost:5000/busybox:mine
docker://docker.io/library/busybox:latest \
docker://localhost:5000/busybox:mine
run_skopeo inspect --tls-verify=false docker://localhost:5000/busybox:mine
expect_output --substring "localhost:5000/busybox"

View File

@@ -92,7 +92,8 @@ END_POLICY_JSON
fi
# Cache local copy
run_skopeo copy docker://busybox:latest dir:$TESTDIR/busybox
run_skopeo copy docker://docker.io/library/busybox:latest \
dir:$TESTDIR/busybox
# Push a bunch of images. Do so *without* --policy flag; this lets us
# sign or not, creating images that will or won't conform to policy.

View File

@@ -13,7 +13,7 @@ function setup() {
# delete image from registry
@test "delete: remove image from registry" {
local remote_image=docker://busybox:latest
local remote_image=docker://docker.io/library/busybox:latest
local localimg=docker://localhost:5000/busybox:unsigned
local output=

View File

@@ -5,6 +5,9 @@ SKOPEO_BINARY=${SKOPEO_BINARY:-$(dirname ${BASH_SOURCE})/../skopeo}
# Default timeout for a skopeo command.
SKOPEO_TIMEOUT=${SKOPEO_TIMEOUT:-300}
# Default image to run as a local registry
REGISTRY_FQIN=${SKOPEO_TEST_REGISTRY_FQIN:-docker.io/library/registry:2}
###############################################################################
# BEGIN setup/teardown
@@ -288,9 +291,21 @@ start_registry() {
reg_args+=( -e REGISTRY_STORAGE_DELETE_ENABLED=true)
fi
# TODO: This is TEMPORARY (as of 2020-03-30); remove once crun is fixed.
# Skopeo PR #836 claims there's a "regression" in crun with cgroupsv1,
# but offers no details about what it is (crun issue nor PR) nor when/if
# it's fixed. It's simply a workaround, forcing podman to use runc,
# which might work great for skopeo CI but breaks Fedora gating tests.
# Instead of always forcing runc, do so only when under cgroups v1:
local runtime=
cgroup_type=$(stat -f -c %T /sys/fs/cgroup)
if [[ $cgroup_type == "tmpfs" ]]; then
runtime="--runtime runc"
fi
# cgroup option necessary under podman-in-podman (CI tests),
# and doesn't seem to do any harm otherwise.
PODMAN="podman --cgroup-manager=cgroupfs"
PODMAN="podman $runtime --cgroup-manager=cgroupfs"
# Called with --testuser? Create an htpasswd file
if [[ -n $testuser ]]; then
@@ -299,7 +314,7 @@ start_registry() {
fi
if ! egrep -q "^$testuser:" $AUTHDIR/htpasswd; then
log_and_run $PODMAN run --rm --entrypoint htpasswd registry:2 \
log_and_run $PODMAN run --rm --entrypoint htpasswd $REGISTRY_FQIN \
-Bbn $testuser $testpassword >> $AUTHDIR/htpasswd
fi
@@ -332,7 +347,7 @@ start_registry() {
log_and_run cp $CERT $TESTDIR/client-auth/
fi
log_and_run $PODMAN run -d --name $name "${reg_args[@]}" registry:2
log_and_run $PODMAN run -d --name $name "${reg_args[@]}" $REGISTRY_FQIN
# Wait for registry to actually come up
timeout=10

View File

@@ -8,13 +8,13 @@ import (
"io/ioutil"
"os"
"reflect"
"runtime"
"strings"
"sync"
"time"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/internal/pkg/platform"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/blobinfocache"
"github.com/containers/image/v5/pkg/compression"
@@ -27,8 +27,8 @@ import (
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vbauerster/mpb/v4"
"github.com/vbauerster/mpb/v4/decor"
"github.com/vbauerster/mpb/v5"
"github.com/vbauerster/mpb/v5/decor"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/sync/semaphore"
)
@@ -356,11 +356,11 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
if err != nil {
return nil, "", errors.Wrapf(err, "Error reading manifest list")
}
list, err := manifest.ListFromBlob(manifestList, manifestType)
originalList, err := manifest.ListFromBlob(manifestList, manifestType)
if err != nil {
return nil, "", errors.Wrapf(err, "Error parsing manifest list %q", string(manifestList))
}
originalList := list.Clone()
updatedList := originalList.Clone()
// Read and/or clear the set of signatures for this list.
var sigs [][]byte
@@ -390,18 +390,18 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
case imgspecv1.MediaTypeImageManifest:
forceListMIMEType = imgspecv1.MediaTypeImageIndex
}
selectedListType, err := c.determineListConversion(manifestType, c.dest.SupportedManifestMIMETypes(), forceListMIMEType)
selectedListType, otherManifestMIMETypeCandidates, err := c.determineListConversion(manifestType, c.dest.SupportedManifestMIMETypes(), forceListMIMEType)
if err != nil {
return nil, "", errors.Wrapf(err, "Error determining manifest list type to write to destination")
}
if selectedListType != list.MIMEType() {
if selectedListType != originalList.MIMEType() {
if !canModifyManifestList {
return nil, "", errors.Errorf("Error: manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", selectedListType)
}
}
// Copy each image, or just the ones we want to copy, in turn.
instanceDigests := list.Instances()
instanceDigests := updatedList.Instances()
imagesToCopy := len(instanceDigests)
if options.ImageListSelection == CopySpecificImages {
imagesToCopy = len(options.Instances)
@@ -419,7 +419,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
}
if skip {
update, err := list.Instance(instanceDigest)
update, err := updatedList.Instance(instanceDigest)
if err != nil {
return nil, "", err
}
@@ -447,42 +447,61 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
// Now reset the digest/size/types of the manifests in the list to account for any conversions that we made.
if err = list.UpdateInstances(updates); err != nil {
if err = updatedList.UpdateInstances(updates); err != nil {
return nil, "", errors.Wrapf(err, "Error updating manifest list")
}
// Perform the list conversion.
if selectedListType != list.MIMEType() {
list, err = list.ConvertToMIMEType(selectedListType)
if err != nil {
return nil, "", errors.Wrapf(err, "Error converting manifest list to list with MIME type %q", selectedListType)
}
}
// Check if the updates or a type conversion meaningfully changed the list of images
// by serializing them both so that we can compare them.
updatedManifestList, err := list.Serialize()
if err != nil {
return nil, "", errors.Wrapf(err, "Error encoding updated manifest list (%q: %#v)", list.MIMEType(), list.Instances())
}
originalManifestList, err := originalList.Serialize()
if err != nil {
return nil, "", errors.Wrapf(err, "Error encoding original manifest list for comparison (%q: %#v)", originalList.MIMEType(), originalList.Instances())
}
// If we can't just use the original value, but we have to change it, flag an error.
if !bytes.Equal(updatedManifestList, originalManifestList) {
if !canModifyManifestList {
return nil, "", errors.Errorf("Error: manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", selectedListType)
}
manifestList = updatedManifestList
logrus.Debugf("Manifest list has been updated")
}
// Save the manifest list.
// Iterate through supported list types, preferred format first.
c.Printf("Writing manifest list to image destination\n")
if err = c.dest.PutManifest(ctx, manifestList, nil); err != nil {
return nil, "", errors.Wrapf(err, "Error writing manifest list %q", string(manifestList))
var errs []string
for _, thisListType := range append([]string{selectedListType}, otherManifestMIMETypeCandidates...) {
attemptedList := updatedList
logrus.Debugf("Trying to use manifest list type %s…", thisListType)
// Perform the list conversion, if we need one.
if thisListType != updatedList.MIMEType() {
attemptedList, err = updatedList.ConvertToMIMEType(thisListType)
if err != nil {
return nil, "", errors.Wrapf(err, "Error converting manifest list to list with MIME type %q", thisListType)
}
}
// Check if the updates or a type conversion meaningfully changed the list of images
// by serializing them both so that we can compare them.
attemptedManifestList, err := attemptedList.Serialize()
if err != nil {
return nil, "", errors.Wrapf(err, "Error encoding updated manifest list (%q: %#v)", updatedList.MIMEType(), updatedList.Instances())
}
originalManifestList, err := originalList.Serialize()
if err != nil {
return nil, "", errors.Wrapf(err, "Error encoding original manifest list for comparison (%q: %#v)", originalList.MIMEType(), originalList.Instances())
}
// If we can't just use the original value, but we have to change it, flag an error.
if !bytes.Equal(attemptedManifestList, originalManifestList) {
if !canModifyManifestList {
return nil, "", errors.Errorf("Error: manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", thisListType)
}
logrus.Debugf("Manifest list has been updated")
} else {
// We can just use the original value, so use it instead of the one we just rebuilt, so that we don't change the digest.
attemptedManifestList = manifestList
}
// Save the manifest list.
err = c.dest.PutManifest(ctx, attemptedManifestList, nil)
if err != nil {
logrus.Debugf("Upload of manifest list type %s failed: %v", thisListType, err)
errs = append(errs, fmt.Sprintf("%s(%v)", thisListType, err))
continue
}
errs = nil
manifestList = attemptedManifestList
break
}
if errs != nil {
return nil, "", fmt.Errorf("Uploading manifest list failed, attempted the following formats: %s", strings.Join(errs, ", "))
}
// Sign the manifest list.
@@ -527,15 +546,6 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
return nil, "", "", errors.Wrapf(err, "Error initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
}
// TODO: Remove src.SupportsEncryption call and interface once copyUpdatedConfigAndManifest does not depend on source Image manifest type
// Currently, the way copyUpdatedConfigAndManifest updates the manifest is to apply updates to the source manifest and call PutManifest
// of the modified source manifest. The implication is that schemas like docker2 cannot be encrypted even though the destination
// supports encryption because docker2 struct does not have annotations, which are required.
// Reference to issue: https://github.com/containers/image/issues/746
if options.OciEncryptLayers != nil && !src.SupportsEncryption(ctx) {
return nil, "", "", errors.Errorf("Encryption request but not supported by source transport %s", src.Reference().Transport().Name())
}
// If the destination is a digested reference, make a note of that, determine what digest value we're
// expecting, and check that the source manifest matches it. If the source manifest doesn't, but it's
// one item from a manifest list that matches it, accept that as a match.
@@ -708,21 +718,26 @@ func checkImageDestinationForCurrentRuntime(ctx context.Context, sys *types.Syst
if err != nil {
return errors.Wrapf(err, "Error parsing image configuration")
}
wantedOS := runtime.GOOS
if sys != nil && sys.OSChoice != "" {
wantedOS = sys.OSChoice
}
if wantedOS != c.OS {
logrus.Infof("Image operating system mismatch: image uses %q, expecting %q", c.OS, wantedOS)
wantedPlatforms, err := platform.WantedPlatforms(sys)
if err != nil {
return errors.Wrapf(err, "error getting current platform information %#v", sys)
}
wantedArch := runtime.GOARCH
if sys != nil && sys.ArchitectureChoice != "" {
wantedArch = sys.ArchitectureChoice
options := newOrderedSet()
match := false
for _, wantedPlatform := range wantedPlatforms {
// Waiting for https://github.com/opencontainers/image-spec/pull/777 :
// This currently cant use image.MatchesPlatform because we dont know what to use
// for image.Variant.
if wantedPlatform.OS == c.OS && wantedPlatform.Architecture == c.Architecture {
match = true
break
}
options.append(fmt.Sprintf("%s+%s", wantedPlatform.OS, wantedPlatform.Architecture))
}
if wantedArch != c.Architecture {
logrus.Infof("Image architecture mismatch: image uses %q, expecting %q", c.Architecture, wantedArch)
if !match {
logrus.Infof("Image operating system mismatch: image uses OS %q+architecture %q, expecting one of %q",
c.OS, c.Architecture, strings.Join(options.list, ", "))
}
}
return nil
@@ -833,21 +848,24 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
}
}
func() { // A scope for defer
if err := func() error { // A scope for defer
progressPool, progressCleanup := ic.c.newProgressPool(ctx)
defer progressCleanup()
for i, srcLayer := range srcInfos {
err = copySemaphore.Acquire(ctx, 1)
if err != nil {
logrus.Debug("Can't acquire semaphoer", err)
return errors.Wrapf(err, "Can't acquire semaphore")
}
go copyLayerHelper(i, srcLayer, encLayerBitmap[i], progressPool)
}
// Wait for all layers to be copied
copyGroup.Wait()
}()
return nil
}(); err != nil {
return err
}
destInfos := make([]types.BlobInfo, numLayers)
diffIDs := make([]digest.Digest, numLayers)
@@ -961,7 +979,7 @@ func (c *copier) createProgressBar(pool *mpb.Progress, info types.BlobInfo, kind
var bar *mpb.Bar
if info.Size > 0 {
bar = pool.AddBar(info.Size,
mpb.BarClearOnComplete(),
mpb.BarFillerClearOnComplete(),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(prefix), onComplete),
),
@@ -972,7 +990,7 @@ func (c *copier) createProgressBar(pool *mpb.Progress, info types.BlobInfo, kind
} else {
bar = pool.AddSpinner(info.Size,
mpb.SpinnerOnLeft,
mpb.BarClearOnComplete(),
mpb.BarFillerClearOnComplete(),
mpb.SpinnerStyle([]string{".", "..", "...", "....", ""}),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(prefix), onComplete),
@@ -1006,7 +1024,7 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
return destInfo, nil
}()
if err != nil {
return nil
return err
}
if destInfo.Digest != srcInfo.Digest {
return errors.Errorf("Internal error: copying uncompressed config blob %s changed digest to %s", srcInfo.Digest, destInfo.Digest)

View File

@@ -15,7 +15,7 @@ import (
// Include v2s1 signed but not v2s1 unsigned, because docker/distribution requires a signature even if the unsigned MIME type is used.
var preferredManifestMIMETypes = []string{manifest.DockerV2Schema2MediaType, manifest.DockerV2Schema1SignedMediaType}
// orderedSet is a list of strings (MIME types in our case), with each string appearing at most once.
// orderedSet is a list of strings (MIME types or platform descriptors in our case), with each string appearing at most once.
type orderedSet struct {
list []string
included map[string]struct{}
@@ -125,8 +125,10 @@ func isMultiImage(ctx context.Context, img types.UnparsedImage) (bool, error) {
// determineListConversion takes the current MIME type of a list of manifests,
// the list of MIME types supported for a given destination, and a possible
// forced value, and returns the MIME type to which we should convert the list
// of manifests, whether we are converting to it or using it unmodified.
func (c *copier) determineListConversion(currentListMIMEType string, destSupportedMIMETypes []string, forcedListMIMEType string) (string, error) {
// of manifests (regardless of whether we are converting to it or using it
// unmodified) and a slice of other list types which might be supported by the
// destination.
func (c *copier) determineListConversion(currentListMIMEType string, destSupportedMIMETypes []string, forcedListMIMEType string) (string, []string, error) {
// If there's no list of supported types, then anything we support is expected to be supported.
if len(destSupportedMIMETypes) == 0 {
destSupportedMIMETypes = manifest.SupportedListMIMETypes
@@ -136,6 +138,7 @@ func (c *copier) determineListConversion(currentListMIMEType string, destSupport
destSupportedMIMETypes = []string{forcedListMIMEType}
}
var selectedType string
var otherSupportedTypes []string
for i := range destSupportedMIMETypes {
// The second priority is the first member of the list of acceptable types that is a list,
// but keep going in case current type occurs later in the list.
@@ -148,15 +151,21 @@ func (c *copier) determineListConversion(currentListMIMEType string, destSupport
selectedType = destSupportedMIMETypes[i]
}
}
// Pick out the other list types that we support.
for i := range destSupportedMIMETypes {
if selectedType != destSupportedMIMETypes[i] && manifest.MIMETypeIsMultiImage(destSupportedMIMETypes[i]) {
otherSupportedTypes = append(otherSupportedTypes, destSupportedMIMETypes[i])
}
}
logrus.Debugf("Manifest list has MIME type %s, ordered candidate list [%s]", currentListMIMEType, strings.Join(destSupportedMIMETypes, ", "))
if selectedType == "" {
return "", errors.Errorf("destination does not support any supported manifest list types (%v)", manifest.SupportedListMIMETypes)
return "", nil, errors.Errorf("destination does not support any supported manifest list types (%v)", manifest.SupportedListMIMETypes)
}
if selectedType != currentListMIMEType {
logrus.Debugf("... will convert to %s", selectedType)
logrus.Debugf("... will convert to %s first, and then try %v", selectedType, otherSupportedTypes)
} else {
logrus.Debugf("... will use the original manifest list type")
logrus.Debugf("... will use the original manifest list type, and then try %v", otherSupportedTypes)
}
// Done.
return selectedType, nil
return selectedType, otherSupportedTypes, nil
}

View File

@@ -41,10 +41,10 @@ func (t archiveTransport) ValidatePolicyConfigurationScope(scope string) error {
// archiveReference is an ImageReference for Docker images.
type archiveReference struct {
// only used for destinations
path string
// only used for destinations,
// archiveReference.destinationRef is optional and can be nil for destinations as well.
destinationRef reference.NamedTagged
path string
}
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an Docker ImageReference.
@@ -64,11 +64,6 @@ func ParseReference(refString string) (types.ImageReference, error) {
return nil, errors.Wrapf(err, "docker-archive parsing reference")
}
ref = reference.TagNameOnly(ref)
if _, isDigest := ref.(reference.Canonical); isDigest {
return nil, errors.Errorf("docker-archive doesn't support digest references: %s", refString)
}
refTagged, isTagged := ref.(reference.NamedTagged)
if !isTagged {
// Really shouldn't be hit...
@@ -77,9 +72,20 @@ func ParseReference(refString string) (types.ImageReference, error) {
destinationRef = refTagged
}
return NewReference(path, destinationRef)
}
// NewReference rethrns a Docker archive reference for a path and an optional destination reference.
func NewReference(path string, destinationRef reference.NamedTagged) (types.ImageReference, error) {
if strings.Contains(path, ":") {
return nil, errors.Errorf("Invalid docker-archive: reference: colon in path %q is not supported", path)
}
if _, isDigest := destinationRef.(reference.Canonical); isDigest {
return nil, errors.Errorf("docker-archive doesn't support digest references: %s", destinationRef.String())
}
return archiveReference{
destinationRef: destinationRef,
path: path,
destinationRef: destinationRef,
}, nil
}

View File

@@ -1,11 +1,13 @@
package docker
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@@ -21,6 +23,7 @@ import (
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/pkg/tlsclientconfig"
"github.com/containers/image/v5/types"
"github.com/containers/storage/pkg/homedir"
clientLib "github.com/docker/distribution/registry/client"
"github.com/docker/go-connections/tlsconfig"
digest "github.com/opencontainers/go-digest"
@@ -51,7 +54,18 @@ const (
backoffMaxDelay = 60 * time.Second
)
var systemPerHostCertDirPaths = [2]string{"/etc/containers/certs.d", "/etc/docker/certs.d"}
type certPath struct {
path string
absolute bool
}
var (
homeCertDir = filepath.FromSlash(".config/containers/certs.d")
perHostCertDirs = []certPath{
{path: "/etc/containers/certs.d", absolute: true},
{path: "/etc/docker/certs.d", absolute: true},
}
)
// extensionSignature and extensionSignatureList come from github.com/openshift/origin/pkg/dockerregistry/server/signaturedispatcher.go:
// signature represents a Docker image signature.
@@ -85,8 +99,8 @@ type dockerClient struct {
// by detectProperties(). Callers can edit tlsClientConfig.InsecureSkipVerify in the meantime.
tlsClientConfig *tls.Config
// The following members are not set by newDockerClient and must be set by callers if needed.
username string
password string
auth types.DockerAuthConfig
registryToken string
signatureBase signatureStorageBase
scope authScope
@@ -166,11 +180,12 @@ func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
hostCertDir string
fullCertDirPath string
)
for _, systemPerHostCertDirPath := range systemPerHostCertDirPaths {
if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
hostCertDir = filepath.Join(sys.RootForImplicitAbsolutePaths, systemPerHostCertDirPath)
for _, perHostCertDir := range append([]certPath{{path: filepath.Join(homedir.Get(), homeCertDir), absolute: false}}, perHostCertDirs...) {
if sys != nil && sys.RootForImplicitAbsolutePaths != "" && perHostCertDir.absolute {
hostCertDir = filepath.Join(sys.RootForImplicitAbsolutePaths, perHostCertDir.path)
} else {
hostCertDir = systemPerHostCertDirPath
hostCertDir = perHostCertDir.path
}
fullCertDirPath = filepath.Join(hostCertDir, hostPort)
@@ -196,10 +211,11 @@ func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, write bool, actions string) (*dockerClient, error) {
registry := reference.Domain(ref.ref)
username, password, err := config.GetAuthentication(sys, registry)
auth, err := config.GetCredentials(sys, registry)
if err != nil {
return nil, errors.Wrapf(err, "error getting username and password")
}
sigBase, err := configuredSignatureStorageBase(sys, ref, write)
if err != nil {
return nil, err
@@ -209,8 +225,10 @@ func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, write
if err != nil {
return nil, err
}
client.username = username
client.password = password
client.auth = auth
if sys != nil {
client.registryToken = sys.DockerBearerRegistryToken
}
client.signatureBase = sigBase
client.scope.actions = actions
client.scope.remoteName = reference.Path(ref.ref)
@@ -252,7 +270,7 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
}
if reg != nil {
if reg.Blocked {
return nil, fmt.Errorf("registry %s is blocked in %s", reg.Prefix, sysregistriesv2.ConfigPath(sys))
return nil, fmt.Errorf("registry %s is blocked in %s or %s", reg.Prefix, sysregistriesv2.ConfigPath(sys), sysregistriesv2.ConfigDirPath(sys))
}
skipVerify = reg.Insecure
}
@@ -272,8 +290,10 @@ func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password
if err != nil {
return errors.Wrapf(err, "error creating new docker client")
}
client.username = username
client.password = password
client.auth = types.DockerAuthConfig{
Username: username,
Password: password,
}
resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth, nil)
if err != nil {
@@ -315,7 +335,7 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
v1Res := &V1Results{}
// Get credentials from authfile for the underlying hostname
username, password, err := config.GetAuthentication(sys, registry)
auth, err := config.GetCredentials(sys, registry)
if err != nil {
return nil, errors.Wrapf(err, "error getting username and password")
}
@@ -333,8 +353,10 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
if err != nil {
return nil, errors.Wrapf(err, "error creating new docker client")
}
client.username = username
client.password = password
client.auth = auth
if sys != nil {
client.registryToken = sys.DockerBearerRegistryToken
}
// Only try the v1 search endpoint if the search query is not empty. If it is
// empty skip to the v2 endpoint.
@@ -515,30 +537,43 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
schemeNames = append(schemeNames, challenge.Scheme)
switch challenge.Scheme {
case "basic":
req.SetBasicAuth(c.username, c.password)
req.SetBasicAuth(c.auth.Username, c.auth.Password)
return nil
case "bearer":
cacheKey := ""
scopes := []authScope{c.scope}
if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
cacheKey = fmt.Sprintf("%s:%s", extraScope.remoteName, extraScope.actions)
scopes = append(scopes, *extraScope)
}
var token bearerToken
t, inCache := c.tokenCache.Load(cacheKey)
if inCache {
token = t.(bearerToken)
}
if !inCache || time.Now().After(token.expirationTime) {
t, err := c.getBearerToken(req.Context(), challenge, scopes)
if err != nil {
return err
registryToken := c.registryToken
if registryToken == "" {
cacheKey := ""
scopes := []authScope{c.scope}
if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
cacheKey = fmt.Sprintf("%s:%s", extraScope.remoteName, extraScope.actions)
scopes = append(scopes, *extraScope)
}
token = *t
c.tokenCache.Store(cacheKey, token)
var token bearerToken
t, inCache := c.tokenCache.Load(cacheKey)
if inCache {
token = t.(bearerToken)
}
if !inCache || time.Now().After(token.expirationTime) {
var (
t *bearerToken
err error
)
if c.auth.IdentityToken != "" {
t, err = c.getBearerTokenOAuth2(req.Context(), challenge, scopes)
} else {
t, err = c.getBearerToken(req.Context(), challenge, scopes)
}
if err != nil {
return err
}
token = *t
c.tokenCache.Store(cacheKey, token)
}
registryToken = token.Token
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Token))
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken))
return nil
default:
logrus.Debugf("no handler for %s authentication", challenge.Scheme)
@@ -548,48 +583,97 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
return nil
}
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, scopes []authScope) (*bearerToken, error) {
func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge challenge,
scopes []authScope) (*bearerToken, error) {
realm, ok := challenge.Parameters["realm"]
if !ok {
return nil, errors.Errorf("missing realm in bearer auth challenge")
}
authReq, err := http.NewRequest("GET", realm, nil)
authReq, err := http.NewRequest(http.MethodPost, realm, nil)
if err != nil {
return nil, err
}
authReq = authReq.WithContext(ctx)
getParams := authReq.URL.Query()
if c.username != "" {
getParams.Add("account", c.username)
}
// Make the form data required against the oauth2 authentication
// More details here: https://docs.docker.com/registry/spec/auth/oauth/
params := authReq.URL.Query()
if service, ok := challenge.Parameters["service"]; ok && service != "" {
getParams.Add("service", service)
params.Add("service", service)
}
for _, scope := range scopes {
if scope.remoteName != "" && scope.actions != "" {
getParams.Add("scope", fmt.Sprintf("repository:%s:%s", scope.remoteName, scope.actions))
params.Add("scope", fmt.Sprintf("repository:%s:%s", scope.remoteName, scope.actions))
}
}
authReq.URL.RawQuery = getParams.Encode()
if c.username != "" && c.password != "" {
authReq.SetBasicAuth(c.username, c.password)
}
params.Add("grant_type", "refresh_token")
params.Add("refresh_token", c.auth.IdentityToken)
params.Add("client_id", "containers/image")
authReq.Body = ioutil.NopCloser(bytes.NewBufferString(params.Encode()))
authReq.Header.Add("Content-Type", "application/x-www-form-urlencoded")
logrus.Debugf("%s %s", authReq.Method, authReq.URL.String())
res, err := c.client.Do(authReq)
if err != nil {
return nil, err
}
defer res.Body.Close()
switch res.StatusCode {
case http.StatusUnauthorized:
err := clientLib.HandleErrorResponse(res)
logrus.Debugf("Server response when trying to obtain an access token: \n%q", err.Error())
return nil, ErrUnauthorizedForCredentials{Err: err}
case http.StatusOK:
break
default:
return nil, errors.Errorf("unexpected http code: %d (%s), URL: %s", res.StatusCode, http.StatusText(res.StatusCode), authReq.URL)
if err := httpResponseToError(res, "Trying to obtain access token"); err != nil {
return nil, err
}
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
if err != nil {
return nil, err
}
return newBearerTokenFromJSONBlob(tokenBlob)
}
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
scopes []authScope) (*bearerToken, error) {
realm, ok := challenge.Parameters["realm"]
if !ok {
return nil, errors.Errorf("missing realm in bearer auth challenge")
}
authReq, err := http.NewRequest(http.MethodGet, realm, nil)
if err != nil {
return nil, err
}
authReq = authReq.WithContext(ctx)
params := authReq.URL.Query()
if c.auth.Username != "" {
params.Add("account", c.auth.Username)
}
if service, ok := challenge.Parameters["service"]; ok && service != "" {
params.Add("service", service)
}
for _, scope := range scopes {
if scope.remoteName != "" && scope.actions != "" {
params.Add("scope", fmt.Sprintf("repository:%s:%s", scope.remoteName, scope.actions))
}
}
authReq.URL.RawQuery = params.Encode()
if c.auth.Username != "" && c.auth.Password != "" {
authReq.SetBasicAuth(c.auth.Username, c.auth.Password)
}
logrus.Debugf("%s %s", authReq.Method, authReq.URL.String())
res, err := c.client.Do(authReq)
if err != nil {
return nil, err
}
defer res.Body.Close()
if err := httpResponseToError(res, "Requesting bear token"); err != nil {
return nil, err
}
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
if err != nil {

View File

@@ -108,6 +108,7 @@ func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, pullSo
if endpointSys != nil && endpointSys.DockerAuthConfig != nil && reference.Domain(ref.ref) != primaryDomain {
copy := *endpointSys
copy.DockerAuthConfig = nil
copy.DockerBearerRegistryToken = ""
endpointSys = &copy
}

View File

@@ -249,6 +249,9 @@ func (s *Source) ensureCachedDataIsPresentPrivate() error {
if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
return errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
}
if parsedConfig.RootFS == nil {
return errors.Errorf("Invalid image config (rootFS is not set): %s", tarManifest[0].Config)
}
knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
if err != nil {

View File

@@ -56,7 +56,7 @@ func (m *manifestSchema1) ConfigBlob(context.Context) ([]byte, error) {
// layers in the resulting configuration isn't guaranteed to be returned to due how
// old image manifests work (docker v2s1 especially).
func (m *manifestSchema1) OCIConfig(ctx context.Context) (*imgspecv1.Image, error) {
v2s2, err := m.convertToManifestSchema2(nil, nil)
v2s2, err := m.convertToManifestSchema2(ctx, &types.ManifestUpdateOptions{})
if err != nil {
return nil, err
}
@@ -107,6 +107,24 @@ func (m *manifestSchema1) UpdatedImageNeedsLayerDiffIDs(options types.ManifestUp
// This does not change the state of the original Image object.
func (m *manifestSchema1) UpdatedImage(ctx context.Context, options types.ManifestUpdateOptions) (types.Image, error) {
copy := manifestSchema1{m: manifest.Schema1Clone(m.m)}
// We have 2 MIME types for schema 1, which are basically equivalent (even the un-"Signed" MIME type will be rejected if there isnt a signature; so,
// handle conversions between them by doing nothing.
if options.ManifestMIMEType != manifest.DockerV2Schema1MediaType && options.ManifestMIMEType != manifest.DockerV2Schema1SignedMediaType {
converted, err := convertManifestIfRequiredWithUpdate(ctx, options, map[string]manifestConvertFn{
imgspecv1.MediaTypeImageManifest: copy.convertToManifestOCI1,
manifest.DockerV2Schema2MediaType: copy.convertToManifestSchema2Generic,
})
if err != nil {
return nil, err
}
if converted != nil {
return converted, nil
}
}
// No conversion required, update manifest
if options.LayerInfos != nil {
if err := copy.m.UpdateLayerInfos(options.LayerInfos); err != nil {
return nil, err
@@ -121,36 +139,30 @@ func (m *manifestSchema1) UpdatedImage(ctx context.Context, options types.Manife
}
}
switch options.ManifestMIMEType {
case "": // No conversion, OK
case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType:
// We have 2 MIME types for schema 1, which are basically equivalent (even the un-"Signed" MIME type will be rejected if there isnt a signature; so,
// handle conversions between them by doing nothing.
case manifest.DockerV2Schema2MediaType:
m2, err := copy.convertToManifestSchema2(options.InformationOnly.LayerInfos, options.InformationOnly.LayerDiffIDs)
if err != nil {
return nil, err
}
return memoryImageFromManifest(m2), nil
case imgspecv1.MediaTypeImageManifest:
// We can't directly convert to OCI, but we can transitively convert via a Docker V2.2 Distribution manifest
m2, err := copy.convertToManifestSchema2(options.InformationOnly.LayerInfos, options.InformationOnly.LayerDiffIDs)
if err != nil {
return nil, err
}
return m2.UpdatedImage(ctx, types.ManifestUpdateOptions{
ManifestMIMEType: imgspecv1.MediaTypeImageManifest,
InformationOnly: options.InformationOnly,
})
default:
return nil, errors.Errorf("Conversion of image manifest from %s to %s is not implemented", manifest.DockerV2Schema1SignedMediaType, options.ManifestMIMEType)
}
return memoryImageFromManifest(&copy), nil
}
// convertToManifestSchema2Generic returns a genericManifest implementation converted to manifest.DockerV2Schema2MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema1 object.
//
// We need this function just because a function returning an implementation of the genericManifest
// interface is not automatically assignable to a function type returning the genericManifest interface
func (m *manifestSchema1) convertToManifestSchema2Generic(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
return m.convertToManifestSchema2(ctx, options)
}
// convertToManifestSchema2 returns a genericManifest implementation converted to manifest.DockerV2Schema2MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema1 object.
//
// Based on github.com/docker/docker/distribution/pull_v2.go
func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.BlobInfo, layerDiffIDs []digest.Digest) (genericManifest, error) {
func (m *manifestSchema1) convertToManifestSchema2(_ context.Context, options *types.ManifestUpdateOptions) (*manifestSchema2, error) {
uploadedLayerInfos := options.InformationOnly.LayerInfos
layerDiffIDs := options.InformationOnly.LayerDiffIDs
if len(m.m.ExtractedV1Compatibility) == 0 {
// What would this even mean?! Anyhow, the rest of the code depends on FSLayers[0] and ExtractedV1Compatibility[0] existing.
return nil, errors.Errorf("Cannot convert an image with 0 history entries to %s", manifest.DockerV2Schema2MediaType)
@@ -165,6 +177,15 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl
return nil, errors.Errorf("Internal error: collected %d DiffID values, but schema1 manifest has %d fsLayers", len(layerDiffIDs), len(m.m.FSLayers))
}
var convertedLayerUpdates []types.BlobInfo // Only used if options.LayerInfos != nil
if options.LayerInfos != nil {
if len(options.LayerInfos) != len(m.m.FSLayers) {
return nil, errors.Errorf("Error converting image: layer edits for %d layers vs %d existing layers",
len(options.LayerInfos), len(m.m.FSLayers))
}
convertedLayerUpdates = []types.BlobInfo{}
}
// Build a list of the diffIDs for the non-empty layers.
diffIDs := []digest.Digest{}
var layers []manifest.Schema2Descriptor
@@ -185,6 +206,9 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl
Size: size,
Digest: m.m.FSLayers[v1Index].BlobSum,
})
if options.LayerInfos != nil {
convertedLayerUpdates = append(convertedLayerUpdates, options.LayerInfos[v2Index])
}
diffIDs = append(diffIDs, d)
}
}
@@ -198,9 +222,26 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl
Digest: digest.FromBytes(configJSON),
}
if options.LayerInfos != nil {
options.LayerInfos = convertedLayerUpdates
}
return manifestSchema2FromComponents(configDescriptor, nil, configJSON, layers), nil
}
// convertToManifestOCI1 returns a genericManifest implementation converted to imgspecv1.MediaTypeImageManifest.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema1 object.
func (m *manifestSchema1) convertToManifestOCI1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
// We can't directly convert to OCI, but we can transitively convert via a Docker V2.2 Distribution manifest
m2, err := m.convertToManifestSchema2(ctx, options)
if err != nil {
return nil, err
}
return m2.convertToManifestOCI1(ctx, options)
}
// SupportsEncryption returns if encryption is supported for the manifest type
func (m *manifestSchema1) SupportsEncryption(context.Context) bool {
return false

View File

@@ -50,7 +50,7 @@ func manifestSchema2FromManifest(src types.ImageSource, manifestBlob []byte) (ge
}
// manifestSchema2FromComponents builds a new manifestSchema2 from the supplied data:
func manifestSchema2FromComponents(config manifest.Schema2Descriptor, src types.ImageSource, configBlob []byte, layers []manifest.Schema2Descriptor) genericManifest {
func manifestSchema2FromComponents(config manifest.Schema2Descriptor, src types.ImageSource, configBlob []byte, layers []manifest.Schema2Descriptor) *manifestSchema2 {
return &manifestSchema2{
src: src,
configBlob: configBlob,
@@ -160,6 +160,21 @@ func (m *manifestSchema2) UpdatedImage(ctx context.Context, options types.Manife
configBlob: m.configBlob,
m: manifest.Schema2Clone(m.m),
}
converted, err := convertManifestIfRequiredWithUpdate(ctx, options, map[string]manifestConvertFn{
manifest.DockerV2Schema1MediaType: copy.convertToManifestSchema1,
manifest.DockerV2Schema1SignedMediaType: copy.convertToManifestSchema1,
imgspecv1.MediaTypeImageManifest: copy.convertToManifestOCI1,
})
if err != nil {
return nil, err
}
if converted != nil {
return converted, nil
}
// No conversion required, update manifest
if options.LayerInfos != nil {
if err := copy.m.UpdateLayerInfos(options.LayerInfos); err != nil {
return nil, err
@@ -167,16 +182,6 @@ func (m *manifestSchema2) UpdatedImage(ctx context.Context, options types.Manife
}
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1 to schema2, but we really don't care.
switch options.ManifestMIMEType {
case "": // No conversion, OK
case manifest.DockerV2Schema1SignedMediaType, manifest.DockerV2Schema1MediaType:
return copy.convertToManifestSchema1(ctx, options.InformationOnly.Destination)
case imgspecv1.MediaTypeImageManifest:
return copy.convertToManifestOCI1(ctx)
default:
return nil, errors.Errorf("Conversion of image manifest from %s to %s is not implemented", manifest.DockerV2Schema2MediaType, options.ManifestMIMEType)
}
return memoryImageFromManifest(&copy), nil
}
@@ -189,7 +194,11 @@ func oci1DescriptorFromSchema2Descriptor(d manifest.Schema2Descriptor) imgspecv1
}
}
func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context) (types.Image, error) {
// convertToManifestOCI1 returns a genericManifest implementation converted to imgspecv1.MediaTypeImageManifest.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema2 object.
func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context, _ *types.ManifestUpdateOptions) (genericManifest, error) {
configOCI, err := m.OCIConfig(ctx)
if err != nil {
return nil, err
@@ -222,12 +231,27 @@ func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context) (types.Imag
}
}
m1 := manifestOCI1FromComponents(config, m.src, configOCIBytes, layers)
return memoryImageFromManifest(m1), nil
return manifestOCI1FromComponents(config, m.src, configOCIBytes, layers), nil
}
// convertToManifestSchema1 returns a genericManifest implementation converted to manifest.DockerV2Schema1{Signed,}MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema2 object.
//
// Based on docker/distribution/manifest/schema1/config_builder.go
func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, dest types.ImageDestination) (types.Image, error) {
func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
dest := options.InformationOnly.Destination
var convertedLayerUpdates []types.BlobInfo // Only used if options.LayerInfos != nil
if options.LayerInfos != nil {
if len(options.LayerInfos) != len(m.m.LayersDescriptors) {
return nil, fmt.Errorf("Error converting image: layer edits for %d layers vs %d existing layers",
len(options.LayerInfos), len(m.m.LayersDescriptors))
}
convertedLayerUpdates = []types.BlobInfo{}
}
configBytes, err := m.ConfigBlob(ctx)
if err != nil {
return nil, err
@@ -254,24 +278,32 @@ func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, dest typ
var blobDigest digest.Digest
if historyEntry.EmptyLayer {
emptyLayerBlobInfo := types.BlobInfo{Digest: GzippedEmptyLayerDigest, Size: int64(len(GzippedEmptyLayer))}
if !haveGzippedEmptyLayer {
logrus.Debugf("Uploading empty layer during conversion to schema 1")
// Ideally we should update the relevant BlobInfoCache about this layer, but that would require passing it down here,
// and anyway this blob is so small that its easier to just copy it than to worry about figuring out another location where to get it.
info, err := dest.PutBlob(ctx, bytes.NewReader(GzippedEmptyLayer), types.BlobInfo{Digest: GzippedEmptyLayerDigest, Size: int64(len(GzippedEmptyLayer))}, none.NoCache, false)
info, err := dest.PutBlob(ctx, bytes.NewReader(GzippedEmptyLayer), emptyLayerBlobInfo, none.NoCache, false)
if err != nil {
return nil, errors.Wrap(err, "Error uploading empty layer")
}
if info.Digest != GzippedEmptyLayerDigest {
return nil, errors.Errorf("Internal error: Uploaded empty layer has digest %#v instead of %s", info.Digest, GzippedEmptyLayerDigest)
if info.Digest != emptyLayerBlobInfo.Digest {
return nil, errors.Errorf("Internal error: Uploaded empty layer has digest %#v instead of %s", info.Digest, emptyLayerBlobInfo.Digest)
}
haveGzippedEmptyLayer = true
}
blobDigest = GzippedEmptyLayerDigest
if options.LayerInfos != nil {
convertedLayerUpdates = append(convertedLayerUpdates, emptyLayerBlobInfo)
}
blobDigest = emptyLayerBlobInfo.Digest
} else {
if nonemptyLayerIndex >= len(m.m.LayersDescriptors) {
return nil, errors.Errorf("Invalid image configuration, needs more than the %d distributed layers", len(m.m.LayersDescriptors))
}
if options.LayerInfos != nil {
convertedLayerUpdates = append(convertedLayerUpdates, options.LayerInfos[nonemptyLayerIndex])
}
blobDigest = m.m.LayersDescriptors[nonemptyLayerIndex].Digest
nonemptyLayerIndex++
}
@@ -313,11 +345,14 @@ func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, dest typ
}
history[0].V1Compatibility = string(v1Config)
if options.LayerInfos != nil {
options.LayerInfos = convertedLayerUpdates
}
m1, err := manifestSchema1FromComponents(dest.Reference().DockerReference(), fsLayers, history, imageConfig.Architecture)
if err != nil {
return nil, err // This should never happen, we should have created all the components correctly.
}
return memoryImageFromManifest(m1), nil
return m1, nil
}
func v1IDFromBlobDigestAndComponents(blobDigest digest.Digest, others ...string) (string, error) {

View File

@@ -8,6 +8,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// genericManifest is an interface for parsing, modifying image manifests and related data.
@@ -45,6 +46,10 @@ type genericManifest interface {
// This does not change the state of the original Image object.
UpdatedImage(ctx context.Context, options types.ManifestUpdateOptions) (types.Image, error)
// SupportsEncryption returns if encryption is supported for the manifest type
//
// Deprecated: Initially used to determine if a manifest can be copied from a source manifest type since
// the process of updating a manifest between different manifest types was to update then convert.
// This resulted in some fields in the update being lost. This has been fixed by: https://github.com/containers/image/pull/836
SupportsEncryption(ctx context.Context) bool
}
@@ -75,3 +80,34 @@ func manifestLayerInfosToBlobInfos(layers []manifest.LayerInfo) []types.BlobInfo
}
return blobs
}
// manifestConvertFn (a method of genericManifest object) returns a genericManifest implementation
// converted to a specific manifest MIME type.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original genericManifest object.
type manifestConvertFn func(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error)
// convertManifestIfRequiredWithUpdate will run conversion functions of a manifest if
// required and re-apply the options to the converted type.
// It returns (nil, nil) if no conversion was requested.
func convertManifestIfRequiredWithUpdate(ctx context.Context, options types.ManifestUpdateOptions, converters map[string]manifestConvertFn) (types.Image, error) {
if options.ManifestMIMEType == "" {
return nil, nil
}
converter, ok := converters[options.ManifestMIMEType]
if !ok {
return nil, errors.Errorf("Unsupported conversion type: %v", options.ManifestMIMEType)
}
optionsCopy := options
convertedManifest, err := converter(ctx, &optionsCopy)
if err != nil {
return nil, err
}
convertedImage := memoryImageFromManifest(convertedManifest)
optionsCopy.ManifestMIMEType = ""
return convertedImage.UpdatedImage(ctx, optionsCopy)
}

View File

@@ -140,6 +140,21 @@ func (m *manifestOCI1) UpdatedImage(ctx context.Context, options types.ManifestU
configBlob: m.configBlob,
m: manifest.OCI1Clone(m.m),
}
converted, err := convertManifestIfRequiredWithUpdate(ctx, options, map[string]manifestConvertFn{
manifest.DockerV2Schema2MediaType: copy.convertToManifestSchema2Generic,
manifest.DockerV2Schema1MediaType: copy.convertToManifestSchema1,
manifest.DockerV2Schema1SignedMediaType: copy.convertToManifestSchema1,
})
if err != nil {
return nil, err
}
if converted != nil {
return converted, nil
}
// No conversion required, update manifest
if options.LayerInfos != nil {
if err := copy.m.UpdateLayerInfos(options.LayerInfos); err != nil {
return nil, err
@@ -147,24 +162,6 @@ func (m *manifestOCI1) UpdatedImage(ctx context.Context, options types.ManifestU
}
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1, but we really don't care.
switch options.ManifestMIMEType {
case "": // No conversion, OK
case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType:
// We can't directly convert to V1, but we can transitively convert via a V2 image
m2, err := copy.convertToManifestSchema2()
if err != nil {
return nil, err
}
return m2.UpdatedImage(ctx, types.ManifestUpdateOptions{
ManifestMIMEType: options.ManifestMIMEType,
InformationOnly: options.InformationOnly,
})
case manifest.DockerV2Schema2MediaType:
return copy.convertToManifestSchema2()
default:
return nil, errors.Errorf("Conversion of image manifest from %s to %s is not implemented", imgspecv1.MediaTypeImageManifest, options.ManifestMIMEType)
}
return memoryImageFromManifest(&copy), nil
}
@@ -177,7 +174,22 @@ func schema2DescriptorFromOCI1Descriptor(d imgspecv1.Descriptor) manifest.Schema
}
}
func (m *manifestOCI1) convertToManifestSchema2() (types.Image, error) {
// convertToManifestSchema2Generic returns a genericManifest implementation converted to manifest.DockerV2Schema2MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestSchema1 object.
//
// We need this function just because a function returning an implementation of the genericManifest
// interface is not automatically assignable to a function type returning the genericManifest interface
func (m *manifestOCI1) convertToManifestSchema2Generic(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
return m.convertToManifestSchema2(ctx, options)
}
// convertToManifestSchema2 returns a genericManifest implementation converted to manifest.DockerV2Schema2MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestOCI1 object.
func (m *manifestOCI1) convertToManifestSchema2(_ context.Context, _ *types.ManifestUpdateOptions) (*manifestSchema2, error) {
// Create a copy of the descriptor.
config := schema2DescriptorFromOCI1Descriptor(m.m.Config)
@@ -209,8 +221,21 @@ func (m *manifestOCI1) convertToManifestSchema2() (types.Image, error) {
// Rather than copying the ConfigBlob now, we just pass m.src to the
// translated manifest, since the only difference is the mediatype of
// descriptors there is no change to any blob stored in m.src.
m1 := manifestSchema2FromComponents(config, m.src, nil, layers)
return memoryImageFromManifest(m1), nil
return manifestSchema2FromComponents(config, m.src, nil, layers), nil
}
// convertToManifestSchema1 returns a genericManifest implementation converted to manifest.DockerV2Schema1{Signed,}MediaType.
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
// value.
// This does not change the state of the original manifestOCI1 object.
func (m *manifestOCI1) convertToManifestSchema1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
// We can't directly convert to V1, but we can transitively convert via a V2 image
m2, err := m.convertToManifestSchema2(ctx, options)
if err != nil {
return nil, err
}
return m2.convertToManifestSchema1(ctx, options)
}
// SupportsEncryption returns if encryption is supported for the manifest type

View File

@@ -0,0 +1,203 @@
package platform
// Largely based on
// https://github.com/moby/moby/blob/bc846d2e8fe5538220e0c31e9d0e8446f6fbc022/distribution/cpuinfo_unix.go
// Copyright 2012-2017 Docker, Inc.
//
// https://github.com/containerd/containerd/blob/726dcaea50883e51b2ec6db13caff0e7936b711d/platforms/cpuinfo.go
// Copyright The containerd 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.
import (
"bufio"
"fmt"
"os"
"runtime"
"strings"
"github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)
// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
if runtime.GOOS != "linux" {
return "", fmt.Errorf("getCPUInfo for OS %s not implemented", runtime.GOOS)
}
cpuinfo, err := os.Open("/proc/cpuinfo")
if err != nil {
return "", err
}
defer cpuinfo.Close()
// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
// the first core is enough.
scanner := bufio.NewScanner(cpuinfo)
for scanner.Scan() {
newline := scanner.Text()
list := strings.Split(newline, ":")
if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
return strings.TrimSpace(list[1]), nil
}
}
// Check whether the scanner encountered errors
err = scanner.Err()
if err != nil {
return "", err
}
return "", fmt.Errorf("getCPUInfo for pattern: %s not found", pattern)
}
func getCPUVariantWindows(arch string) string {
// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
// runtime.GOARCH to determine the variants
var variant string
switch arch {
case "arm64":
variant = "v8"
case "arm":
variant = "v7"
default:
variant = ""
}
return variant
}
func getCPUVariantArm() string {
variant, err := getCPUInfo("Cpu architecture")
if err != nil {
return ""
}
// TODO handle RPi Zero mismatch (https://github.com/moby/moby/pull/36121#issuecomment-398328286)
switch strings.ToLower(variant) {
case "8", "aarch64":
variant = "v8"
case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
variant = "v7"
case "6", "6tej":
variant = "v6"
case "5", "5t", "5te", "5tej":
variant = "v5"
case "4", "4t":
variant = "v4"
case "3":
variant = "v3"
default:
variant = ""
}
return variant
}
func getCPUVariant(os string, arch string) string {
if os == "windows" {
return getCPUVariantWindows(arch)
}
if arch == "arm" || arch == "arm64" {
return getCPUVariantArm()
}
return ""
}
var compatibility = map[string][]string{
"arm": {"v7", "v6", "v5"},
"arm64": {"v8"},
}
// Returns all compatible platforms with the platform specifics possibly overriden by user,
// the most compatible platform is first.
// If some option (arch, os, variant) is not present, a value from current platform is detected.
func WantedPlatforms(ctx *types.SystemContext) ([]imgspecv1.Platform, error) {
wantedArch := runtime.GOARCH
wantedVariant := ""
if ctx != nil && ctx.ArchitectureChoice != "" {
wantedArch = ctx.ArchitectureChoice
} else {
// Only auto-detect the variant if we are using the default architecture.
// If the user has specified the ArchitectureChoice, don't autodetect, even if
// ctx.ArchitectureChoice == runtime.GOARCH, because we have no idea whether the runtime.GOARCH
// value is relevant to the use case, and if we do autodetect a variant,
// ctx.VariantChoice can't be used to override it back to "".
wantedVariant = getCPUVariant(runtime.GOOS, runtime.GOARCH)
}
if ctx != nil && ctx.VariantChoice != "" {
wantedVariant = ctx.VariantChoice
}
wantedOS := runtime.GOOS
if ctx != nil && ctx.OSChoice != "" {
wantedOS = ctx.OSChoice
}
var wantedPlatforms []imgspecv1.Platform
if wantedVariant != "" && compatibility[wantedArch] != nil {
wantedPlatforms = make([]imgspecv1.Platform, 0, len(compatibility[wantedArch]))
wantedIndex := -1
for i, v := range compatibility[wantedArch] {
if wantedVariant == v {
wantedIndex = i
break
}
}
// user wants a variant which we know nothing about - not even compatibility
if wantedIndex == -1 {
wantedPlatforms = []imgspecv1.Platform{
{
OS: wantedOS,
Architecture: wantedArch,
Variant: wantedVariant,
},
}
} else {
for i := wantedIndex; i < len(compatibility[wantedArch]); i++ {
v := compatibility[wantedArch][i]
wantedPlatforms = append(wantedPlatforms, imgspecv1.Platform{
OS: wantedOS,
Architecture: wantedArch,
Variant: v,
})
}
}
} else {
wantedPlatforms = []imgspecv1.Platform{
{
OS: wantedOS,
Architecture: wantedArch,
Variant: wantedVariant,
},
}
}
return wantedPlatforms, nil
}
func MatchesPlatform(image imgspecv1.Platform, wanted imgspecv1.Platform) bool {
if image.Architecture != wanted.Architecture {
return false
}
if image.OS != wanted.OS {
return false
}
if wanted.Variant == "" || image.Variant == wanted.Variant {
return true
}
return false
}

View File

@@ -118,9 +118,11 @@ type Schema2V1Image struct {
Author string `json:"author,omitempty"`
// Config is the configuration of the container received from the client
Config *Schema2Config `json:"config,omitempty"`
// Architecture is the hardware that the image is build and runs on
// Architecture is the hardware that the image is built and runs on
Architecture string `json:"architecture,omitempty"`
// OS is the operating system used to build and run the image
// Variant is a variant of the CPU that the image is built and runs on
Variant string `json:"variant,omitempty"`
// OS is the operating system used to built and run the image
OS string `json:"os,omitempty"`
// Size is the total size of the image including all layers it is composed of
Size int64 `json:",omitempty"`
@@ -330,6 +332,7 @@ func (m *Schema2) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*t
Created: &s2.Created,
DockerVersion: s2.DockerVersion,
Architecture: s2.Architecture,
Variant: s2.Variant,
Os: s2.OS,
Layers: layerInfosToStrings(m.LayerInfos()),
}

View File

@@ -3,8 +3,8 @@ package manifest
import (
"encoding/json"
"fmt"
"runtime"
platform "github.com/containers/image/v5/internal/pkg/platform"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -81,9 +81,6 @@ func (list *Schema2List) UpdateInstances(updates []ListUpdate) error {
if updates[i].MediaType == "" {
return errors.Errorf("update %d of %d passed to Schema2List.UpdateInstances had no media type (was %q)", i+1, len(updates), list.Manifests[i].MediaType)
}
if err := SupportedSchema2MediaType(updates[i].MediaType); err != nil && SupportedOCI1MediaType(updates[i].MediaType) != nil {
return errors.Wrapf(err, "update %d of %d passed to Schema2List.UpdateInstances had an unsupported media type (was %q): %q", i+1, len(updates), list.Manifests[i].MediaType, updates[i].MediaType)
}
list.Manifests[i].MediaType = updates[i].MediaType
}
return nil
@@ -92,21 +89,25 @@ func (list *Schema2List) UpdateInstances(updates []ListUpdate) error {
// ChooseInstance parses blob as a schema2 manifest list, and returns the digest
// of the image which is appropriate for the current environment.
func (list *Schema2List) ChooseInstance(ctx *types.SystemContext) (digest.Digest, error) {
wantedArch := runtime.GOARCH
if ctx != nil && ctx.ArchitectureChoice != "" {
wantedArch = ctx.ArchitectureChoice
wantedPlatforms, err := platform.WantedPlatforms(ctx)
if err != nil {
return "", errors.Wrapf(err, "error getting platform information %#v", ctx)
}
wantedOS := runtime.GOOS
if ctx != nil && ctx.OSChoice != "" {
wantedOS = ctx.OSChoice
}
for _, d := range list.Manifests {
if d.Platform.Architecture == wantedArch && d.Platform.OS == wantedOS {
return d.Digest, nil
for _, wantedPlatform := range wantedPlatforms {
for _, d := range list.Manifests {
imagePlatform := imgspecv1.Platform{
Architecture: d.Platform.Architecture,
OS: d.Platform.OS,
OSVersion: d.Platform.OSVersion,
OSFeatures: dupStringSlice(d.Platform.OSFeatures),
Variant: d.Platform.Variant,
}
if platform.MatchesPlatform(imagePlatform, wantedPlatform) {
return d.Digest, nil
}
}
}
return "", fmt.Errorf("no image found in manifest list for architecture %s, OS %s", wantedArch, wantedOS)
return "", fmt.Errorf("no image found in manifest list for architecture %s, variant %s, OS %s", wantedPlatforms[0].Architecture, wantedPlatforms[0].Variant, wantedPlatforms[0].OS)
}
// Serialize returns the list in a blob format.

View File

@@ -32,7 +32,14 @@ type OCI1 struct {
imgspecv1.Manifest
}
// SupportedOCI1MediaType checks if the specified string is a supported OCI1 media type.
// SupportedOCI1MediaType checks if the specified string is a supported OCI1
// media type.
//
// Deprecated: blindly rejecting unknown MIME types when the consumer does not
// need to process the input just reduces interoperability (and violates the
// standard) with no benefit, and that this function does not check that the
// media type is appropriate for any specific purpose, so its not all that
// useful for validation anyway.
func SupportedOCI1MediaType(m string) error {
switch m {
case imgspecv1.MediaTypeDescriptor, imgspecv1.MediaTypeImageConfig, imgspecv1.MediaTypeImageLayer, imgspecv1.MediaTypeImageLayerGzip, imgspecv1.MediaTypeImageLayerNonDistributable, imgspecv1.MediaTypeImageLayerNonDistributableGzip, imgspecv1.MediaTypeImageLayerNonDistributableZstd, imgspecv1.MediaTypeImageLayerZstd, imgspecv1.MediaTypeImageManifest, imgspecv1.MediaTypeLayoutHeader, ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc:
@@ -48,15 +55,6 @@ func OCI1FromManifest(manifest []byte) (*OCI1, error) {
if err := json.Unmarshal(manifest, &oci1); err != nil {
return nil, err
}
// Check manifest's and layers' media types.
if err := SupportedOCI1MediaType(oci1.Config.MediaType); err != nil {
return nil, err
}
for _, layer := range oci1.Layers {
if err := SupportedOCI1MediaType(layer.MediaType); err != nil {
return nil, err
}
}
return &oci1, nil
}
@@ -128,11 +126,6 @@ func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
m.Layers = make([]imgspecv1.Descriptor, len(layerInfos))
for i, info := range layerInfos {
mimeType := original[i].MediaType
// First make sure we support the media type of the original layer.
if err := SupportedOCI1MediaType(original[i].MediaType); err != nil {
return fmt.Errorf("Error preparing updated manifest: unknown media type of original layer: %q", original[i].MediaType)
}
if info.CryptoOperation == types.Decrypt {
decMimeType, err := getDecryptedMediaType(mimeType)
if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"runtime"
platform "github.com/containers/image/v5/internal/pkg/platform"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
imgspec "github.com/opencontainers/image-spec/specs-go"
@@ -64,9 +65,6 @@ func (index *OCI1Index) UpdateInstances(updates []ListUpdate) error {
if updates[i].MediaType == "" {
return errors.Errorf("update %d of %d passed to OCI1Index.UpdateInstances had no media type (was %q)", i+1, len(updates), index.Manifests[i].MediaType)
}
if err := SupportedOCI1MediaType(updates[i].MediaType); err != nil && SupportedSchema2MediaType(updates[i].MediaType) != nil && updates[i].MediaType != imgspecv1.MediaTypeImageIndex {
return errors.Wrapf(err, "update %d of %d passed to OCI1Index.UpdateInstances had an unsupported media type (was %q): %q", i+1, len(updates), index.Manifests[i].MediaType, updates[i].MediaType)
}
index.Manifests[i].MediaType = updates[i].MediaType
}
return nil
@@ -75,26 +73,31 @@ func (index *OCI1Index) UpdateInstances(updates []ListUpdate) error {
// ChooseInstance parses blob as an oci v1 manifest index, and returns the digest
// of the image which is appropriate for the current environment.
func (index *OCI1Index) ChooseInstance(ctx *types.SystemContext) (digest.Digest, error) {
wantedArch := runtime.GOARCH
if ctx != nil && ctx.ArchitectureChoice != "" {
wantedArch = ctx.ArchitectureChoice
wantedPlatforms, err := platform.WantedPlatforms(ctx)
if err != nil {
return "", errors.Wrapf(err, "error getting platform information %#v", ctx)
}
wantedOS := runtime.GOOS
if ctx != nil && ctx.OSChoice != "" {
wantedOS = ctx.OSChoice
}
for _, d := range index.Manifests {
if d.Platform != nil && d.Platform.Architecture == wantedArch && d.Platform.OS == wantedOS {
return d.Digest, nil
for _, wantedPlatform := range wantedPlatforms {
for _, d := range index.Manifests {
imagePlatform := imgspecv1.Platform{
Architecture: d.Platform.Architecture,
OS: d.Platform.OS,
OSVersion: d.Platform.OSVersion,
OSFeatures: dupStringSlice(d.Platform.OSFeatures),
Variant: d.Platform.Variant,
}
if platform.MatchesPlatform(imagePlatform, wantedPlatform) {
return d.Digest, nil
}
}
}
for _, d := range index.Manifests {
if d.Platform == nil {
return d.Digest, nil
}
}
return "", fmt.Errorf("no image found in image index for architecture %s, OS %s", wantedArch, wantedOS)
return "", fmt.Errorf("no image found in image index for architecture %s, variant %s, OS %s", wantedPlatforms[0].Architecture, wantedPlatforms[0].Variant, wantedPlatforms[0].OS)
}
// Serialize returns the index in a blob format.

View File

@@ -16,12 +16,12 @@ import (
"strings"
"time"
"github.com/containers/storage/pkg/homedir"
"github.com/ghodss/yaml"
"github.com/imdario/mergo"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/http2"
"k8s.io/client-go/util/homedir"
)
// restTLSClientConfig is a modified copy of k8s.io/kubernets/pkg/client/restclient.TLSClientConfig.
@@ -65,7 +65,7 @@ type restConfig struct {
BearerToken string
// TLSClientConfig contains settings to enable transport layer security
restTLSClientConfig
TLSClientConfig restTLSClientConfig
// Server should be accessed without verifying the TLS
// certificate. For testing only.
@@ -90,7 +90,7 @@ func defaultClientConfig() clientConfig {
return clientConfig
}
var recommendedHomeFile = path.Join(homedir.HomeDir(), ".kube/config")
var recommendedHomeFile = path.Join(homedir.Get(), ".kube/config")
// newOpenShiftClientConfigLoadingRules is a modified copy of openshift/origin/pkg/cmd/cli/config.NewOpenShiftClientConfigLoadingRules.
// NewOpenShiftClientConfigLoadingRules returns file priority loading rules for OpenShift.
@@ -238,8 +238,8 @@ func getServerIdentificationPartialConfig(configAuthInfo clientcmdAuthInfo, conf
// configClusterInfo holds the information identify the server provided by .kubeconfig
configClientConfig := &restConfig{}
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
configClientConfig.TLSClientConfig.CAFile = configClusterInfo.CertificateAuthority
configClientConfig.TLSClientConfig.CAData = configClusterInfo.CertificateAuthorityData
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
if err := mergo.MergeWithOverwrite(mergedConfig, configClientConfig); err != nil {
return nil, err
@@ -264,10 +264,10 @@ func getUserIdentificationPartialConfig(configAuthInfo clientcmdAuthInfo) (*rest
mergedConfig.BearerToken = configAuthInfo.Token
}
if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
mergedConfig.CertFile = configAuthInfo.ClientCertificate
mergedConfig.CertData = configAuthInfo.ClientCertificateData
mergedConfig.KeyFile = configAuthInfo.ClientKey
mergedConfig.KeyData = configAuthInfo.ClientKeyData
mergedConfig.TLSClientConfig.CertFile = configAuthInfo.ClientCertificate
mergedConfig.TLSClientConfig.CertData = configAuthInfo.ClientCertificateData
mergedConfig.TLSClientConfig.KeyFile = configAuthInfo.ClientKey
mergedConfig.TLSClientConfig.KeyData = configAuthInfo.ClientKeyData
}
if len(configAuthInfo.Username) > 0 || len(configAuthInfo.Password) > 0 {
mergedConfig.Username = configAuthInfo.Username
@@ -806,8 +806,8 @@ func defaultServerURL(host string, defaultTLS bool) (*url.URL, error) {
func defaultServerURLFor(config *restConfig) (*url.URL, error) {
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
hasCA := len(config.TLSClientConfig.CAFile) != 0 || len(config.TLSClientConfig.CAData) != 0
hasCert := len(config.TLSClientConfig.CertFile) != 0 || len(config.TLSClientConfig.CertData) != 0
defaultTLS := hasCA || hasCert || config.Insecure
host := config.Host
if host == "" {
@@ -968,11 +968,11 @@ func tlsConfigFor(c *restConfig) (*tls.Config, error) {
}
if c.HasCA() {
tlsConfig.RootCAs = rootCertPool(c.CAData)
tlsConfig.RootCAs = rootCertPool(c.TLSClientConfig.CAData)
}
if c.HasCertAuth() {
cert, err := tls.X509KeyPair(c.CertData, c.KeyData)
cert, err := tls.X509KeyPair(c.TLSClientConfig.CertData, c.TLSClientConfig.KeyData)
if err != nil {
return nil, err
}
@@ -988,17 +988,17 @@ func tlsConfigFor(c *restConfig) (*tls.Config, error) {
// either populated or were empty to start.
func loadTLSFiles(c *restConfig) error {
var err error
c.CAData, err = dataFromSliceOrFile(c.CAData, c.CAFile)
c.TLSClientConfig.CAData, err = dataFromSliceOrFile(c.TLSClientConfig.CAData, c.TLSClientConfig.CAFile)
if err != nil {
return err
}
c.CertData, err = dataFromSliceOrFile(c.CertData, c.CertFile)
c.TLSClientConfig.CertData, err = dataFromSliceOrFile(c.TLSClientConfig.CertData, c.TLSClientConfig.CertFile)
if err != nil {
return err
}
c.KeyData, err = dataFromSliceOrFile(c.KeyData, c.KeyFile)
c.TLSClientConfig.KeyData, err = dataFromSliceOrFile(c.TLSClientConfig.KeyData, c.TLSClientConfig.KeyFile)
if err != nil {
return err
}
@@ -1042,13 +1042,13 @@ func rootCertPool(caData []byte) *x509.CertPool {
// HasCA is a modified copy of k8s.io/kubernetes/pkg/client/transport.Config.HasCA.
// HasCA returns whether the configuration has a certificate authority or not.
func (c *restConfig) HasCA() bool {
return len(c.CAData) > 0 || len(c.CAFile) > 0
return len(c.TLSClientConfig.CAData) > 0 || len(c.TLSClientConfig.CAFile) > 0
}
// HasCertAuth is a modified copy of k8s.io/kubernetes/pkg/client/transport.Config.HasCertAuth.
// HasCertAuth returns whether the configuration has certificate authentication or not.
func (c *restConfig) HasCertAuth() bool {
return len(c.CertData) != 0 || len(c.CertFile) != 0
return len(c.TLSClientConfig.CertData) != 0 || len(c.TLSClientConfig.CertFile) != 0
}
// clientcmdConfig is a modified copy of k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api.Config.

View File

@@ -9,9 +9,9 @@ import (
"github.com/containers/image/v5/pkg/blobinfocache/internal/prioritize"
"github.com/containers/image/v5/types"
bolt "github.com/etcd-io/bbolt"
"github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"
)
var (

View File

@@ -18,7 +18,8 @@ import (
)
type dockerAuthConfig struct {
Auth string `json:"auth,omitempty"`
Auth string `json:"auth,omitempty"`
IdentityToken string `json:"identitytoken,omitempty"`
}
type dockerConfigFile struct {
@@ -72,20 +73,23 @@ func SetAuthentication(sys *types.SystemContext, registry, username, password st
})
}
// GetAuthentication returns the registry credentials stored in
// either auth.json file or .docker/config.json
// If an entry is not found empty strings are returned for the username and password
func GetAuthentication(sys *types.SystemContext, registry string) (string, string, error) {
// GetCredentials returns the registry credentials stored in either auth.json
// file or .docker/config.json, including support for OAuth2 and IdentityToken.
// If an entry is not found, an empty struct is returned.
func GetCredentials(sys *types.SystemContext, registry string) (types.DockerAuthConfig, error) {
if sys != nil && sys.DockerAuthConfig != nil {
logrus.Debug("Returning credentials from DockerAuthConfig")
return sys.DockerAuthConfig.Username, sys.DockerAuthConfig.Password, nil
return *sys.DockerAuthConfig, nil
}
if enableKeyring {
username, password, err := getAuthFromKernelKeyring(registry)
if err == nil {
logrus.Debug("returning credentials from kernel keyring")
return username, password, nil
return types.DockerAuthConfig{
Username: username,
Password: password,
}, nil
}
}
@@ -104,18 +108,39 @@ func GetAuthentication(sys *types.SystemContext, registry string) (string, strin
authPath{path: filepath.Join(homedir.Get(), dockerLegacyHomePath), legacyFormat: true})
for _, path := range paths {
username, password, err := findAuthentication(registry, path.path, path.legacyFormat)
authConfig, err := findAuthentication(registry, path.path, path.legacyFormat)
if err != nil {
logrus.Debugf("Credentials not found")
return "", "", err
return types.DockerAuthConfig{}, err
}
if username != "" && password != "" {
if (authConfig.Username != "" && authConfig.Password != "") || authConfig.IdentityToken != "" {
logrus.Debugf("Returning credentials from %s", path.path)
return username, password, nil
return authConfig, nil
}
}
logrus.Debugf("Credentials not found")
return "", "", nil
return types.DockerAuthConfig{}, nil
}
// GetAuthentication returns the registry credentials stored in
// either auth.json file or .docker/config.json
// If an entry is not found empty strings are returned for the username and password
//
// Deprecated: This API only has support for username and password. To get the
// support for oauth2 in docker registry authentication, we added the new
// GetCredentials API. The new API should be used and this API is kept to
// maintain backward compatibility.
func GetAuthentication(sys *types.SystemContext, registry string) (string, string, error) {
auth, err := GetCredentials(sys, registry)
if err != nil {
return "", "", err
}
if auth.IdentityToken != "" {
return "", "", errors.Wrap(ErrNotSupported, "non-empty identity token found and this API doesn't support it")
}
return auth.Username, auth.Password, nil
}
// RemoveAuthentication deletes the credentials stored in auth.json
@@ -294,20 +319,28 @@ func deleteAuthFromCredHelper(credHelper, registry string) error {
}
// findAuthentication looks for auth of registry in path
func findAuthentication(registry, path string, legacyFormat bool) (string, string, error) {
func findAuthentication(registry, path string, legacyFormat bool) (types.DockerAuthConfig, error) {
auths, err := readJSONFile(path, legacyFormat)
if err != nil {
return "", "", errors.Wrapf(err, "error reading JSON file %q", path)
return types.DockerAuthConfig{}, errors.Wrapf(err, "error reading JSON file %q", path)
}
// First try cred helpers. They should always be normalized.
if ch, exists := auths.CredHelpers[registry]; exists {
return getAuthFromCredHelper(ch, registry)
username, password, err := getAuthFromCredHelper(ch, registry)
if err != nil {
return types.DockerAuthConfig{}, err
}
return types.DockerAuthConfig{
Username: username,
Password: password,
}, nil
}
// I'm feeling lucky
if val, exists := auths.AuthConfigs[registry]; exists {
return decodeDockerAuth(val.Auth)
return decodeDockerAuth(val)
}
// bad luck; let's normalize the entries first
@@ -316,25 +349,35 @@ func findAuthentication(registry, path string, legacyFormat bool) (string, strin
for k, v := range auths.AuthConfigs {
normalizedAuths[normalizeRegistry(k)] = v
}
if val, exists := normalizedAuths[registry]; exists {
return decodeDockerAuth(val.Auth)
return decodeDockerAuth(val)
}
return "", "", nil
return types.DockerAuthConfig{}, nil
}
func decodeDockerAuth(s string) (string, string, error) {
decoded, err := base64.StdEncoding.DecodeString(s)
// decodeDockerAuth decodes the username and password, which is
// encoded in base64.
func decodeDockerAuth(conf dockerAuthConfig) (types.DockerAuthConfig, error) {
decoded, err := base64.StdEncoding.DecodeString(conf.Auth)
if err != nil {
return "", "", err
return types.DockerAuthConfig{}, err
}
parts := strings.SplitN(string(decoded), ":", 2)
if len(parts) != 2 {
// if it's invalid just skip, as docker does
return "", "", nil
return types.DockerAuthConfig{}, nil
}
user := parts[0]
password := strings.Trim(parts[1], "\x00")
return user, password, nil
return types.DockerAuthConfig{
Username: user,
Password: password,
IdentityToken: conf.IdentityToken,
}, nil
}
// convertToHostname converts a registry url which has http|https prepended

View File

@@ -2,16 +2,17 @@ package sysregistriesv2
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"sync"
"github.com/BurntSushi/toml"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
"github.com/containers/storage/pkg/homedir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -26,6 +27,16 @@ var systemRegistriesConfPath = builtinRegistriesConfPath
// DO NOT change this, instead see systemRegistriesConfPath above.
const builtinRegistriesConfPath = "/etc/containers/registries.conf"
// systemRegistriesConfDirPath is the path to the system-wide registry
// configuration directory and is used to add/subtract potential registries for
// obtaining images. You can override this at build time with
// -ldflags '-X github.com/containers/image/sysregistries.systemRegistriesConfDirecotyPath=$your_path'
var systemRegistriesConfDirPath = builtinRegistriesConfDirPath
// builtinRegistriesConfDirPath is the path to the registry configuration directory.
// DO NOT change this, instead see systemRegistriesConfDirectoryPath above.
const builtinRegistriesConfDirPath = "/etc/containers/registries.conf.d"
// Endpoint describes a remote location of a registry.
type Endpoint struct {
// The endpoint's remote location.
@@ -35,6 +46,12 @@ type Endpoint struct {
Insecure bool `toml:"insecure,omitempty"`
}
// userRegistriesFile is the path to the per user registry configuration file.
var userRegistriesFile = filepath.FromSlash(".config/containers/registries.conf")
// userRegistriesDir is the path to the per user registry configuration file.
var userRegistriesDir = filepath.FromSlash(".config/containers/registries.conf.d")
// rewriteReference will substitute the provided reference `prefix` to the
// endpoints `location` from the `ref` and creates a new named reference from it.
// The function errors if the newly created reference is not parsable.
@@ -49,7 +66,7 @@ func (e *Endpoint) rewriteReference(ref reference.Named, prefix string) (referen
if err != nil {
return nil, errors.Wrapf(err, "error rewriting reference")
}
logrus.Debugf("reference rewritten from '%v' to '%v'", refString, newParsedRef.String())
return newParsedRef, nil
}
@@ -302,29 +319,83 @@ func (config *V2RegistriesConf) postProcess() error {
config.UnqualifiedSearchRegistries[i] = registry
}
// Registries are ordered and the first longest prefix always wins,
// rendering later items with the same prefix non-existent. We cannot error
// out anymore as this might break existing users, so let's just ignore them
// to guarantee that the same prefix exists only once.
knownPrefixes := make(map[string]bool)
uniqueRegistries := []Registry{}
for i := range config.Registries {
// TODO: should we warn if we see the same prefix being used multiple times?
if _, exists := knownPrefixes[config.Registries[i].Prefix]; !exists {
knownPrefixes[config.Registries[i].Prefix] = true
uniqueRegistries = append(uniqueRegistries, config.Registries[i])
}
}
config.Registries = uniqueRegistries
return nil
}
// ConfigPath returns the path to the system-wide registry configuration file.
func ConfigPath(ctx *types.SystemContext) string {
confPath := systemRegistriesConfPath
if ctx != nil {
if ctx.SystemRegistriesConfPath != "" {
confPath = ctx.SystemRegistriesConfPath
} else if ctx.RootForImplicitAbsolutePaths != "" {
confPath = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfPath)
}
if ctx != nil && ctx.SystemRegistriesConfPath != "" {
return ctx.SystemRegistriesConfPath
}
userRegistriesFilePath := filepath.Join(homedir.Get(), userRegistriesFile)
if _, err := os.Stat(userRegistriesFilePath); err == nil {
return userRegistriesFilePath
}
if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
return filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfPath)
}
return systemRegistriesConfPath
}
// ConfigDirPath returns the path to the system-wide directory for drop-in
// registry configuration files.
func ConfigDirPath(ctx *types.SystemContext) string {
if ctx != nil && ctx.SystemRegistriesConfDirPath != "" {
return ctx.SystemRegistriesConfDirPath
}
userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
if _, err := os.Stat(userRegistriesDirPath); err == nil {
return userRegistriesDirPath
}
if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
return filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfDirPath)
}
return systemRegistriesConfDirPath
}
// configWrapper is used to store the paths from ConfigPath and ConfigDirPath
// and acts as a key to the internal cache.
type configWrapper struct {
configPath string
configDirPath string
}
// newConfigWrapper returns a configWrapper for the specified SystemContext.
func newConfigWrapper(ctx *types.SystemContext) configWrapper {
return configWrapper{
configPath: ConfigPath(ctx),
configDirPath: ConfigDirPath(ctx),
}
return confPath
}
// configMutex is used to synchronize concurrent accesses to configCache.
var configMutex = sync.Mutex{}
// configCache caches already loaded configs with config paths as keys and is
// used to avoid redudantly parsing configs. Concurrent accesses to the cache
// used to avoid redundantly parsing configs. Concurrent accesses to the cache
// are synchronized via configMutex.
var configCache = make(map[string]*V2RegistriesConf)
var configCache = make(map[configWrapper]*V2RegistriesConf)
// InvalidateCache invalidates the registry cache. This function is meant to be
// used for long-running processes that need to reload potential changes made to
@@ -332,66 +403,108 @@ var configCache = make(map[string]*V2RegistriesConf)
func InvalidateCache() {
configMutex.Lock()
defer configMutex.Unlock()
configCache = make(map[string]*V2RegistriesConf)
configCache = make(map[configWrapper]*V2RegistriesConf)
}
// getConfig returns the config object corresponding to ctx, loading it if it is not yet cached.
func getConfig(ctx *types.SystemContext) (*V2RegistriesConf, error) {
configPath := ConfigPath(ctx)
wrapper := newConfigWrapper(ctx)
configMutex.Lock()
// if the config has already been loaded, return the cached registries
if config, inCache := configCache[configPath]; inCache {
if config, inCache := configCache[wrapper]; inCache {
configMutex.Unlock()
return config, nil
}
configMutex.Unlock()
return TryUpdatingCache(ctx)
return tryUpdatingCache(ctx, wrapper)
}
// dropInConfigs returns a slice of drop-in-configs from the registries.conf.d
// directory.
func dropInConfigs(wrapper configWrapper) ([]string, error) {
var configs []string
err := filepath.Walk(wrapper.configDirPath,
// WalkFunc to read additional configs
func(path string, info os.FileInfo, err error) error {
switch {
case err != nil:
// return error (could be a permission problem)
return err
case info == nil:
// this should only happen when err != nil but let's be sure
return nil
case info.IsDir():
if path != wrapper.configDirPath {
// make sure to not recurse into sub-directories
return filepath.SkipDir
}
// ignore directories
return nil
default:
// only add *.conf files
if strings.HasSuffix(path, ".conf") {
configs = append(configs, path)
}
return nil
}
},
)
if err != nil && !os.IsNotExist(err) {
// Ignore IsNotExist errors: most systems won't have a registries.conf.d
// directory.
return nil, errors.Wrapf(err, "error reading registries.conf.d")
}
return configs, nil
}
// TryUpdatingCache loads the configuration from the provided `SystemContext`
// without using the internal cache. On success, the loaded configuration will
// be added into the internal registry cache.
func TryUpdatingCache(ctx *types.SystemContext) (*V2RegistriesConf, error) {
configPath := ConfigPath(ctx)
return tryUpdatingCache(ctx, newConfigWrapper(ctx))
}
// tryUpdatingCache implements TryUpdatingCache with an additional configWrapper
// argument to avoid redundantly calculating the config paths.
func tryUpdatingCache(ctx *types.SystemContext, wrapper configWrapper) (*V2RegistriesConf, error) {
configMutex.Lock()
defer configMutex.Unlock()
// load the config
config, err := loadRegistryConf(configPath)
if err != nil {
// Return an empty []Registry if we use the default config,
// which implies that the config path of the SystemContext
// isn't set. Note: if ctx.SystemRegistriesConfPath points to
// the default config, we will still return an error.
config := &tomlConfig{}
if err := config.loadConfig(wrapper.configPath, false); err != nil {
// Continue with an empty []Registry if we use the default config, which
// implies that the config path of the SystemContext isn't set.
//
// Note: if ctx.SystemRegistriesConfPath points to the default config,
// we will still return an error.
if os.IsNotExist(err) && (ctx == nil || ctx.SystemRegistriesConfPath == "") {
return &V2RegistriesConf{Registries: []Registry{}}, nil
config = &tomlConfig{}
config.V2RegistriesConf = V2RegistriesConf{Registries: []Registry{}}
} else {
return nil, errors.Wrapf(err, "error loading registries configuration %q", wrapper.configPath)
}
}
// Load the configs from the conf directory path.
dinConfigs, err := dropInConfigs(wrapper)
if err != nil {
return nil, err
}
for _, path := range dinConfigs {
// Enforce v2 format for drop-in-configs.
if err := config.loadConfig(path, true); err != nil {
return nil, errors.Wrapf(err, "error loading drop-in registries configuration %q", path)
}
}
v2Config := &config.V2RegistriesConf
// backwards compatibility for v1 configs
if config.V1RegistriesConf.Nonempty() {
if config.V2RegistriesConf.Nonempty() {
return nil, &InvalidRegistries{s: "mixing sysregistry v1/v2 is not supported"}
}
v2, err := config.V1RegistriesConf.ConvertToV2()
if err != nil {
return nil, err
}
v2Config = v2
}
if err := v2Config.postProcess(); err != nil {
return nil, err
}
// populate the cache
configCache[configPath] = v2Config
configCache[wrapper] = v2Config
return v2Config, nil
}
@@ -470,16 +583,72 @@ func FindRegistry(ctx *types.SystemContext, ref string) (*Registry, error) {
return nil, nil
}
// Loads the registry configuration file from the filesystem and then unmarshals
// it. Returns the unmarshalled object.
func loadRegistryConf(configPath string) (*tomlConfig, error) {
config := &tomlConfig{}
// loadConfig loads and unmarshals the configuration at the specified path. Note
// that v1 configs are translated into v2 and are cleared. Use forceV2 if the
// config must in the v2 format.
//
// Note that specified fields in path will replace already set fields in the
// tomlConfig. Only the [[registry]] tables are merged by prefix.
func (c *tomlConfig) loadConfig(path string, forceV2 bool) error {
logrus.Debugf("Loading registries configuration %q", path)
configBytes, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, err
// Save the registries before decoding the file where they could be lost.
// We merge them later again.
registryMap := make(map[string]Registry)
for i := range c.Registries {
registryMap[c.Registries[i].Prefix] = c.Registries[i]
}
err = toml.Unmarshal(configBytes, &config)
return config, err
// Load the tomlConfig. Note that `DecodeFile` will overwrite set fields.
c.Registries = nil // important to clear the memory to prevent us from overlapping fields
_, err := toml.DecodeFile(path, c)
if err != nil {
return err
}
if c.V1RegistriesConf.Nonempty() {
// Enforce the v2 format if requested.
if forceV2 {
return &InvalidRegistries{s: "registry must be in v2 format but is in v1"}
}
// Convert a v1 config into a v2 config.
if c.V2RegistriesConf.Nonempty() {
return &InvalidRegistries{s: "mixing sysregistry v1/v2 is not supported"}
}
v2, err := c.V1RegistriesConf.ConvertToV2()
if err != nil {
return err
}
c.V1RegistriesConf = V1RegistriesConf{}
c.V2RegistriesConf = *v2
}
// Post process registries, set the correct prefixes, sanity checks, etc.
if err := c.postProcess(); err != nil {
return err
}
// Merge the freshly loaded registries.
for i := range c.Registries {
registryMap[c.Registries[i].Prefix] = c.Registries[i]
}
// Go maps have a non-deterministic order when iterating the keys, so
// we dump them in a slice and sort it to enforce some order in
// Registries slice. Some consumers of c/image (e.g., CRI-O) log the
// the configuration where a non-deterministic order could easily cause
// confusion.
prefixes := []string{}
for prefix := range registryMap {
prefixes = append(prefixes, prefix)
}
sort.Strings(prefixes)
c.Registries = []Registry{}
for _, prefix := range prefixes {
c.Registries = append(c.Registries, registryMap[prefix])
}
return nil
}

View File

@@ -30,6 +30,14 @@ func newReference(transport storageTransport, named reference.Named, id string)
if named == nil && id == "" {
return nil, ErrInvalidReference
}
if named != nil && reference.IsNameOnly(named) {
return nil, errors.Wrapf(ErrInvalidReference, "reference %s has neither a tag nor a digest", named.String())
}
if id != "" {
if err := validateImageID(id); err != nil {
return nil, errors.Wrapf(ErrInvalidReference, "invalid ID value %q: %v", id, err)
}
}
// We take a copy of the transport, which contains a pointer to the
// store that it used for resolving this reference, so that the
// transport that we'll return from Transport() won't be affected by

View File

@@ -43,6 +43,8 @@ type StoreTransport interface {
types.ImageTransport
// SetStore sets the default store for this transport.
SetStore(storage.Store)
// GetStoreIfSet returns the default store for this transport, or nil if not set/determined yet.
GetStoreIfSet() storage.Store
// GetImage retrieves the image from the transport's store that's named
// by the reference.
GetImage(types.ImageReference) (*storage.Image, error)
@@ -52,6 +54,9 @@ type StoreTransport interface {
// ParseStoreReference parses a reference, overriding any store
// specification that it may contain.
ParseStoreReference(store storage.Store, reference string) (*storageReference, error)
// NewStoreReference creates a reference for (named@ID) in store.
// either of name or ID can be unset; named must not be a reference.IsNameOnly.
NewStoreReference(store storage.Store, named reference.Named, id string) (*storageReference, error)
// SetDefaultUIDMap sets the default UID map to use when opening stores.
SetDefaultUIDMap(idmap []idtools.IDMap)
// SetDefaultGIDMap sets the default GID map to use when opening stores.
@@ -82,6 +87,11 @@ func (s *storageTransport) SetStore(store storage.Store) {
s.store = store
}
// GetStoreIfSet returns the default store for this transport, as set using SetStore() or initialized by default, or nil if not set/determined yet.
func (s *storageTransport) GetStoreIfSet() storage.Store {
return s.store
}
// SetDefaultUIDMap sets the default UID map to use when opening stores.
func (s *storageTransport) SetDefaultUIDMap(idmap []idtools.IDMap) {
s.defaultUIDMap = idmap
@@ -129,7 +139,7 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
// If it looks like a digest, leave it alone for now.
if _, err := digest.Parse(possibleID); err != nil {
// Otherwise…
if idSum, err := digest.Parse("sha256:" + possibleID); err == nil && idSum.Validate() == nil {
if err := validateImageID(possibleID); err == nil {
id = possibleID // … it is a full ID
} else if img, err := store.Image(possibleID); err == nil && img != nil && len(possibleID) >= minimumTruncatedIDLength && strings.HasPrefix(img.ID, possibleID) {
// … it is a truncated version of the ID of an image that's present in local storage,
@@ -167,7 +177,7 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
named = reference.TagNameOnly(named)
}
result, err := newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, named, id)
result, err := s.NewStoreReference(store, named, id)
if err != nil {
return nil, err
}
@@ -175,6 +185,12 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
return result, nil
}
// NewStoreReference creates a reference for (named@ID) in store.
// either of name or ID can be unset; named must not be a reference.IsNameOnly.
func (s *storageTransport) NewStoreReference(store storage.Store, named reference.Named, id string) (*storageReference, error) {
return newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, named, id)
}
func (s *storageTransport) GetStore() (storage.Store, error) {
// Return the transport's previously-set store. If we don't have one
// of those, initialize one now.
@@ -342,7 +358,7 @@ func (s storageTransport) ValidatePolicyConfigurationScope(scope string) error {
switch len(fields) {
case 1: // name only
case 2: // name:tag@ID or name[:tag]@digest
if _, idErr := digest.Parse("sha256:" + fields[1]); idErr != nil {
if idErr := validateImageID(fields[1]); idErr != nil {
if _, digestErr := digest.Parse(fields[1]); digestErr != nil {
return fmt.Errorf("%v is neither a valid digest(%s) nor a valid ID(%s)", fields[1], digestErr.Error(), idErr.Error())
}
@@ -351,7 +367,7 @@ func (s storageTransport) ValidatePolicyConfigurationScope(scope string) error {
if _, err := digest.Parse(fields[1]); err != nil {
return err
}
if _, err := digest.Parse("sha256:" + fields[2]); err != nil {
if err := validateImageID(fields[2]); err != nil {
return err
}
default: // Coverage: This should never happen
@@ -363,3 +379,9 @@ func (s storageTransport) ValidatePolicyConfigurationScope(scope string) error {
// are few semantically invalid strings.
return nil
}
// validateImageID returns nil if id is a valid (full) image ID, or an error
func validateImageID(id string) error {
_, err := digest.Parse("sha256:" + id)
return err
}

View File

@@ -22,7 +22,6 @@ type ConfigUpdater interface {
}
type tarballReference struct {
transport types.ImageTransport
config imgspecv1.Image
annotations map[string]string
filenames []string
@@ -43,7 +42,7 @@ func (r *tarballReference) ConfigUpdate(config imgspecv1.Image, annotations map[
}
func (r *tarballReference) Transport() types.ImageTransport {
return r.transport
return Transport
}
func (r *tarballReference) StringWithinTransport() string {

View File

@@ -48,12 +48,21 @@ func (t *tarballTransport) ParseReference(reference string) (types.ImageReferenc
}
f.Close()
}
ref := &tarballReference{
transport: t,
filenames: filenames,
stdin: stdin,
return NewReference(filenames, stdin)
}
// NewReference creates a new "tarball:" reference for the listed fileNames.
// If any of the fileNames is "-", the contents of stdin are used instead.
func NewReference(fileNames []string, stdin []byte) (types.ImageReference, error) {
for _, path := range fileNames {
if strings.Contains(path, separator) {
return nil, fmt.Errorf("Invalid path %q: paths including the separator %q are not supported", path, separator)
}
}
return ref, nil
return &tarballReference{
filenames: fileNames,
stdin: stdin,
}, nil
}
func (t *tarballTransport) ValidatePolicyConfigurationScope(scope string) error {

View File

@@ -399,6 +399,10 @@ type Image interface {
// This does not change the state of the original Image object.
UpdatedImage(ctx context.Context, options ManifestUpdateOptions) (Image, error)
// SupportsEncryption returns an indicator that the image supports encryption
//
// Deprecated: Initially used to determine if a manifest can be copied from a source manifest type since
// the process of updating a manifest between different manifest types was to update then convert.
// This resulted in some fields in the update being lost. This has been fixed by: https://github.com/containers/image/pull/836
SupportsEncryption(ctx context.Context) bool
// Size returns an approximation of the amount of disk space which is consumed by the image in its current
// location. If the size is not known, -1 will be returned.
@@ -440,6 +444,7 @@ type ImageInspectInfo struct {
DockerVersion string
Labels map[string]string
Architecture string
Variant string
Os string
Layers []string
Env []string
@@ -450,6 +455,11 @@ type ImageInspectInfo struct {
type DockerAuthConfig struct {
Username string
Password string
// IdentityToken can be used as an refresh_token in place of username and
// password to obtain the bearer/access token in oauth2 flow. If identity
// token is set, password should not be set.
// Ref: https://docs.docker.com/registry/spec/auth/oauth/
IdentityToken string
}
// OptionalBool is a boolean with an additional undefined value, which is meant
@@ -497,6 +507,8 @@ type SystemContext struct {
RegistriesDirPath string
// Path to the system-wide registries configuration file
SystemRegistriesConfPath string
// Path to the system-wide registries configuration directory
SystemRegistriesConfDirPath string
// If not "", overrides the default path for the authentication file, but only new format files
AuthFilePath string
// if not "", overrides the default path for the authentication file, but with the legacy format;
@@ -510,6 +522,8 @@ type SystemContext struct {
ArchitectureChoice string
// If not "", overrides the use of platform.GOOS when choosing an image or verifying OS match.
OSChoice string
// If not "", overrides the use of detected ARM platform variant when choosing an image or verifying variant match.
VariantChoice string
// If not "", overrides the system's default directory containing a blob info cache.
BlobInfoCacheDir string
// Additional tags when creating or copying a docker-archive.
@@ -540,7 +554,10 @@ type SystemContext struct {
// Allow contacting docker registries over HTTP, or HTTPS with failed TLS verification. Note that this does not affect other TLS connections.
DockerInsecureSkipTLSVerify OptionalBool
// if nil, the library tries to parse ~/.docker/config.json to retrieve credentials
// Ignored if DockerBearerRegistryToken is non-empty.
DockerAuthConfig *DockerAuthConfig
// if not "", the library uses this registry token to authenticate to the registry
DockerBearerRegistryToken string
// if not "", an User-Agent header is added to each request when contacting a registry.
DockerRegistryUserAgent string
// if true, a V1 ping attempt isn't done to give users a better error. Default is false.

View File

@@ -6,9 +6,9 @@ const (
// VersionMajor is for an API incompatible changes
VersionMajor = 5
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 2
VersionMinor = 4
// VersionPatch is for backwards-compatible bug fixes
VersionPatch = 1
VersionPatch = 3
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""

View File

@@ -0,0 +1,3 @@
## The OCIcrypt Library Project Community Code of Conduct
The OCIcrypt Library project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).

View File

@@ -1,6 +1,7 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -175,24 +176,11 @@
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://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,

View File

@@ -2,6 +2,13 @@
The `ocicrypt` library is the OCI image spec implementation of container image encryption. More details of the spec can be seen in the [OCI repository](https://github.com/opencontainers/image-spec/pull/775). The purpose of this library is to encode spec structures and consts in code, as well as provide a consistent implementation of image encryption across container runtimes and build tools.
Consumers of OCIcrypt:
- [containerd/imgcrypt](https://github.com/containerd/imgcrypt)
- [cri-o](https://github.com/cri-o/cri-o)
- [skopeo](https://github.com/containers/skopeo)
## Usage
There are various levels of usage for this library. The main consumers of these would be runtime/buil tools, and a more specific use would be in the ability to extend cryptographic function.

View File

@@ -196,10 +196,13 @@ func decryptLayerKeyOptsData(dc *config.DecryptConfig, desc ocispec.Descriptor)
if b64Annotation != "" {
keywrapper := GetKeyWrapper(scheme)
if len(keywrapper.GetPrivateKeys(dc.Parameters)) == 0 {
if keywrapper.NoPossibleKeys(dc.Parameters) {
continue
}
privKeyGiven = true
if len(keywrapper.GetPrivateKeys(dc.Parameters)) > 0 {
privKeyGiven = true
}
optsData, err := preUnwrapKey(keywrapper, dc, b64Annotation)
if err != nil {

View File

@@ -10,7 +10,6 @@ require (
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/stretchr/testify v1.3.0 // indirect
github.com/urfave/cli v1.22.1
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
google.golang.org/grpc v1.24.0 // indirect
gopkg.in/square/go-jose.v2 v2.3.1

View File

@@ -3,8 +3,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/containerd v1.2.10 h1:liQDhXqIn7y6cJ/7qBgOaZsiTZJc56/wkkhDBiDBRDw=
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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=
@@ -28,10 +26,6 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -39,8 +33,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
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/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -64,10 +56,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,6 +1,7 @@
package helpers
import (
"context"
"fmt"
"io/ioutil"
"os"
@@ -14,7 +15,6 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
// processRecipientKeys sorts the array of recipients by type. Recipients may be either
@@ -147,11 +147,11 @@ func processPrivateKeyFiles(keyFilesAndPwds []string) ([][]byte, [][]byte, [][]b
return gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privkeys, privkeysPasswords, nil
}
func createGPGClient(context *cli.Context) (ocicrypt.GPGClient, error) {
return ocicrypt.NewGPGClient(context.String("gpg-version"), context.String("gpg-homedir"))
func createGPGClient(context context.Context) (ocicrypt.GPGClient, error) {
return ocicrypt.NewGPGClient(context.Value("gpg-version").(string), context.Value("gpg-homedir").(string))
}
func getGPGPrivateKeys(context *cli.Context, gpgSecretKeyRingFiles [][]byte, descs []ocispec.Descriptor, mustFindKey bool) (gpgPrivKeys [][]byte, gpgPrivKeysPwds [][]byte, err error) {
func getGPGPrivateKeys(context context.Context, gpgSecretKeyRingFiles [][]byte, descs []ocispec.Descriptor, mustFindKey bool) (gpgPrivKeys [][]byte, gpgPrivKeysPwds [][]byte, err error) {
gpgClient, err := createGPGClient(context)
if err != nil {
return nil, nil, err

View File

@@ -91,6 +91,10 @@ func (kw *jweKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jweString []byte) (
return nil, errors.New("JWE: No suitable private key found for decryption")
}
func (kw *jweKeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool {
return len(kw.GetPrivateKeys(dcparameters)) == 0
}
func (kw *jweKeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte {
return dcparameters["privkeys"]
}

View File

@@ -26,15 +26,23 @@ type KeyWrapper interface {
WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error)
UnwrapKey(dc *config.DecryptConfig, annotation []byte) ([]byte, error)
GetAnnotationID() string
// NoPossibleKeys returns true if there is no possibility of performing
// decryption for parameters provided.
NoPossibleKeys(dcparameters map[string][][]byte) bool
// GetPrivateKeys (optional) gets the array of private keys. It is an optional implementation
// as in some key services, a private key may not be exportable (i.e. HSM)
// If not implemented, return nil
GetPrivateKeys(dcparameters map[string][][]byte) [][]byte
// GetKeyIdsFromPacket (optional) gets a list of key IDs. This is optional as some encryption
// schemes may not have a notion of key IDs
// If not implemented, return the nil slice
GetKeyIdsFromPacket(packet string) ([]uint64, error)
// GetRecipients (optional) gets a list of recipients. It is optional due to the validity of
// recipients in a particular encryptiong scheme
// If not implemented, return the nil slice
GetRecipients(packet string) ([]string, error)
}

View File

@@ -191,6 +191,10 @@ func (kw *gpgKeyWrapper) GetRecipients(b64pgpPackets string) ([]string, error) {
return array, nil
}
func (kw *gpgKeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool {
return len(kw.GetPrivateKeys(dcparameters)) == 0
}
func (kw *gpgKeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte {
return dcparameters["gpg-privatekeys"]
}

View File

@@ -70,6 +70,10 @@ func collectX509s(x509s [][]byte) ([]*x509.Certificate, error) {
return x509Certs, nil
}
func (kw *pkcs7KeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool {
return len(kw.GetPrivateKeys(dcparameters)) == 0
}
func (kw *pkcs7KeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte {
return dcparameters["privkeys"]
}

View File

@@ -19,7 +19,7 @@ env:
####
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
_BUILT_IMAGE_SUFFIX: "libpod-6228273469587456"
_BUILT_IMAGE_SUFFIX: "libpod-5874660151656448"
FEDORA_CACHE_IMAGE_NAME: "fedora-31-${_BUILT_IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-30-${_BUILT_IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-19-${_BUILT_IMAGE_SUFFIX}"
@@ -50,31 +50,50 @@ gce_instance:
disk: 200
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
testing_task:
depends_on:
- lint
# Not all $TEST_DRIVER combinations are valid for all OS types.
# Note: Nested-variable resolution happens at runtime, not eval. time.
# Use verbose logic for ease of reading/maintaining.
only_if: >-
( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "vfs" ) ||
( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "aufs" ) ||
( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "overlay" ) ||
( $VM_IMAGE =~ '.*UBUNTU.*' && $TEST_DRIVER == "fuse-overlay" ) ||
( $VM_IMAGE =~ '.*FEDORA.*' && $TEST_DRIVER != "aufs" )
allow_failures: $TEST_DRIVER == "devicemapper"
env:
matrix:
VM_IMAGE: "${FEDORA_CACHE_IMAGE_NAME}"
VM_IMAGE: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
VM_IMAGE: "${UBUNTU_CACHE_IMAGE_NAME}"
# VM_IMAGE: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}" # No fuse3 support
matrix: # See ./contrib/cirrus/build_and_test.sh
TEST_DRIVER: "vfs"
TEST_DRIVER: "aufs"
TEST_DRIVER: "overlay"
TEST_DRIVER: "fuse-overlay"
TEST_DRIVER: "devicemapper"
TEST_DRIVER: "fuse-overlay-whiteout"
gce_instance: # Only need to specify differences from defaults (above)
matrix: # Duplicate this task for each matrix product.
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
# image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}" # No fuse3 support
image_name: "${VM_IMAGE}"
# Separate scripts for separate outputs, makes debugging easier.
setup_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}'
build_and_test_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/build_and_test.sh |& ${_TIMESTAMP}'
# Log collection when job was successful
df_script: '${_DFCMD} || true'
rh_audit_log_script: '${_RAUDITCMD} || true'
ubuntu_audit_log_script: '${_UAUDITCMD} || true'
journal_log_script: '${_JOURNALCMD} || true'
on_failure: # Script names must be different from above
failure_df_script: '${_DFCMD} || true'
failure_rh_audit_log_script: '${_RAUDITCMD} || true'
failure_ubuntu_audit_log_script: '${_UAUDITCMD} || true'
failure_journal_log_script: '${_JOURNALCMD} || true'
always:
df_script: '${_DFCMD} || true'
rh_audit_log_script: '${_RAUDITCMD} || true'
ubuntu_audit_log_script: '${_UAUDITCMD} || true'
journal_log_script: '${_JOURNALCMD} || true'
lint_task:
env:
@@ -94,7 +113,7 @@ lint_task:
meta_task:
container:
image: "quay.io/libpod/imgts:latest" # see contrib/imgts
image: "quay.io/libpod/imgts:master"
cpu: 1
memory: 1

View File

@@ -1,62 +0,0 @@
---
sudo: required
# N/B: host go env. not actually used, see .run_ci_tests.sh
language: go
go:
- master
services:
- docker
env:
# Ubuntu
- GO_VERSION="stable"
DISTRO="ubuntu"
- GO_VERSION="1.12.12"
DISTRO="ubuntu"
# Fedora
- GO_VERSION="stable"
DISTRO="fedora"
- GO_VERSION="1.12.12"
DISTRO="fedora"
# CentOS
- GO_VERSION="stable"
DISTRO="centos"
- GO_VERSION="1.12.12"
DISTRO="centos"
# GO_VERSION="stable" builds successfully, but tests fail on all platforms.
# Run the tests, but ignore the result (for now)
matrix:
allow_failures:
- env: GO_VERSION="stable" DISTRO="ubuntu"
- env: GO_VERSION="stable" DISTRO="fedora"
- env: GO_VERSION="stable" DISTRO="centos"
before_install:
- sudo apt-get -qq update
- sudo apt-get -qq install realpath
script:
- echo "Travis/host environment:"
- export TRAVIS_ENV="-e TRAVIS=$TRAVIS
-e CI=$CI
-e TRAVIS_COMMIT=$TRAVIS_COMMIT
-e TRAVIS_COMMIT_RANGE=$TRAVIS_COMMIT_RANGE
-e TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG
-e TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST
-e TRAVIS_PULL_REQUEST_SHA=$TRAVIS_PULL_REQUEST_SHA
-e TRAVIS_PULL_REQUEST_SLUG=$TRAVIS_PULL_REQUEST_SLUG
-e TRAVIS_BRANCH=$TRAVIS_BRANCH
-e TRAVIS_JOB_ID=$TRAVIS_JOB_ID
-e TRAVIS_BUILD_DIR=$TRAVIS_BUILD_DIR"
- env
- echo "Running tests in SPC using ./hack/run_ci_tests.sh"
- ./hack/run_ci_tests.sh

View File

@@ -0,0 +1,3 @@
## The Containers Storage Project Community Code of Conduct
The Containers Storage project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).

View File

@@ -54,19 +54,19 @@ sources := $(wildcard *.go cmd/containers-storage/*.go drivers/*.go drivers/*/*.
containers-storage: $(sources) ## build using gc on the host
$(GO_BUILD) -compiler gc $(BUILDFLAGS) ./cmd/containers-storage
layers_ffjson.go: layers.go
layers_ffjson.go: $(FFJSON) layers.go
$(RM) $@
$(FFJSON) layers.go
images_ffjson.go: images.go
images_ffjson.go: $(FFJSON) images.go
$(RM) $@
$(FFJSON) images.go
containers_ffjson.go: containers.go
containers_ffjson.go: $(FFJSON) containers.go
$(RM) $@
$(FFJSON) containers.go
pkg/archive/archive_ffjson.go: pkg/archive/archive.go
pkg/archive/archive_ffjson.go: $(FFJSON) pkg/archive/archive.go
$(RM) $@
$(FFJSON) pkg/archive/archive.go
@@ -118,6 +118,9 @@ validate: ## validate DCO, gofmt, ./pkg/ isolation, golint,\ngo vet and vendor u
install.tools:
make -C tests/tools
$(FFJSON):
make -C tests/tools build/ffjson
install.docs: docs
make -C docs install

View File

@@ -1 +1 @@
1.15.8
1.18.2

View File

@@ -5,10 +5,10 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/selinux/pkg/pwalk"
)
const (
@@ -51,16 +51,13 @@ func chownByMapsMain() {
if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 {
toHost = nil
}
chown := func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error walking to %q: %v", path, err)
}
chown := func(path string, info os.FileInfo, _ error) error {
if path == "." {
return nil
}
return platformLChown(path, info, toHost, toContainer)
}
if err := filepath.Walk(".", chown); err != nil {
if err := pwalk.Walk(".", chown); err != nil {
fmt.Fprintf(os.Stderr, "error during chown: %v", err)
os.Exit(1)
}

View File

@@ -12,66 +12,63 @@ import (
)
func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
sysinfo := info.Sys()
if st, ok := sysinfo.(*syscall.Stat_t); ok {
// Map an on-disk UID/GID pair from host to container
// using the first map, then back to the host using the
// second map. Skip that first step if they're 0, to
// compensate for cases where a parent layer should
// have had a mapped value, but didn't.
uid, gid := int(st.Uid), int(st.Gid)
if toContainer != nil {
pair := idtools.IDPair{
UID: uid,
GID: gid,
}
mappedUID, mappedGID, err := toContainer.ToContainer(pair)
if err != nil {
if (uid != 0) || (gid != 0) {
return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
}
mappedUID, mappedGID = uid, gid
}
uid, gid = mappedUID, mappedGID
st, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return nil
}
// Map an on-disk UID/GID pair from host to container
// using the first map, then back to the host using the
// second map. Skip that first step if they're 0, to
// compensate for cases where a parent layer should
// have had a mapped value, but didn't.
uid, gid := int(st.Uid), int(st.Gid)
if toContainer != nil {
pair := idtools.IDPair{
UID: uid,
GID: gid,
}
if toHost != nil {
pair := idtools.IDPair{
UID: uid,
GID: gid,
mappedUID, mappedGID, err := toContainer.ToContainer(pair)
if err != nil {
if (uid != 0) || (gid != 0) {
return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
}
mappedPair, err := toHost.ToHost(pair)
if err != nil {
return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
}
uid, gid = mappedPair.UID, mappedPair.GID
mappedUID, mappedGID = uid, gid
}
uid, gid = mappedUID, mappedGID
}
if toHost != nil {
pair := idtools.IDPair{
UID: uid,
GID: gid,
}
mappedPair, err := toHost.ToHost(pair)
if err != nil {
return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
}
uid, gid = mappedPair.UID, mappedPair.GID
}
if uid != int(st.Uid) || gid != int(st.Gid) {
cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && err != system.ErrNotSupportedPlatform {
return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
}
if uid != int(st.Uid) || gid != int(st.Gid) {
stat, err := os.Lstat(path)
if err != nil {
return fmt.Errorf("%s: lstat(%q): %v", os.Args[0], path, err)
}
cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && err != system.ErrNotSupportedPlatform {
return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
}
// Make the change.
if err := syscall.Lchown(path, uid, gid); err != nil {
return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
}
// Restore the SUID and SGID bits if they were originally set.
if (stat.Mode()&os.ModeSymlink == 0) && stat.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
if err := os.Chmod(path, stat.Mode()); err != nil {
return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
}
}
if cap != nil {
if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
}
}
// Make the change.
if err := syscall.Lchown(path, uid, gid); err != nil {
return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
}
// Restore the SUID and SGID bits if they were originally set.
if (info.Mode()&os.ModeSymlink == 0) && info.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
if err := os.Chmod(path, info.Mode()); err != nil {
return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
}
}
if cap != nil {
if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
}
}
}
return nil
}

View File

@@ -1209,7 +1209,7 @@ func (devices *DeviceSet) growFS(info *devInfo) error {
options = joinMountOptions(options, devices.mountOptions)
if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s\n%v", info.DevName(), fsMountPoint, err, string(dmesg.Dmesg(256)))
return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
}
defer unix.Unmount(fsMountPoint, unix.MNT_DETACH)
@@ -2414,7 +2414,7 @@ func (devices *DeviceSet) MountDevice(hash, path string, moptions graphdriver.Mo
options = joinMountOptions(options, label.FormatMountLabel("", moptions.MountLabel))
if err := mount.Mount(info.DevName(), path, fstype, options); err != nil {
return fmt.Errorf("devmapper: Error mounting '%s' on '%s': %s\n%v", info.DevName(), path, err, string(dmesg.Dmesg(256)))
return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
}
if fstype == xfs && devices.xfsNospaceRetries != "" {

View File

@@ -2,29 +2,27 @@ module github.com/containers/storage
require (
github.com/BurntSushi/toml v0.3.1
github.com/DataDog/zstd v1.4.0 // indirect
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5
github.com/Microsoft/hcsshim v0.8.7
github.com/docker/docker v0.0.0-20171019062838-86f080cff091 // indirect
github.com/docker/go-units v0.4.0
github.com/klauspost/compress v1.9.8
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/klauspost/pgzip v1.2.1
github.com/mattn/go-shellwords v1.0.9
github.com/hashicorp/go-multierror v1.0.0
github.com/klauspost/compress v1.10.3
github.com/klauspost/pgzip v1.2.3
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/selinux v1.3.1
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700
github.com/opencontainers/selinux v1.4.0
github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.4.2
github.com/spf13/pflag v1.0.3 // indirect
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.5.1
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/tchap/go-patricia v2.3.0+incompatible
github.com/vbatts/tar-split v0.11.1
golang.org/x/net v0.0.0-20190628185345-da137c7871d7
golang.org/x/sys v0.0.0-20191115151921-52ab43148777
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2
gotest.tools v2.2.0+incompatible
)

View File

@@ -1,127 +1,94 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/zstd v1.4.0 h1:vhoV+DUHnRZdKW1i5UMjAk2G4JY8wN4ayRfYDNdEhwo=
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b h1:T4nWG1TXIxeor8mAu5bFguPJgSIGhZqv/f0z55KCrJM=
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50 h1:WMpHmC6AxwWb9hMqhudkqG7A/p14KiMnl6d3r1iUMjU=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containers/common v0.5.0 h1:ZAef7h3oO46PcbTyfooZf8XLHrYad+GkhSu3EhH6P24=
github.com/containers/common v0.5.0/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
github.com/containers/common v0.6.1 h1:z9VeVXYeOnNV99uNLp7zoE5KO1n0hqz1mdm5a6AiIrA=
github.com/containers/common v0.6.1/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
github.com/containers/storage v1.16.0/go.mod h1:nqN09JSi1/RSI1UAUwDYXPRiGSlq5FPbNkN/xb0TfG0=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/docker v0.0.0-20171019062838-86f080cff091 h1:QpxpTw4MJeOzbC7X00IFxnZhZx8oDOqXMrMAHiwNn54=
github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.7.2 h1:liMOoeIvFpr9kEvalrZ7VVBA4wGf7zfOgwBjzz/5g2Y=
github.com/klauspost/compress v1.7.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.1 h1:TWy0o9J9c6LK9C8t7Msh6IAJNXbsU/nvKLTQUU5HdaY=
github.com/klauspost/compress v1.9.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.3 h1:hkFELABwacUEgBfiguNeQydKv3M9pawBq8o24Ypw9+M=
github.com/klauspost/compress v1.9.3/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA=
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.8 h1:VMAMUUOh+gaxKTMk+zqbjsSjsIcUcL/LF4o63i82QyA=
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/compress v1.10.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0=
github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.2 h1:8d4I0LDiieuGngsqlqOih9ker/NS0LX4V0i+EhiFWg0=
github.com/klauspost/pgzip v1.2.2/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.3 h1:Ce2to9wvs/cuJ2b86/CKQoTYr9VHfpanYosZ0UBJqdw=
github.com/klauspost/pgzip v1.2.3/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9wIsXc=
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.7 h1:KqhVjVZomx2puPACkj9vrGFqnp42Htvo9SEAWePHKOs=
github.com/mattn/go-shellwords v1.0.7/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.9 h1:eaB5JspOwiKKcHdqcjbfe5lA9cNn/4NRRtddXJCimqk=
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM=
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
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=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8 h1:dDCFes8Hj1r/i5qnypONo5jdOme/8HWZC/aNDyhECt0=
github.com/opencontainers/runc v1.0.0-rc8/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1 h1:wY4pOY8fBdSIvs9+IDHC55thBuEulhzfSgKeC1yFvzQ=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 h1:Dliu5QO+4JYWu/yMshaMU7G3JN2POGpwjJN7gjy10Go=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg=
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.3.1 h1:dn2Rc3wTEvTB6iVqoFrKKeMb0uZ38ZheeyMu2h5C1TI=
github.com/opencontainers/selinux v1.3.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/opencontainers/selinux v1.3.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.4.0 h1:cpiX/2wWIju/6My60T6/z9CxNG7c8xTQyEmA9fChpUo=
github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -129,55 +96,42 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 h1:gGBSHPOU7g8YjTbhwn+lvFm2VDEhhA+PwDIlstkgSxE=
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 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/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
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.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -188,41 +142,40 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339 h1:zSqWKgm/o7HAnlAzBQ+aetp9fpuyytsXnKA8eiLHYQM=
golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2 h1:/J2nHFg1MTqaRLFO7M+J78ASNsJoz3r0cvHBPQ77fsE=
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v0.0.0-20190624233834-05ebafbffc79 h1:C+K4iPg1rIvmCf4JjelkbWv2jeWevEwp05Lz8XfTYgE=
gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
// source: ./images.go
// source: images.go
package storage

View File

@@ -281,6 +281,8 @@ func copyLayer(l *Layer) *Layer {
Flags: copyStringInterfaceMap(l.Flags),
UIDMap: copyIDMap(l.UIDMap),
GIDMap: copyIDMap(l.GIDMap),
UIDs: copyUint32Slice(l.UIDs),
GIDs: copyUint32Slice(l.GIDs),
}
}

2156
vendor/github.com/containers/storage/layers_ffjson.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -134,6 +134,18 @@ type OptionsConfig struct {
// should be used to set up default GID mappings.
RemapGroup string `toml:"remap-group"`
// RootAutoUsernsUser is the name of one or more entries in /etc/subuid and
// /etc/subgid which should be used to set up automatically a userns.
RootAutoUsernsUser string `toml:"root-auto-userns-user"`
// AutoUsernsMinSize is the minimum size for a user namespace that is
// created automatically.
AutoUsernsMinSize uint32 `toml:"auto-userns-min-size"`
// AutoUsernsMaxSize is the maximum size for a user namespace that is
// created automatically.
AutoUsernsMaxSize uint32 `toml:"auto-userns-max-size"`
// Aufs container options to be handed to aufs drivers
Aufs struct{ AufsOptionsConfig } `toml:"aufs"`

View File

@@ -1,7 +1,6 @@
package fileutils
import (
"errors"
"fmt"
"io"
"os"
@@ -10,6 +9,7 @@ import (
"strings"
"text/scanner"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -358,6 +358,21 @@ func ReadSymlinkedDirectory(path string) (string, error) {
return realPath, nil
}
// ReadSymlinkedPath returns the target directory of a symlink.
// The target of the symbolic link can be a file and a directory.
func ReadSymlinkedPath(path string) (realPath string, err error) {
if realPath, err = filepath.Abs(path); err != nil {
return "", errors.Wrapf(err, "unable to get absolute path for %q", path)
}
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
return "", errors.Wrapf(err, "failed to canonicalise path for %q", path)
}
if _, err := os.Stat(realPath); err != nil {
return "", errors.Wrapf(err, "failed to stat target %q of %q", realPath, path)
}
return realPath, nil
}
// CreateIfNotExists creates a file or a directory only if it does not already exist.
func CreateIfNotExists(path string, isDir bool) error {
if _, err := os.Stat(path); err != nil {

View File

@@ -1,23 +1,96 @@
// +build linux
package homedir
import (
"os"
// Copyright 2013-2018 Docker, Inc.
// NOTE: this package has originally been copied from github.com/docker/docker.
"github.com/containers/storage/pkg/idtools"
import (
"errors"
"os"
"path/filepath"
"strings"
)
// GetStatic returns the home directory for the current user without calling
// os/user.Current(). This is useful for static-linked binary on glibc-based
// system, because a call to os/user.Current() in a static binary leads to
// segfault due to a glibc issue that won't be fixed in a short term.
// (#29344, golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341)
func GetStatic() (string, error) {
uid := os.Getuid()
usr, err := idtools.LookupUID(uid)
if err != nil {
return "", err
// GetRuntimeDir returns XDG_RUNTIME_DIR.
// XDG_RUNTIME_DIR is typically configured via pam_systemd.
// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func GetRuntimeDir() (string, error) {
if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
return xdgRuntimeDir, nil
}
return usr.Home, nil
return "", errors.New("could not get XDG_RUNTIME_DIR")
}
// StickRuntimeDirContents sets the sticky bit on files that are under
// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
//
// StickyRuntimeDir returns slice of sticked files.
// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func StickRuntimeDirContents(files []string) ([]string, error) {
runtimeDir, err := GetRuntimeDir()
if err != nil {
// ignore error if runtimeDir is empty
return nil, nil
}
runtimeDir, err = filepath.Abs(runtimeDir)
if err != nil {
return nil, err
}
var sticked []string
for _, f := range files {
f, err = filepath.Abs(f)
if err != nil {
return sticked, err
}
if strings.HasPrefix(f, runtimeDir+"/") {
if err = stick(f); err != nil {
return sticked, err
}
sticked = append(sticked, f)
}
}
return sticked, nil
}
func stick(f string) error {
st, err := os.Stat(f)
if err != nil {
return err
}
m := st.Mode()
m |= os.ModeSticky
return os.Chmod(f, m)
}
// GetDataHome returns XDG_DATA_HOME.
// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func GetDataHome() (string, error) {
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
return xdgDataHome, nil
}
home := os.Getenv("HOME")
if home == "" {
return "", errors.New("could not get either XDG_DATA_HOME or HOME")
}
return filepath.Join(home, ".local", "share"), nil
}
// GetConfigHome returns XDG_CONFIG_HOME.
// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func GetConfigHome() (string, error) {
if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
return xdgConfigHome, nil
}
home := os.Getenv("HOME")
if home == "" {
return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
}
return filepath.Join(home, ".config"), nil
}

View File

@@ -2,12 +2,29 @@
package homedir
// Copyright 2013-2018 Docker, Inc.
// NOTE: this package has originally been copied from github.com/docker/docker.
import (
"errors"
)
// GetStatic is not needed for non-linux systems.
// (Precisely, it is needed only for glibc-based linux systems.)
func GetStatic() (string, error) {
return "", errors.New("homedir.GetStatic() is not supported on this system")
// GetRuntimeDir is unsupported on non-linux system.
func GetRuntimeDir() (string, error) {
return "", errors.New("homedir.GetRuntimeDir() is not supported on this system")
}
// StickRuntimeDirContents is unsupported on non-linux system.
func StickRuntimeDirContents(files []string) ([]string, error) {
return nil, errors.New("homedir.StickRuntimeDirContents() is not supported on this system")
}
// GetDataHome is unsupported on non-linux system.
func GetDataHome() (string, error) {
return "", errors.New("homedir.GetDataHome() is not supported on this system")
}
// GetConfigHome is unsupported on non-linux system.
func GetConfigHome() (string, error) {
return "", errors.New("homedir.GetConfigHome() is not supported on this system")
}

View File

@@ -2,10 +2,12 @@
package homedir
// Copyright 2013-2018 Docker, Inc.
// NOTE: this package has originally been copied from github.com/docker/docker.
import (
"os"
"github.com/opencontainers/runc/libcontainer/user"
"os/user"
)
// Key returns the env var name for the user's home dir based on
@@ -17,11 +19,16 @@ func Key() string {
// Get returns the home directory of the current user with the help of
// environment variables depending on the target operating system.
// Returned path should be used with "path/filepath" to form new paths.
//
// If linking statically with cgo enabled against glibc, ensure the
// osusergo build tag is used.
//
// If needing to do nss lookups, do not disable cgo or set osusergo.
func Get() string {
home := os.Getenv(Key())
if home == "" {
if u, err := user.CurrentUser(); err == nil {
return u.Home
if u, err := user.Current(); err == nil {
return u.HomeDir
}
}
return home

View File

@@ -1,5 +1,8 @@
package homedir
// Copyright 2013-2018 Docker, Inc.
// NOTE: this package has originally been copied from github.com/docker/docker.
import (
"os"
)

View File

@@ -65,7 +65,7 @@ func (w *atomicFileWriter) Close() (retErr error) {
os.Remove(w.f.Name())
}
}()
if err := w.f.Sync(); err != nil {
if err := fdatasync(w.f); err != nil {
w.f.Close()
return err
}
@@ -126,7 +126,7 @@ type syncFileCloser struct {
}
func (w syncFileCloser) Close() error {
err := w.File.Sync()
err := fdatasync(w.File)
if err1 := w.File.Close(); err == nil {
err = err1
}

View File

@@ -0,0 +1,11 @@
package ioutils
import (
"os"
"golang.org/x/sys/unix"
)
func fdatasync(f *os.File) error {
return unix.Fdatasync(int(f.Fd()))
}

View File

@@ -0,0 +1,11 @@
// +build !linux
package ioutils
import (
"os"
)
func fdatasync(f *os.File) error {
return f.Sync()
}

View File

@@ -206,10 +206,6 @@ func (l *lockfile) Touch() error {
if n != len(id) {
return unix.ENOSPC
}
err = unix.Fsync(int(l.fd))
if err != nil {
return err
}
return nil
}

View File

@@ -1,49 +0,0 @@
// +build freebsd,cgo
package mount
/*
#include <sys/mount.h>
*/
import "C"
const (
// RDONLY will mount the filesystem as read-only.
RDONLY = C.MNT_RDONLY
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
// take effect.
NOSUID = C.MNT_NOSUID
// NOEXEC will not allow execution of any binaries on the mounted file system.
NOEXEC = C.MNT_NOEXEC
// SYNCHRONOUS will allow any I/O to the file system to be done synchronously.
SYNCHRONOUS = C.MNT_SYNCHRONOUS
// NOATIME will not update the file access time when reading from a file.
NOATIME = C.MNT_NOATIME
)
// These flags are unsupported.
const (
BIND = 0
DIRSYNC = 0
MANDLOCK = 0
NODEV = 0
NODIRATIME = 0
UNBINDABLE = 0
RUNBINDABLE = 0
PRIVATE = 0
RPRIVATE = 0
SHARED = 0
RSHARED = 0
SLAVE = 0
RSLAVE = 0
RBIND = 0
RELATIVE = 0
RELATIME = 0
REMOUNT = 0
STRICTATIME = 0
mntDetach = 0
)

View File

@@ -82,4 +82,6 @@ const (
// it possible for the kernel to default to relatime or noatime but still
// allow userspace to override it.
STRICTATIME = unix.MS_STRICTATIME
mntDetach = unix.MNT_DETACH
)

View File

@@ -1,4 +1,4 @@
// +build !linux,!freebsd freebsd,!cgo solaris,!cgo
// +build !linux
package mount

View File

@@ -2,12 +2,47 @@ package mount
import (
"sort"
"strconv"
"strings"
"time"
"github.com/containers/storage/pkg/fileutils"
)
// mountError holds an error from a mount or unmount operation
type mountError struct {
op string
source, target string
flags uintptr
data string
err error
}
// Error returns a string representation of mountError
func (e *mountError) Error() string {
out := e.op + " "
if e.source != "" {
out += e.source + ":" + e.target
} else {
out += e.target
}
if e.flags != uintptr(0) {
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
}
if e.data != "" {
out += ", data: " + e.data
}
out += ": " + e.err.Error()
return out
}
// Cause returns the underlying cause of the error
func (e *mountError) Cause() error {
return e.err
}
// GetMounts retrieves a list of mounts for the current running process.
func GetMounts() ([]*Info, error) {
return parseMountTable()
@@ -21,10 +56,11 @@ func Mounted(mountpoint string) (bool, error) {
return false, err
}
mountpoint, err = fileutils.ReadSymlinkedDirectory(mountpoint)
mountpoint, err = fileutils.ReadSymlinkedPath(mountpoint)
if err != nil {
return false, err
}
// Search the table for the mountpoint
for _, e := range entries {
if e.Mountpoint == mountpoint {
@@ -39,13 +75,13 @@ func Mounted(mountpoint string) (bool, error) {
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags.
func Mount(device, target, mType, options string) error {
flag, _ := ParseOptions(options)
flag, data := ParseOptions(options)
if flag&REMOUNT != REMOUNT {
if mounted, err := Mounted(target); err != nil || mounted {
return err
}
}
return ForceMount(device, target, mType, options)
return mount(device, target, mType, uintptr(flag), data)
}
// ForceMount will mount a filesystem according to the specified configuration,
@@ -60,14 +96,11 @@ func ForceMount(device, target, mType, options string) error {
// Unmount lazily unmounts a filesystem on supported platforms, otherwise
// does a normal unmount.
func Unmount(target string) error {
if mounted, err := Mounted(target); err != nil || !mounted {
return err
}
return ForceUnmount(target)
return unmount(target, mntDetach)
}
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first.
// the deepest mount first.
func RecursiveUnmount(target string) error {
mounts, err := GetMounts()
if err != nil {
@@ -75,16 +108,16 @@ func RecursiveUnmount(target string) error {
}
// Make the deepest mount be first
sort.Sort(sort.Reverse(byMountpoint(mounts)))
sort.Slice(mounts, func(i, j int) bool {
return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
})
for i, m := range mounts {
if !strings.HasPrefix(m.Mountpoint, target) {
continue
}
if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 {
if mounted, err := Mounted(m.Mountpoint); err != nil || mounted {
return err
}
return err
// Ignore errors for submounts and continue trying to unmount others
// The final unmount should fail if there ane any submounts remaining
}
@@ -92,15 +125,10 @@ func RecursiveUnmount(target string) error {
return nil
}
// ForceUnmount will force an unmount of the target filesystem, regardless if
// it is mounted or not.
func ForceUnmount(target string) (err error) {
// Simple retry logic for unmount
for i := 0; i < 10; i++ {
if err = unmount(target, 0); err == nil {
return nil
}
time.Sleep(100 * time.Millisecond)
}
return nil
// ForceUnmount lazily unmounts a filesystem on supported platforms,
// otherwise does a normal unmount.
//
// Deprecated: please use Unmount instead, it is identical.
func ForceUnmount(target string) error {
return unmount(target, mntDetach)
}

View File

@@ -14,8 +14,6 @@ import (
"fmt"
"strings"
"unsafe"
"golang.org/x/sys/unix"
)
func allocateIOVecs(options []string) []C.struct_iovec {
@@ -54,7 +52,3 @@ func mount(device, target, mType string, flag uintptr, data string) error {
}
return nil
}
func unmount(target string, flag int) error {
return unix.Unmount(target, flag)
}

View File

@@ -35,25 +35,40 @@ func mount(device, target, mType string, flags uintptr, data string) error {
// Initial call applying all non-propagation flags for mount
// or remount with changed data
if err := unix.Mount(device, target, mType, oflags, data); err != nil {
return err
return &mountError{
op: "mount",
source: device,
target: target,
flags: oflags,
data: data,
err: err,
}
}
}
if flags&ptypes != 0 {
// Change the propagation type.
if err := unix.Mount("", target, "", flags&pflags, ""); err != nil {
return err
return &mountError{
op: "remount",
target: target,
flags: flags & pflags,
err: err,
}
}
}
if oflags&broflags == broflags {
// Remount the bind to apply read only.
return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "")
if err := unix.Mount("", target, "", oflags|unix.MS_REMOUNT, ""); err != nil {
return &mountError{
op: "remount-ro",
target: target,
flags: oflags | unix.MS_REMOUNT,
err: err,
}
}
}
return nil
}
func unmount(target string, flag int) error {
return unix.Unmount(target, flag)
}

View File

@@ -1,34 +0,0 @@
// +build solaris,cgo
package mount
import (
"unsafe"
"golang.org/x/sys/unix"
)
// #include <stdlib.h>
// #include <stdio.h>
// #include <sys/mount.h>
// int Mount(const char *spec, const char *dir, int mflag,
// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) {
// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen);
// }
import "C"
func mount(device, target, mType string, flag uintptr, data string) error {
spec := C.CString(device)
dir := C.CString(target)
fstype := C.CString(mType)
_, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0)
C.free(unsafe.Pointer(spec))
C.free(unsafe.Pointer(dir))
C.free(unsafe.Pointer(fstype))
return err
}
func unmount(target string, flag int) error {
err := unix.Unmount(target, flag)
return err
}

View File

@@ -1,11 +1,7 @@
// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
// +build !linux
package mount
func mount(device, target, mType string, flag uintptr, data string) error {
panic("Not implemented")
}
func unmount(target string, flag int) error {
panic("Not implemented")
}

View File

@@ -38,17 +38,3 @@ type Info struct {
// VfsOpts represents per super block options.
VfsOpts string
}
type byMountpoint []*Info
func (by byMountpoint) Len() int {
return len(by)
}
func (by byMountpoint) Less(i, j int) bool {
return by[i].Mountpoint < by[j].Mountpoint
}
func (by byMountpoint) Swap(i, j int) {
by[i], by[j] = by[j], by[i]
}

View File

@@ -1,5 +1,3 @@
// +build linux
package mount
import (
@@ -7,25 +5,10 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
)
const (
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
(2) parent ID: ID of parent (or of self for the top of the mount tree)
(3) major:minor: value of st_dev for files on filesystem
(4) root: root of the mount within the filesystem
(5) mount point: mount point relative to the process's root
(6) mount options: per mount options
(7) optional fields: zero or more fields of the form "tag[:value]"
(8) separator: marks the end of the optional fields
(9) filesystem type: name of filesystem of the form "type[.subtype]"
(10) mount source: filesystem specific information or "none"
(11) super options: per super block options*/
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
"github.com/pkg/errors"
)
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
@@ -41,43 +24,85 @@ func parseMountTable() ([]*Info, error) {
}
func parseInfoFile(r io.Reader) ([]*Info, error) {
var (
s = bufio.NewScanner(r)
out = []*Info{}
)
s := bufio.NewScanner(r)
out := []*Info{}
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
/*
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(0)(1)(2) (3) (4) (5) (6) (7) (8) (9) (10)
(0) mount ID: unique identifier of the mount (may be reused after umount)
(1) parent ID: ID of parent (or of self for the top of the mount tree)
(2) major:minor: value of st_dev for files on filesystem
(3) root: root of the mount within the filesystem
(4) mount point: mount point relative to the process's root
(5) mount options: per mount options
(6) optional fields: zero or more fields of the form "tag[:value]"
(7) separator: marks the end of the optional fields
(8) filesystem type: name of filesystem of the form "type[.subtype]"
(9) mount source: filesystem specific information or "none"
(10) super options: per super block options
*/
text := s.Text()
fields := strings.Split(text, " ")
numFields := len(fields)
if numFields < 10 {
// should be at least 10 fields
return nil, errors.Errorf("Parsing %q failed: not enough fields (%d)", text, numFields)
}
var (
p = &Info{}
text = s.Text()
optionalFields string
)
if _, err := fmt.Sscanf(text, mountinfoFormat,
&p.ID, &p.Parent, &p.Major, &p.Minor,
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
p := &Info{}
// ignore any number parsing errors, there should not be any
p.ID, _ = strconv.Atoi(fields[0])
p.Parent, _ = strconv.Atoi(fields[1])
mm := strings.Split(fields[2], ":")
if len(mm) != 2 {
return nil, fmt.Errorf("Parsing %q failed: unexpected minor:major pair %s", text, mm)
}
// Safe as mountinfo encodes mountpoints with spaces as \040.
index := strings.Index(text, " - ")
postSeparatorFields := strings.Fields(text[index+3:])
if len(postSeparatorFields) < 3 {
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
p.Major, _ = strconv.Atoi(mm[0])
p.Minor, _ = strconv.Atoi(mm[1])
p.Root = fields[3]
p.Mountpoint = fields[4]
p.Opts = fields[5]
// one or more optional fields, when a separator (-)
i := 6
for ; i < numFields && fields[i] != "-"; i++ {
switch i {
case 6:
p.Optional = string(fields[6])
default:
/* NOTE there might be more optional fields before the separator,
such as fields[7] or fields[8], although as of Linux kernel 5.5
the only known ones are mount propagation flags in fields[6].
The correct behavior is to ignore any unknown optional fields.
*/
}
}
if i == numFields {
return nil, fmt.Errorf("Parsing %q failed: missing - separator", text)
}
if optionalFields != "-" {
p.Optional = optionalFields
// There should be 3 fields after the separator...
if i+4 > numFields {
return nil, fmt.Errorf("Parsing %q failed: not enough fields after a - separator", text)
}
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
// (like "//serv/My Documents") _may_ end up having a space in the last field
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
// option unc= is ignored, so a space should not appear. In here we ignore
// those "extra" fields caused by extra spaces.
p.Fstype = fields[i+1]
p.Source = fields[i+2]
p.VfsOpts = fields[i+3]
p.Fstype = postSeparatorFields[0]
p.Source = postSeparatorFields[1]
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
out = append(out, p)
}
if err := s.Err(); err != nil {
return nil, err
}
return out, nil
}

View File

@@ -1,37 +0,0 @@
// +build solaris,cgo
package mount
/*
#include <stdio.h>
#include <sys/mnttab.h>
*/
import "C"
import (
"fmt"
)
func parseMountTable() ([]*Info, error) {
mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r"))
if mnttab == nil {
return nil, fmt.Errorf("Failed to open %s", C.MNTTAB)
}
var out []*Info
var mp C.struct_mnttab
ret := C.getmntent(mnttab, &mp)
for ret == 0 {
var mountinfo Info
mountinfo.Mountpoint = C.GoString(mp.mnt_mountp)
mountinfo.Source = C.GoString(mp.mnt_special)
mountinfo.Fstype = C.GoString(mp.mnt_fstype)
mountinfo.Opts = C.GoString(mp.mnt_mntopts)
out = append(out, &mountinfo)
ret = C.getmntent(mnttab, &mp)
}
C.fclose(mnttab)
return out, nil
}

View File

@@ -1,4 +1,4 @@
// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
// +build !linux
package mount

View File

@@ -1,6 +0,0 @@
package mount
func parseMountTable() ([]*Info, error) {
// Do NOT return an error!
return nil, nil
}

Some files were not shown because too many files have changed in this diff Show More