Compare commits

...

420 Commits

Author SHA1 Message Date
Colin Walters
723f050465 Merge pull request #2361 from mtrmac/k8s.gcr.io-3
[release-1.3] Refer to registry.k8s.io instead of k8s.gcr.io
2024-06-19 19:41:36 -04:00
Miloslav Trmač
05e6fa25ed Refer to registry.k8s.io instead of k8s.gcr.io
... per https://kubernetes.io/blog/2023/02/06/k8s-gcr-io-freeze-announcement/ .

We are seeing intermittent failures (sufficient to reliably cause a test suite failure)
pulling from k8s.gcr.io, let's see if using the newer one improves things.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-06-19 17:55:01 +02:00
Miloslav Trmač
a0f7bcde83 Merge pull request #2326 from mtrmac/tests-1.3
[release-1.3] Freeze the fedora-minimal image reference at Fedora 38
2024-05-10 13:54:31 +02:00
Miloslav Trmač
8b694b2649 Freeze the fedora-minimal image reference at Fedora 38
... because the tests are assuming a v2s2 image, but
as of Fedora 39, the image uses the OCI format.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
2024-05-10 13:22:59 +02:00
Miloslav Trmač
069208bedc Merge pull request #2183 from mtrmac/release-1.3-docker.io-dependency-backport
[release-1.3] Fix using images from rate-limited docker hub
2023-12-21 18:35:22 +01:00
Chris Evich
623d90afbb Fix using images from rate-limited docker hub
The necessary images have been manually copied over to quay.  Code was
updated with centralized constants for the utilized images.  Tests then
all reference the constants (in case the image locations need to change
again).

Signed-off-by: Chris Evich <cevich@redhat.com>
2023-12-21 18:01:15 +01:00
Miloslav Trmač
0583c8e641 Merge pull request #1989 from cevich/release-1.3_add_self_destruct
[release-1.3] Cirrus: Add CI self-destruct condition on EOL date
2023-05-04 19:06:43 +02:00
Chris Evich
76b7472044 Cirrus: Add CI self-destruct condition on EOL date
This branch will never receive any security-backports when the
associated RHEL release reaches EOL.  Add a condition to force CI to
break with a helpful message, after this RHEL EOL date.

Signed-off-by: Chris Evich <cevich@redhat.com>
2023-05-03 10:53:21 -04:00
Chris Evich
aab0d6da59 Merge pull request #1715 from cevich/release-1.3_latest_imgts
[release-1.3] [CI:DOCS] Cirrus: Use the latest imgts container
2022-07-26 15:55:40 -04:00
Chris Evich
e44bf704dd [CI:DOCS] Cirrus: Use the latest imgts container
Contains important updates re: preserving release-branch CI VM images.
Ref: https://github.com/containers/automation_images/pull/157

Signed-off-by: Chris Evich <cevich@redhat.com>
2022-07-26 15:31:26 -04:00
Miloslav Trmač
e02b7b21b3 Merge pull request #1670 from mtrmac/non-artifact-oci-repo-1.3
[release-1.3] Change a repo used for sync tests
2022-06-10 17:41:36 +02:00
Miloslav Trmač
2c19d55c3f Change a repo used for sync tests
The k8s.gcr.io/coredns/coredns repo now contains an OCI
artifact, which we can't copy; so, use a different
repo to test syncing.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-06-10 16:21:03 +02:00
Daniel J Walsh
f110fb7969 Merge pull request #1574 from mtrmac/inspect-expect-config-1.3
[release-1.3] Don't expect the config blob to be listed in (skopeo inspect)
2022-02-28 07:47:00 -05:00
Miloslav Trmač
2091af3db1 Improve a comment in the 010-inspect.bats test
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-23 22:49:29 +01:00
Miloslav Trmač
32aa9fe647 Only look for the layer digests in the Layers field.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-17 18:34:04 +01:00
Miloslav Trmač
ffee6f7219 Don't expect the config blob to be listed in (skopeo inspect)
... because it currently isn't.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-17 18:33:58 +01:00
Ed Santiago
3761ea6714 Fix bug that prevented useful diagnostics on registry fail
Sigh. 'expr 1 - 1' yields 0 (correctly) but also exits 1. This
is even documented in the man page, but I didn't know it. And
thus, on the final iteration, when timeout reached 0, BATS
errored out on the expr instead of continuing to the 'podman logs'
or the 'die' message.

Solution is super trivial: use $(( ... )) instead of expr.

Signed-off-by: Ed Santiago <santiago@redhat.com>
2021-11-15 09:08:45 -05:00
Chris Evich
8e25f6bbeb Merge pull request #1494 from cevich/fix_skip_cross
Cirrus: Fix only_if error
2021-11-05 11:56:57 -04:00
Chris Evich
59ceb6a5ea Cirrus: Fix only_if error
The logic parser for `only_if` and `skip` is a little weird in that it
wants a boolean, but doesn't support using them.  In this case, using `1
== 0` results in an error from the parser:

`Error while parsing tasks: INVALID_ARGUMENT: internal boolevator error:
parsing error: 1 == 0 :1:1 - 1:2 unexpected Int while scanning
extensions!`

However, since the goal is to block this particular task from running
(essentially) indefinitely, it's easier to just remove it.  We can rely
on git recording it's history in case it needs to be recovered in the
future.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-11-04 12:54:43 -04:00
Daniel J Walsh
78cb493f95 Merge pull request #1450 from cevich/1.3_disable_osx_test
[release-1.3] Cirrus: Disable OSX task
2021-09-20 14:32:30 -04:00
Chris Evich
c5dcc3b7d5 Cirrus: Disable OSX task
Release-branches infrequently change, but the OSX VM images constantly
change.  Disable this test to avoid encountering flakes.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-09-20 11:59:54 -04:00
Miloslav Trmač
038f70e6f5 Merge pull request #1353 from containers/tsweeeny/v1.3.2-dev
[release-1.3] Bump to Skopeo v1.3.2-dev
2021-07-02 14:50:41 +02:00
TomSweeneyRedHat
53b9ccff29 [release-1.3] Bump to Skopeo v1.3.2-dev
Bump the release branch version to the next numbered dev.

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-06-29 18:25:30 -04:00
Tom Sweeney
e9207c4564 Merge pull request #1349 from TomSweeneyRedHat/tsweeney/v1.3.1
[release-1.3] Bump skopeo v1.3.1, c/storage v1.31.3, c/common v0.38.12
2021-06-29 18:15:54 -04:00
TomSweeneyRedHat
f21d940c6e [release-1.3] Bump skopeo v1.3.1, c/storage v1.31.3, c/common v0.38.11
Also includes some tweaks for the CI in this branch.

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-06-29 16:41:43 -04:00
Daniel J Walsh
c35944bec0 Bump to v1.3.0 2021-05-19 17:09:40 -04:00
Daniel J Walsh
266dc3dc9a Merge pull request #1291 from containers/dependabot/go_modules/github.com/containers/common-0.38.3
Bump github.com/containers/common from 0.38.1 to 0.38.4
2021-05-19 17:05:21 -04:00
dependabot[bot]
91d9ccf5e5 Bump github.com/containers/common from 0.38.1 to 0.38.4
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.38.1 to 0.38.4.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.38.1...v0.38.4)

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-05-19 15:55:54 -04:00
Daniel J Walsh
4e57679c9a Merge pull request #1281 from containers/dependabot/go_modules/github.com/containers/common-0.38.1
Bump github.com/containers/common from 0.38.0 to 0.38.1
2021-05-14 04:30:45 -04:00
dependabot[bot]
68f188ae77 Bump github.com/containers/common from 0.38.0 to 0.38.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.38.0 to 0.38.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.38.0...v0.38.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-13 08:17:04 +00:00
Daniel J Walsh
0faf160170 Merge pull request #1280 from containers/dependabot/go_modules/github.com/containers/common-0.38.0
Bump github.com/containers/common from 0.37.1 to 0.38.0
2021-05-10 17:52:49 -04:00
dependabot[bot]
69decaeb1d Bump github.com/containers/common from 0.37.1 to 0.38.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.37.1 to 0.38.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.37.1...v0.38.0)

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-05-10 15:56:42 -04:00
Daniel J Walsh
001775e994 Merge pull request #1278 from accupara/compilation-fix
Add the missing import and a gitignore entry for bin
2021-05-10 14:57:39 -04:00
Yuvraaj Kelkar
fc448c2253 Add the missing import and a gitignore entry for bin 2021-05-09 11:21:01 -07:00
Daniel J Walsh
b10d3e43a4 Merge pull request #1266 from cgwalters/copy-print-digest
copy: Add --digestfile
2021-05-07 05:17:35 -04:00
Colin Walters
a32be320cb copy: Add --digestfile
`podman push` gained this a while ago, and we want it here for the
same reason.

Motivated by closing a race condition in ostree-rs-ext:
17a991050c/lib/src/container/export.rs (L85)

Co-authored-by: Miloslav Trmač <mitr@redhat.com>
2021-05-06 09:19:16 -04:00
Daniel J Walsh
5e13a55444 Merge pull request #1268 from containers/dependabot/go_modules/github.com/containers/storage-1.30.1
Bump github.com/containers/storage from 1.30.0 to 1.30.1
2021-05-06 08:46:20 -04:00
Daniel J Walsh
c0d259712c Merge pull request #1273 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2021-05-06 08:46:01 -04:00
Daniel J Walsh
70abdf7334 Merge pull request #1274 from containers/dependabot/go_modules/github.com/containers/image/v5-5.12.0
Bump github.com/containers/image/v5 from 5.11.1 to 5.12.0
2021-05-06 08:45:44 -04:00
dependabot[bot]
f232ae499b Bump github.com/containers/image/v5 from 5.11.1 to 5.12.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.11.1 to 5.12.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.11.1...v5.12.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-06 09:21:47 +00:00
Wong Hoi Sing Edison
aba84840dc Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-05-06 11:50:50 +08:00
Lokesh Mandvekar
e536c4da34 Merge branch 'master' into dependabot/go_modules/github.com/containers/storage-1.30.1 2021-05-03 10:37:10 -04:00
Valentin Rothberg
a1a8692457 Merge pull request #1270 from containers/dependabot/go_modules/github.com/containers/common-0.37.1
Bump github.com/containers/common from 0.37.0 to 0.37.1
2021-05-03 13:16:45 +02:00
dependabot[bot]
5a594bff65 Bump github.com/containers/common from 0.37.0 to 0.37.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.37.0 to 0.37.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.37.0...v0.37.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-03 10:48:29 +00:00
Valentin Rothberg
2eb35e7af9 Merge pull request #1263 from Freakin/sync-manifest-format
Added format parameter to sync command
2021-05-03 10:25:14 +02:00
Valentin Rothberg
00490a2cbb Merge pull request #1267 from containers/dependabot/add-v2-config-file
Upgrade to GitHub-native Dependabot
2021-05-03 10:19:49 +02:00
Valentin Rothberg
9a10ee2f1f Merge branch 'master' into dependabot/add-v2-config-file 2021-05-03 10:19:14 +02:00
dependabot-preview[bot]
002b2e4db9 Upgrade to GitHub-native Dependabot
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-05-01 06:47:49 -04:00
Daniel J Walsh
891d9750a3 Merge pull request #1269 from cevich/update_f34
Update F34beta -> F34 and U2010 -> U2104
2021-05-01 06:42:22 -04:00
dependabot-preview[bot]
d6912022b5 Bump github.com/containers/storage from 1.30.0 to 1.30.1
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.30.0 to 1.30.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.30.0...v1.30.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-05-01 06:41:32 -04:00
Chris Evich
eab7c4b0d1 Update F34beta -> F34 and U2010 -> U2104
Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-29 11:55:26 -04:00
Brendan Aye
7898ffaf23 Added format parameter to sync command
Signed-off-by: Brendan Aye <brendan.aye@t-mobile.com>
2021-04-28 10:54:21 -07:00
Daniel J Walsh
ce4304a0ad Merge pull request #1258 from containers/dependabot/go_modules/github.com/containers/common-0.37.0
Bump github.com/containers/common from 0.36.0 to 0.37.0
2021-04-28 08:29:18 -04:00
dependabot-preview[bot]
610c612129 Bump github.com/containers/common from 0.36.0 to 0.37.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.36.0 to 0.37.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.36.0...v0.37.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-28 08:00:24 -04:00
Daniel J Walsh
ad9f1d7bb9 Merge pull request #1260 from lsm5/remove-older-distro-docs
Remove older distro docs
2021-04-23 08:08:29 -04:00
Lokesh Mandvekar
37f15d6d11 Remove older distro docs
This commit removes installation steps for older distros:

1. Amazon Linux 2
2. CentOS 7
3. Debian 10
4. Raspbian 10
5. Raspberry Pi OS armhf

We're no longer building new packages for these distros and the
installation steps for older packages are no longer guaranteed to work.
So, these are best removed from the official docs.

Related blog post (also applies to skopeo):
https://podman.io/blogs/2021/03/02/podman-support-for-older-distros.html

Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2021-04-22 14:27:39 -04:00
Valentin Rothberg
2d3f3ed901 Merge pull request #1257 from CharlieTLe/patch-1
Fix typos in docstrings
2021-04-22 07:47:29 +02:00
Charlie Le
65d3890ea1 Fix typos in docstrings 2021-04-21 14:20:04 -07:00
Daniel J Walsh
87f36844c3 Merge pull request #1252 from cevich/travis_osx_to_cirrus
Travis -> Cirrus: MacOS Cross test
2021-04-21 13:20:48 -04:00
Chris Evich
a81cd74734 Travis -> Cirrus: MacOS Cross test
Also cleanup `Makefile` WRT `${DESTDIR}` definition and use to make it's
purpose more clear.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-21 10:47:24 -04:00
Valentin Rothberg
5a3e8b6150 Merge pull request #1249 from cevich/travis_to_cirrus
Travis -> Cirrus: validate, vendor, and test
2021-04-21 16:25:50 +02:00
Chris Evich
88979a6a88 Cirrus: Improve test synchronization with c/image
The `test_skopeo_task` must be substantially duplicated between this
repository and containers/image.  Make this easier to maintain by
implementing a runner script to contain any/all differences.  This
allows the `test_skopeo_task` definition to remain 100%
identical across the two repositories.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-21 09:55:11 -04:00
Chris Evich
146af8cd59 Travis -> Cirrus: validate, vendor, and test
Also add some basic setup commands to hack/get_ci_vm.sh

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-21 09:55:11 -04:00
Daniel J Walsh
6b95125757 Merge pull request #1256 from vrothberg/vendor-image
vendor c/image v5.11.1
2021-04-21 08:33:09 -04:00
Valentin Rothberg
6ee20f9d2a vendor c/image v5.11.1
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-04-21 11:45:03 +02:00
Morten Linderud
c84fc7d243 Makefile: Ensure policy.json uses new variable
In 18e6c6f17b there where changes to
better handle PREFIX and DESTDIR in the Makefile. "CONTAINERSCONFIGDIR"
was renamed to "CONTAINERSCONFDIR" without ensuring it was correct in
the install block. This results in policy.json being isntalled into
"${DESTDIR}/" which is "/policy.json" for Linux distros.

Signed-off-by: Morten Linderud <morten@linderud.pw>
2021-04-19 09:39:51 -04:00
Daniel J Walsh
060fe4b47f Merge pull request #1248 from rhatdan/master
Bump to v1.2.3
2021-04-15 14:48:40 -04:00
Daniel J Walsh
3a759d5136 Move to v1.2.4-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-15 14:47:23 -04:00
Daniel J Walsh
f15564f705 Bump to v1.2.3
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-15 14:47:07 -04:00
Daniel J Walsh
85e0fde20e Merge pull request #1247 from rhatdan/VERSION
Bump to v1.2.2
2021-04-15 14:45:49 -04:00
Daniel J Walsh
fe1cd126f6 Move to v1.2.3-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-15 14:44:41 -04:00
Daniel J Walsh
7a74faf4c1 Bump to v1.2.2
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-15 14:44:27 -04:00
Daniel J Walsh
dbe6764b35 Merge pull request #1243 from containers/dependabot/go_modules/github.com/containers/storage-1.29.0
Bump github.com/containers/storage from 1.26.0 to 1.29.0
2021-04-15 14:38:22 -04:00
dependabot-preview[bot]
5485daff13 Bump github.com/containers/storage from 1.26.0 to 1.29.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.26.0 to 1.29.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.26.0...v1.29.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-04-15 14:05:51 -04:00
Daniel J Walsh
cfbabac961 Merge pull request #1244 from cevich/new_f34b_images
Update to F34beta images + add hack/get_ci_vm.sh script
2021-04-14 16:45:40 -04:00
Daniel J Walsh
5907b4ef08 Merge pull request #1245 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2021-04-14 09:41:08 -04:00
Wong Hoi Sing Edison
c456cef9bd Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-04-14 10:14:00 +08:00
Chris Evich
0196219924 Cirrus: Add hack/get_ci_vm.sh support
This won't be useful unless/until there are `.cirrus.yml` tasks which
actually utilize VMs.  Once there are, or to support their development,
this script may be helpful.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-13 15:12:02 -04:00
Chris Evich
e945435dea Cirrus: Update to use F34beta VM images
Signed-off-by: Chris Evich <cevich@redhat.com>
2021-04-13 15:02:54 -04:00
Valentin Rothberg
c5103c6b51 Merge pull request #1241 from jonstelly/patch-1
Fix for login / logout registry argument
2021-04-13 09:33:55 +02:00
Jon Stelly
61722a8a70 Fix for login / logout registry argument
login and logout don't seem to support or require the `docker://` scheme prefix.

Fixes part of #1240
2021-04-12 13:56:25 -05:00
Daniel J Walsh
cc3ddf4804 Merge pull request #1238 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2021-04-06 08:31:55 -04:00
Wong Hoi Sing Edison
d9f4377831 Update nix pin with make nixpkgs
- Bugfix `make nixpkgs` which pin with branch `nixos-20.09`
  - Code lint with `nixpkgs-fmt`
  - Code sync between x86\_64 and aarch64

Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-04-04 09:14:48 +08:00
Daniel J Walsh
0717014e46 Merge pull request #1234 from vrothberg/fix-1233
skopeo images: set authfile to /tmp/auth.json
2021-03-23 16:27:06 -04:00
Valentin Rothberg
80dcddef36 skopeo images: set authfile to /tmp/auth.json
The Skopeo images set `REGISTRY_AUTH_FILE=/auth.json` which is breaking
non-root users inside the container from logging in (`/` is writable by
root only).  Setting it to `/tmp/auth.json` will support running
non-root users inside the container.

Fixes: #1233
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-03-22 11:28:11 +01:00
Nikolas Skoufis
6b41287cbf Upgrade dsnet/compress to avoid vulnerable xz version
This updates the indirect dependency we have on dsnet/compress (via
opencontainer/image-tools) to the latest master commit, which includes
an update to a non-vulnerable version of xz.
2021-03-16 11:03:19 +01:00
Hironori Shiina
bef5e4505e Add system tests
Add system tests for the following subcommands and flags:
- skopeo copy --format
- skopeo copy --additional-tag
- skopeo copy --dest-shared-blob-dir
- skopeo copy --src-shared-blob-dir
- skopeo inspect --tls-verify --cert-dir
- skopeo delete --tls-verify --cert-dir
- skopeo copy --dest-creds
- skopeo copy --src-creds
- skopeo copy --authfile
- skopeo inspect --authfile
- skopeo delete --authfile
- skopeo copy --remove-signatures
- skopeo standalone-sign
- skopeo standalone-verify
- skopeo manifest-digest

Signed-off-by: Hironori Shiina <shiina.hironori@jp.fujitsu.com>
2021-03-16 11:00:56 +01:00
Chris Evich
f5a028e4d9 Fix skipping tests in test container
Without this env. var. being set from hack/make.sh, many/most
integration tests will `SKIP`.  Fix this by notifying the user
and setting the magic `SKOPEO_CONTAINER_TESTS` variable.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-03-10 17:41:29 +01:00
Chris Evich
3d1d2978d7 Add local integration and system test targets
These tests need to operate as part of the c/image repository CI to
verify downstream-usage.  That environment is already inside the
container built from the Dockerfile (here).  Support this use-case by
adding 'local' targets which bypass the container build.  Also,
simplify the "in-container" check to more specifically verify the exact
container image it's operating under.

Signed-off-by: Chris Evich <cevich@redhat.com>
2021-03-09 15:16:47 +01:00
Wong Hoi Sing Edison
035eb33f1f Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-03-08 16:02:30 +01:00
Chris Evich
6cbb0c4c88 Cirrus: Initial implementation support for GCP VMs
Signed-off-by: Chris Evich <cevich@redhat.com>
2021-03-03 15:33:31 -05:00
Daniel J Walsh
663fe44f27 Merge pull request #1209 from TomSweeneyRedHat/dev/tsweeney/fed33_dockerfiles
Bump skopoeoimage Dockerfiles to user Fedora 33
2021-03-01 12:49:59 -05:00
TomSweeneyRedHat
cc24482985 Bump skopoeoimage Dockerfiles to user Fedora 33
The quay.io/skopeo/testing:latest image was showing v1.2.0 for a version when it
should have been showing at least v1.2.1.  The issue was the Fedora tag in the
Dockerfiles used to build the images was set to 32 and not the later 33.

Addresses: #1204

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-02-27 15:08:16 -05:00
Lokesh Mandvekar
b7bf15bc8b Dockerfile.build: switch to fedora:latest
CopySuite.TestCopySignatures: Use quay.io instead of docker.io.

Resolves: gh#174

Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2021-02-24 15:49:14 +01:00
George Jenkins
61b62f9e93 Enable 'OptimizeDestinationImageAlreadyExists' feature
Signed-off-by: George Jenkins <gjenkins8@bloomberg.net>
2021-02-24 12:39:09 +01:00
Daniel J Walsh
2c8655e251 Merge pull request #1193 from containers/dependabot/go_modules/github.com/spf13/cobra-1.1.3
Bump github.com/spf13/cobra from 1.1.2 to 1.1.3
2021-02-23 16:35:40 -05:00
Daniel J Walsh
94d588c480 Merge pull request #1206 from containers/dependabot/go_modules/github.com/containers/image/v5-5.10.3
Bump github.com/containers/image/v5 from 5.10.2 to 5.10.3
2021-02-23 16:35:15 -05:00
Daniel J Walsh
a85e3beccf Bump github.com/spf13/cobra from 1.1.2 to 1.1.3
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.2...v1.1.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-02-23 05:54:33 -05:00
Daniel J Walsh
3878a37660 Bump github.com/containers/image/v5 from 5.10.2 to 5.10.3
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.10.2 to 5.10.3.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.10.2...v5.10.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-02-23 05:51:54 -05:00
dependabot-preview[bot]
be600975a9 Bump github.com/containers/storage from 1.25.0 to 1.26.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.25.0 to 1.26.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.25.0...v1.26.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-02-22 16:54:52 +01:00
Valentin Rothberg
15f0d5cd2f add stale bot
By popular demand, add the stale bot which we'are already using at
Podman.  The bot will remind us every 30 days of inactivity on specific
issues or pull requests and has turned into a useful tool to keep things
on the radar.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-02-17 09:21:45 +01:00
dependabot-preview[bot]
6fa634227c Bump github.com/spf13/cobra from 1.1.1 to 1.1.2
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-02-11 09:44:06 +01:00
dependabot-preview[bot]
e224b78efc Bump github.com/containers/image/v5 from 5.10.1 to 5.10.2
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.10.1 to 5.10.2.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.10.1...v5.10.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-02-10 16:38:59 +01:00
Miloslav Trmač
1c4b0fc33d Merge pull request #1124 from nalind/test-mediatype
020-copy.bats: check that we set the manifest type correctly
2021-02-05 21:00:28 +01:00
Nalin Dahyabhai
81e66ffc46 020-copy.bats: check that we set the manifest type correctly
When copying to an OCI layout destination, forcing zstd compression,
check that the manifest correctly describes the type of the layer blob.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-02-05 11:31:12 -05:00
Miloslav Trmač
5995ceedf9 Merge pull request #1186 from TomSweeneyRedHat/dev/tsweeney/protobuf
Bump github.com/gogo/protobuf/proto to v1.3.2
2021-02-04 13:29:36 +01:00
TomSweeneyRedHat
7a9d638989 Bump github.com/gogo/protobuf/proto to v1.3.2
Bumping github.com/gogo/protobuf/proto to v1.3.2 to enusure
a low likelyhood CVE is reached.  Partially addresses:

https://bugzilla.redhat.com/show_bug.cgi?id=1924544

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-02-03 20:23:10 -05:00
Daniel J Walsh
40f5a8cf69 Merge pull request #1159 from jonjohnsonjr/user-agent
Set User-Agent to skopeo/$VERSION
2021-02-03 16:56:27 -05:00
Daniel J Walsh
a6e50d32d2 Merge pull request #1184 from containers/dependabot/go_modules/github.com/containers/storage-1.25.0
Bump github.com/containers/storage from 1.24.5 to 1.25.0
2021-02-03 16:36:59 -05:00
Jon Johnson
9a88c3986d Set User-Agent to skopeo/$VERSION
Prior to this, the User-Agent used by containers/image would default to
the default User-Agent for golang, which makes it difficult to
distinguish skopeo from any other golang binaries in registry logs.

Signed-off-by: Jon Johnson <jonjohnson@google.com>
2021-02-03 08:39:43 -08:00
dependabot-preview[bot]
ac5241482c Bump github.com/containers/storage from 1.24.5 to 1.25.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.24.5 to 1.25.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.24.5...v1.25.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-02-03 12:46:11 +01:00
dependabot-preview[bot]
aff1b6215b Bump github.com/containers/ocicrypt from 1.0.3 to 1.1.0
Bumps [github.com/containers/ocicrypt](https://github.com/containers/ocicrypt) from 1.0.3 to 1.1.0.
- [Release notes](https://github.com/containers/ocicrypt/releases)
- [Commits](https://github.com/containers/ocicrypt/compare/v1.0.3...v1.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-02-03 12:42:56 +01:00
Miloslav Trmač
e0ba05af59 Merge pull request #1183 from containers/dependabot/go_modules/github.com/containers/common-0.34.0
Bump github.com/containers/common from 0.33.1 to 0.34.0
2021-02-02 20:43:33 +01:00
Daniel J Walsh
55b9782058 Merge pull request #1171 from containers/dependabot/go_modules/github.com/containers/ocicrypt-1.1.0
Bump github.com/containers/ocicrypt from 1.0.3 to 1.1.0
2021-02-02 08:20:15 -05:00
dependabot-preview[bot]
4ab7faa800 Bump github.com/containers/common from 0.33.1 to 0.34.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.33.1 to 0.34.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.33.1...v0.34.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-02-02 06:32:37 -05:00
Daniel J Walsh
c51c7b4e4d Merge pull request #1178 from containers/dependabot/go_modules/github.com/containers/image/v5-5.10.1
Bump github.com/containers/image/v5 from 5.10.0 to 5.10.1

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-02-02 06:31:37 -05:00
Daniel J Walsh
3375a905cc Merge pull request #1178 from containers/dependabot/go_modules/github.com/containers/image/v5-5.10.1
Bump github.com/containers/image/v5 from 5.10.0 to 5.10.1
2021-02-01 08:50:40 -05:00
Miloslav Trmač
f3c8d26cd8 Merge pull request #1165 from runhyve/fix-freebsd-build
Set PREFIX on FreeBSD and use gpg-config to detect paths
2021-01-30 23:39:42 +01:00
dependabot-preview[bot]
e1dc30b6e1 Bump github.com/containers/image/v5 from 5.10.0 to 5.10.1
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.10.0...v5.10.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-30 06:21:59 -05:00
Daniel J Walsh
a9e9bdc534 Merge pull request #1176 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2021-01-30 06:20:46 -05:00
Mateusz Kwiatkowski
6c8b8c20f5 Rebase against master and improve comment about gpgme-config 2021-01-29 14:19:34 +01:00
Wong Hoi Sing Edison
0e1ee196bd Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-01-29 14:05:36 +08:00
TomSweeneyRedHat
77a2e08eb2 Vendor in latest golang.org/x/crypto
Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-01-28 18:16:10 -05:00
Miloslav Trmač
a3c21f25c9 Merge pull request #1173 from containers/dependabot/go_modules/github.com/containers/image/v5-5.10.0
Bump github.com/containers/image/v5 from 5.9.0 to 5.10.0
2021-01-28 22:18:03 +01:00
dependabot-preview[bot]
1e1952693a Bump github.com/containers/image/v5 from 5.9.0 to 5.10.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.9.0 to 5.10.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.9.0...v5.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-01-28 11:55:09 +01:00
Daniel J Walsh
efc0170ee8 Merge pull request #1169 from edsantiago/dockerpocalypse
Migrate tests from docker.io
2021-01-22 05:23:22 -05:00
Daniel J Walsh
0d0a97eb00 Merge pull request #1168 from rhatdan/Makefile
Fix Makefile to handle PREFIX correctly
2021-01-21 17:47:10 -05:00
Ed Santiago
47a6716921 Migrate tests from docker.io
Switch to using images from quay.io/libpod instead, where
we're not (yet) subject to rate limiting.

Completely rewrite one unclear test. The purpose of the
test was to test #708, in which 'skopeo inspect --raw'
was fixed to be able to inspect images that do not
match the current host's os+arch. We now use a fixed
test image on quay.io, generated by a new script,
whose manifest is pretty unlikely to match our host.

Signed-off-by: Ed Santiago <santiago@redhat.com>
2021-01-21 14:04:01 -07:00
Daniel J Walsh
18e6c6f17b Fix Makefile to handle PREFIX correctly
PREFIX should default to /usr/local according to GNU coding standards.

DESTDIR should just be used for install

This will allow us to specify

make PREFIX=/usr DESTDIR=/tmp/build/ install

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-21 13:54:53 -05:00
Daniel J Walsh
ef6f46a3b5 Merge pull request #1162 from containers/dependabot/go_modules/github.com/containers/common-0.33.1
Bump github.com/containers/common from 0.33.0 to 0.33.1
2021-01-15 04:41:04 -05:00
Miloslav Trmač
31562124a3 Merge pull request #1161 from containers/dependabot/go_modules/github.com/stretchr/testify-1.7.0
Bump github.com/stretchr/testify from 1.6.1 to 1.7.0
2021-01-14 23:24:02 +01:00
dependabot-preview[bot]
b544c1be3a Bump github.com/stretchr/testify from 1.6.1 to 1.7.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.1 to 1.7.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.6.1...v1.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-14 09:50:58 -05:00
dependabot-preview[bot]
0c0a17b641 Bump github.com/containers/common from 0.33.0 to 0.33.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.33.0 to 0.33.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.33.0...v0.33.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-14 09:50:05 -05:00
Miloslav Trmač
2e90a8af5a Merge pull request #1158 from TomSweeneyRedHat/v1.2.1-bump
V1.2.1
2021-01-11 12:20:52 +01:00
TomSweeneyRedHat
2294113c78 Bump to v1.2.2-dev
Bumping to v1.2.2-dev

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-01-10 12:09:25 -05:00
TomSweeneyRedHat
bdb117ded6 Bump to v1.2.1
Bumping to v1.2.1

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2021-01-10 12:08:27 -05:00
Daniel J Walsh
beadcbb17d Merge pull request #1143 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2021-01-10 05:08:02 -05:00
Wong Hoi Sing Edison
fe57e80c18 Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2021-01-10 11:49:55 +08:00
Miloslav Trmač
ac07bf278a Merge pull request #1121 from mtrmac/remapIdentity
Tests for remapIdentity
2021-01-09 17:29:08 +01:00
Miloslav Trmač
3c33cb4556 Add a smoke test for signedIdentity:remapIdentity
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-01-08 17:20:09 +01:00
Miloslav Trmač
f94d85aa8e Split copyWithSignedIdentity from TestCopyVerifyingMirroredSignatures
... because we will add another user.

Also remove an obsolete FIXME.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-01-08 17:20:09 +01:00
Daniel J Walsh
b0da05656d Merge pull request #1152 from rhatdan/VENDOR
Update vendor of containers/common and containers/storage
2021-01-08 10:54:05 -05:00
Daniel J Walsh
9828f21007 Merge pull request #1146 from nalind/test-pause
integration test: sync k8s.gcr.io/pause instead of docker.io/alpine
2021-01-08 10:53:04 -05:00
Nalin Dahyabhai
6ee4b2dc84 integration test: sync k8s.gcr.io/pause instead of docker.io/alpine
Do repository synchronization tests using k8s.gcr.io/pause and
k8s.gcr.io/coredns/coredns instead of docker.io/alpine.
The k8s.gcr.io/pause repository includes multiple tags, at least one of
which is a single image ("1.0"), and at least one of which is a manifest
list ("3.2", "3.3"), and includes a "latest" tag.
The k8s.gcr.io/coredns/coredns repository includes multiple tags, at
least one of which is a single image ("v1.6.6"), and at least one of which
is a manifest list ("v1.8.0").

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-01-08 09:51:08 -05:00
Nalin Dahyabhai
b3a15e7288 integration test: use fedora-minimal for most manifest list tests
Switch most of our tests that exercise reading, copying from, and
inspecting tags that point to manifest lists from using
docker.io/estesp/busybox to using
registry.fedoraproject.org/fedora-minimal, which doesn't limit how often
we can pull the images.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-01-08 09:50:12 -05:00
Daniel J Walsh
f771cb0d39 Update vendor of containers/common and containers/storage
We are preparing for RHEL 8.4 release and want to make
sure all container tools have the same containers suppackages.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-08 09:46:28 -05:00
Miloslav Trmač
c4fb93647a Fix reading the after-sync list of tags in SyncSuite.TestYamlUntagged
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-01-08 11:16:20 +01:00
Daniel J Walsh
81535c5244 Merge pull request #1144 from containers/dependabot/go_modules/github.com/containers/common-0.31.2
Bump github.com/containers/common from 0.31.1 to 0.31.2
2021-01-04 11:45:26 -05:00
dependabot-preview[bot]
7442052875 Bump github.com/containers/common from 0.31.1 to 0.31.2
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.31.1 to 0.31.2.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.31.1...v0.31.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-01-04 09:05:04 -05:00
Daniel J Walsh
84232cf306 Merge pull request #1140 from jsoref/spelling
Spelling
2020-12-30 07:32:24 -05:00
Daniel J Walsh
c339a1abe9 Merge pull request #1138 from containers/dependabot/go_modules/github.com/containers/common-0.31.1
Bump github.com/containers/common from 0.31.0 to 0.31.1
2020-12-30 07:31:38 -05:00
Daniel J Walsh
766927d1d4 Merge pull request #1142 from QiWang19/sync-creds
fix creds sync from yaml
2020-12-30 07:31:08 -05:00
Qi Wang
fc78c93ad2 fix creds sync from yaml
Pass down the creds from yaml file only if the values are not empty.
    Enables to use credentials from other authfiles alternatively.
Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-12-25 20:18:35 -05:00
Josh Soref
4987a67293 Spelling
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-21 16:10:45 -05:00
dependabot-preview[bot]
131b2b8c63 Bump github.com/containers/common from 0.31.0 to 0.31.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.31.0 to 0.31.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.31.0...v0.31.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-12-21 15:58:05 -05:00
Daniel J Walsh
342b8398e2 Merge pull request #1120 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2020-12-21 15:56:24 -05:00
Wong Hoi Sing Edison
6b260e1686 Update nix pin with make nixpkgs
This PR introduce 3 changes:

  - Upgrade Nix stable channel from 20.03 to 20.09.

    NixOS 20.09 released at 2020-10-27, see
    <https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-20.09>
    for more information.

  - Replace `git` with `gitMinimal`.

    All 6 projects (i.e. crun/conmon/skopeo/buildah/podman/cri-o) are
    having `git` as dependency for failsafe during bootstrap. BTW
    <https://github.com/NixOS/nixpkgs/pull/104896> replace `asciidoc`
    with `asciidoctor` so trigger the dependency chain to `glib` and so
    failed (see below). Switching to `gitMinimal` skip this dependency
    chain to `glib`, which also speed up overall build process.

  - Adding `-pthread` for `glib`

    `conmon` couldn't skip the error by replacing `git` with
    `gitMinimal` since it do depend on `glib`. Since `glib` trigger
    error message "undefined reference to 'pthread\_create'", therefore
    adding `pthread` to `CFLAGS` could solve the problem.

Also see:

  - <https://github.com/containers/crun/pull/550>
  - <https://github.com/containers/conmon/pull/218>
  - <https://github.com/containers/skopeo/pull/1120>
  - <https://github.com/containers/buildah/pull/2831>
  - <https://github.com/containers/podman/pull/8526>
  - <https://github.com/cri-o/cri-o/pull/4395>

Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2020-12-20 18:40:40 +08:00
Daniel J Walsh
6294875a04 Merge pull request #1132 from lsm5/update-debian-docs
update debian/ubuntu docs
2020-12-12 06:21:09 -05:00
Lokesh Mandvekar
8cc9fcae6f update debian/ubuntu docs
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2020-12-11 13:20:42 -05:00
Miloslav Trmač
4769dd0689 Merge pull request #1118 from containers/dependabot/go_modules/gopkg.in/yaml.v2-2.4.0
Bump gopkg.in/yaml.v2 from 2.3.0 to 2.4.0
2020-12-08 23:59:30 +01:00
Daniel J Walsh
0fb1121f36 Bump gopkg.in/yaml.v2 from 2.3.0 to 2.4.0
Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.3.0...v2.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-12-08 06:24:11 -05:00
Daniel J Walsh
4aaa9b401d Merge pull request #1127 from containers/dependabot/go_modules/github.com/containers/common-0.31.0
Bump github.com/containers/common from 0.30.0 to 0.31.0
2020-12-08 06:20:17 -05:00
Daniel J Walsh
44087c4866 Merge pull request #1129 from containers/dependabot/go_modules/github.com/containers/storage-1.24.3
Bump github.com/containers/storage from 1.24.1 to 1.24.3
2020-12-08 06:19:43 -05:00
dependabot-preview[bot]
f36f7dbfdf Bump github.com/containers/storage from 1.24.1 to 1.24.3
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.24.1 to 1.24.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.24.1...v1.24.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-12-07 20:28:16 -05:00
dependabot-preview[bot]
07c0e6a50f Bump github.com/containers/common from 0.30.0 to 0.31.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.30.0...v0.31.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-12-07 20:27:40 -05:00
Miloslav Trmač
ed321809d3 Merge pull request #1128 from containers/dependabot/go_modules/github.com/containers/image/v5-5.9.0
Bump github.com/containers/image/v5 from 5.8.1 to 5.9.0
2020-12-08 00:10:06 +01:00
dependabot-preview[bot]
13ef91744c Bump github.com/containers/image/v5 from 5.8.1 to 5.9.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.8.1 to 5.9.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.8.1...v5.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-12-07 19:44:38 +01:00
Miloslav Trmač
5b8fe7ffa5 Merge pull request #1123 from containers/dependabot/go_modules/github.com/containers/common-0.30.0
Bump github.com/containers/common from 0.27.0 to 0.30.0
2020-12-04 17:58:13 +01:00
dependabot-preview[bot]
8cd57ef8de Bump github.com/containers/common from 0.27.0 to 0.30.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.27.0 to 0.30.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.27.0...v0.30.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-12-03 20:36:21 +01:00
Miloslav Trmač
1b813f805b Merge pull request #1119 from mtrmac/xcode-select
Update to macOS 10.14
2020-11-30 15:03:48 +01:00
Miloslav Trmač
f3a8a7360d Update to macOS 10.14
Homebrew:
> Warning: You are using macOS 10.13.
> We (and Apple) do not provide support for this old version.
> You will encounter build failures with some formulae.

So, update to the 10.14 major version, fully-updated.

Also remove the Xcode update attempt, it was added before
Homebrew was warning about the Xcode version, but updating only
after running Homebrew does not help, and anyway it does not
complain anymore after the update.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-11-28 20:47:26 +01:00
Daniel J Walsh
42e9121eba Merge pull request #1117 from lsm5/update-install-docs
Update install docs
2020-11-24 14:50:52 -05:00
Lokesh Mandvekar
4597c09522 update OSX Travis env before running tests
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2020-11-24 14:11:11 -05:00
Lokesh Mandvekar
2ec251c2e2 Update installation docs for debian and ubuntu
Continuation of Michael R. Crusoe's pr#1115.

Co-authored-by: Tom Sweeney <tsweeney@redhat.com>
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2020-11-24 13:41:05 -05:00
Michael R. Crusoe
e717a59174 Update install.md 2020-11-24 08:06:28 -05:00
Daniel J Walsh
c88576b2fc Merge pull request #1112 from rhatdan/VENDOR
vendor in containers/storage v1.24.1 containers/image v5.8,1
2020-11-20 10:52:21 -05:00
Daniel J Walsh
901f7e9c47 vendor in containers/storage v1.24.1 containers/image v5.8,1
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-19 16:29:39 -05:00
Daniel J Walsh
0f4dc80c99 Merge pull request #1110 from barthy1/multi_arch_doc
Add information about multi-arch image to README
2020-11-19 16:25:54 -05:00
Daniel J Walsh
353f3a23e1 Merge pull request #1070 from rhatdan/format
Add --format option to skopeo inspect
2020-11-19 16:25:20 -05:00
Yulia Gaponenko
4b4ad6285e Fix naming and language
- rename skopeo to Skopeo
- improve language

Co-authored-by: Tom Sweeney <tsweeney@redhat.com>
2020-11-19 18:23:46 +01:00
Yulia Gaponenko
6b007c70c7 Add information about multi-arch image to README
Also update to the correct one information about required env variables
for multi-arch build

Signed-off-by: Yulia Gaponenko <yulia.gaponenko1@de.ibm.com>
2020-11-19 18:23:33 +01:00
Daniel J Walsh
6a48870594 Merge pull request #1106 from containers/dependabot/go_modules/github.com/containers/image/v5-5.8.0
Bump github.com/containers/image/v5 from 5.6.0 to 5.8.0
2020-11-19 09:56:08 -05:00
Daniel J Walsh
5d73dea577 Add --format option to skopeo inspect
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-18 16:44:23 -05:00
Daniel J Walsh
82e461ff9d Switch to using errors.Wrapf rather then fmt.Errorsf
We are using both functions throughout the code. Pick
one and stick with it.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-18 16:43:15 -05:00
Daniel J Walsh
e30abff31b Bump github.com/containers/image/v5 from 5.6.0 to 5.8.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.6.0 to 5.8.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.6.0...v5.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-18 15:11:11 -05:00
Daniel J Walsh
7fee9122fb Merge pull request #1105 from containers/dependabot/go_modules/github.com/containers/common-0.27.0
Bump github.com/containers/common from 0.26.0 to 0.27.0
2020-11-18 15:09:00 -05:00
Daniel J Walsh
2342171cdf Merge pull request #880 from muff1nman/sync-digests
Fix #858 Add support for digests in sync
2020-11-17 09:06:44 -05:00
Daniel J Walsh
58c9eccffd Bump github.com/containers/common from 0.26.0 to 0.27.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.26.0 to 0.27.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.26.0...v0.27.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-17 09:02:35 -05:00
Daniel J Walsh
23fa1666dd Merge pull request #1104 from cevich/split_quay_envars
Support namespaced logins for quay.io
2020-11-17 09:01:21 -05:00
Daniel J Walsh
fa2e385713 Merge pull request #1107 from containers/dependabot/go_modules/github.com/containers/storage-1.24.0
Bump github.com/containers/storage from 1.23.9 to 1.24.0
2020-11-17 08:57:03 -05:00
Chris Evich
958c361c97 Support namespaced logins for quay.io
Service accounts (a.k.a. robots) in `quay.io` are forcably namespaced
to the user or orginization under which they are created.  Therefore,
it is impossible to use a common login/password to push images for
both `skopeo` and `containers` namespaces.  Worse, because the
authentication is recorded against `quay.io`, multiple login sessions
are required.

Fix this by adding a function definition which verifies non-empty
username/password arguments, before logging in.  Call this function
as needed from relevant targets, prior to pushing images.

Signed-off-by: Chris Evich <cevich@redhat.com>
2020-11-17 08:53:00 -05:00
Daniel J Walsh
72e8af59aa install: make commands copy-pasteable
Based on Elan Ruusamäe patch.
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-17 09:29:43 +01:00
Andrew DeMaria
873fbee01b Fix #858 Add --all sync flag to emulate copy --all
This replicates the --all copy flag to sync to perform the same
behavior. Namely, the default is CopySystemImage unless --all is passed
which changes the behavior to CopyAllImages. While it is probably
desirable for --all to be the default as there is no option to override
ones architecture with the sync command, --all can potentially break
existing sync incantations depending on registry support. Hence
CopySystemImage remains the default.

Signed-off-by: Andrew DeMaria <ademaria@cloudflare.com>
2020-11-16 15:18:56 -07:00
Andrew DeMaria
1a3eb478a7 Fix #858 Add support for digests in sync
Signed-off-by: Andrew DeMaria <ademaria@cloudflare.com>
2020-11-16 15:18:53 -07:00
dependabot-preview[bot]
bc0ecfc8f6 Bump github.com/containers/storage from 1.23.9 to 1.24.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.9 to 1.24.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.23.9...v1.24.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-16 17:14:54 -05:00
Daniel J Walsh
4ad2c75b52 Merge pull request #1091 from saschagrunert/osusergo
Use osusergo build tag for static build
2020-11-12 15:49:46 -05:00
Daniel J Walsh
9662633059 Merge pull request #1098 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2020-11-12 15:46:34 -05:00
Daniel J Walsh
18fe2fd00a Merge pull request #1089 from containers/dependabot/go_modules/github.com/containers/storage-1.23.7
Bump github.com/containers/storage from 1.23.5 to 1.23.9
2020-11-12 09:43:38 -05:00
Wong Hoi Sing Edison
19f9a6adc2 Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2020-11-12 21:11:43 +08:00
Daniel J Walsh
11b4fd3956 Merge pull request #1099 from mbargull/no-LDFLAGS-override
Avoid overriding LDFLAGS in Makefile
2020-11-12 06:29:23 -05:00
Daniel J Walsh
8d2c20f160 Merge pull request #1066 from barthy1/skopeo_upstream
add multi-arch build of upstream skopeo image via Travis
2020-11-12 06:24:22 -05:00
Daniel J Walsh
6d7d0e7d39 Bump github.com/containers/storage from 1.23.5 to 1.23.9
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.5 to 1.23.9.
- [Release notes](https://github.com/containers/storage/releases)
- [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md)
- [Commits](containers/storage@v1.23.5...v1.23.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-11-12 06:18:40 -05:00
Yulia Gaponenko
39f8117c27 add multi-arch builds for upstream and stable skopeo image via Travis
Travis is used, as it has native hardware to run the build for many
architectures (amd64, s390x, ppc64le). Docker is used as build and
manifest tool. `quay.io/skopeo/upstream:master`, `quay.io/skopeo/stable:v1.2.0`
and `quay.io/containers/skopeo:v1.2.0` are specified as target multi-arch
upstream image.
Travis config file has 3 stages:
- local-build to do the local test for linux/amd64 and osx, as it was in
the initial code
- image-build-push to build and push images for specific architectures
(amd64, s390x, ppc64le)
- manifest-multiarch-push to create and push manifest for multi-arch
image - `quay.io/skopeo/upstream:master`, `quay.io/skopeo/stable:v1.2.0`
and `quay.io/containers/skopeo:v1.2.0`

last stage amnd image push step are not done for pull request.

2 env variables specified in Travis settings are expected - QUAY_USERNAME and
QUAY_PASSWORD to push the images to quay.io.
As a result multi-arch images for 3 architectures are published.

README about build setup id prepared

Signed-off-by: Yulia Gaponenko <yulia.gaponenko1@de.ibm.com>
2020-11-09 20:19:24 +01:00
Marcel Bargull
e709329b03 Avoid overriding LDFLAGS in Makefile
Signed-off-by: Marcel Bargull <marcel.bargull@udo.edu>
2020-11-06 19:20:12 +01:00
Miloslav Trmač
1a3ae1411e Merge pull request #1094 from vrothberg/bump-go
Travis: bump go to 1.15.x
2020-11-06 16:46:12 +01:00
Valentin Rothberg
35daba1194 Dockerfile: install openssl
Apparently openssl was dropped from fedora.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-11-04 16:53:08 +01:00
Valentin Rothberg
65c5b0bf8d integration tests: disable ls for logs
For yet unknown reasons, Travis throws permission errors when trying to
recursively list the contents of a temp directory.  It passes locally,
so disable the logs to unblock CI.  Note, the reasons for the error are
yet to be revealed.

Related-issue: https://github.com/containers/skopeo/issues/1093
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-11-04 16:52:54 +01:00
Valentin Rothberg
cd884fa529 Travis: bump go to 1.15.x
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-11-04 12:04:13 +01:00
Sascha Grunert
3a72464068 Use osusergo build tag for static build
We now use the osusergo build tag to not use the glibc functions which
occur in the warnings but them from golang the os/user package.

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
2020-11-02 10:37:50 +01:00
Daniel J Walsh
32e242586c Merge pull request #1090 from jjasghar/patch-1
Update install.md
2020-10-30 14:14:33 -04:00
JJ Asghar
a7f4b26f90 Update install.md
Fixed some formatting.
2020-10-29 15:37:35 -05:00
Daniel J Walsh
9bcae7060a Merge pull request #1088 from j0057/fix-login-example
Fix `skopeo login` example in README
2020-10-27 15:34:55 -04:00
Joost Molenaar
98fdb042a1 Fix skopeo login example in README 2020-10-27 15:21:46 +01:00
Daniel J Walsh
ceaee440a6 Merge pull request #1076 from containers/dependabot/go_modules/github.com/containers/common-0.26.0
Bump github.com/containers/common from 0.24.0 to 0.26.0
2020-10-21 08:44:58 -04:00
Daniel J Walsh
6eb4fb64a0 Merge pull request #1081 from containers/dependabot/go_modules/github.com/spf13/cobra-1.1.1
Bump github.com/spf13/cobra from 1.0.0 to 1.1.1
2020-10-21 08:44:34 -04:00
dependabot-preview[bot]
a75daba386 Bump github.com/containers/common from 0.24.0 to 0.26.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.24.0...v0.26.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-10-19 06:02:04 -04:00
dependabot-preview[bot]
67d72d27c9 Bump github.com/spf13/cobra from 1.0.0 to 1.1.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.0.0 to 1.1.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.0.0...v1.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-10-19 06:01:38 -04:00
Daniel J Walsh
362f70b056 Merge pull request #1074 from steveeJ/patch-1
install.md: mention Nix/NixOS
2020-10-14 18:10:33 -04:00
Stefan Junker
035e25496a install.md: mention Nix/NixOS 2020-10-14 11:31:45 +02:00
Daniel J Walsh
10da9f7012 Merge pull request #1068 from rhatdan/readme
Update README.md
2020-10-10 08:43:39 -04:00
Daniel J Walsh
c18a977e96 Merge pull request #1069 from rhatdan/makefile
Make Makefile a little easier to use
2020-10-10 08:43:16 -04:00
Daniel J Walsh
0954077fd7 Update install.md
Co-authored-by: Tom Sweeney <tsweeney@redhat.com>
2020-10-09 06:57:29 -04:00
Daniel J Walsh
bde39ce91d Update install.md
Co-authored-by: Miloslav Trmač <mitr@redhat.com>
2020-10-09 06:57:12 -04:00
Daniel J Walsh
a422316d48 Update README.md
Add commands section
Add information about skopeo sync

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-10-08 13:39:32 -04:00
Daniel J Walsh
21aa04e3c3 Make Makefile a little easier to use
By default we should build bin/skopeo locally
and build docs locally.

Show output when doing make docs.

Add description in `make help` to explain default
behaviour.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-10-08 10:19:41 -04:00
Daniel J Walsh
4cc72b9f69 Merge pull request #1067 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2020-10-08 05:16:55 -04:00
Wong Hoi Sing Edison
50ff352e41 Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@pantarei-design.com>
2020-10-08 12:05:09 +08:00
Miloslav Trmač
027d7e466a Merge pull request #1064 from containers/dependabot/go_modules/github.com/containers/common-0.24.0
Bump github.com/containers/common from 0.23.0 to 0.24.0
2020-10-02 20:29:57 +02:00
dependabot-preview[bot]
69f51ac183 Bump github.com/containers/common from 0.23.0 to 0.24.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.23.0 to 0.24.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.23.0...v0.24.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-10-02 11:27:01 -04:00
Miloslav Trmač
d8bc8b62e9 Merge pull request #1062 from edsantiago/openssl_san
Add Subject Alternative Name to local openssl cert
2020-10-01 15:31:07 +02:00
Ed Santiago
f9773889a1 Add Subject Alternative Name to local openssl cert
Go 1.15 deprecates checking CN; this broke gating tests:

   Get "https://localhost:5000/v2/": x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

Easy two-line solution in the 'openssl' invocation. Huge
thanks to Nalin for tracking down and fixing while I was
still getting started:

   https://github.com/containers/buildah/pull/2595

Copied from 0f2892a5b021de3b1cf273f5679fda8298b57c02 in buildah

Signed-off-by: Ed Santiago <santiago@redhat.com>
2020-10-01 06:32:55 -06:00
Daniel J Walsh
6dabefa9db Merge pull request #1055 from nalind/cross
Makefile: add a local-cross target
2020-09-30 07:40:54 -04:00
Daniel J Walsh
5364f84119 Merge pull request #1058 from containers/dependabot/go_modules/github.com/sirupsen/logrus-1.7.0
Bump github.com/sirupsen/logrus from 1.6.0 to 1.7.0
2020-09-30 07:40:36 -04:00
Nalin Dahyabhai
4ba7d50174 Makefile: add a local-cross target
Add a make target that cross-compiles for a handful of the possible
targets that `go tool dist list` can tell us about.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2020-09-29 16:20:40 -04:00
dependabot-preview[bot]
12729c4d7e Bump github.com/sirupsen/logrus from 1.6.0 to 1.7.0
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.6.0...v1.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-29 14:27:34 -04:00
Daniel J Walsh
44beab63c9 Merge pull request #1057 from containers/dependabot/go_modules/github.com/containers/common-0.23.0
Bump github.com/containers/common from 0.22.0 to 0.23.0
2020-09-25 13:29:14 -04:00
Daniel J Walsh
669627d1b6 Merge pull request #1053 from lsm5/centos-obs
include OBS install steps for CentOS
2020-09-25 04:18:43 -04:00
dependabot-preview[bot]
1c45df1e03 Bump github.com/containers/common from 0.22.0 to 0.23.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.22.0 to 0.23.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.22.0...v0.23.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-25 04:16:44 -04:00
Daniel J Walsh
f91a9c569d Merge pull request #1049 from rhatdan/VENDOR
Bump to v1.2.0
2020-09-25 04:12:30 -04:00
Lokesh Mandvekar
248a1dd01a include OBS install steps for CentOS
additional formatting changes

Co-authored-by: Tom Sweeney <tsweeney@redhat.com>
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2020-09-24 14:36:31 -04:00
Daniel J Walsh
3a75b51b59 Move to v1.2.1-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-21 14:27:03 -04:00
Daniel J Walsh
2b4097bc13 Bump to v1.2.0
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-21 14:26:24 -04:00
Daniel J Walsh
8151b89b81 Merge pull request #1038 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2020-09-21 13:53:14 -04:00
Daniel J Walsh
cbd7fb7d37 Merge pull request #1045 from containers/dependabot/go_modules/github.com/containers/image/v5-5.6.0
Bump github.com/containers/image/v5 from 5.5.2 to 5.6.0
2020-09-21 13:51:53 -04:00
Miloslav Trmač
77293ff9c4 Merge pull request #1047 from airadier/registry-token-cli-flag
Add --registry-token flags to support Bearer token authentication
2020-09-18 21:32:24 +02:00
Alvaro Iradier
467b462b79 Keep options order in code and add missing bash completions 2020-09-18 20:57:02 +02:00
Alvaro Iradier
242b573f9a Adding periods 2020-09-18 18:11:01 +02:00
Alvaro Iradier
2d5f12b9a6 Add --registry-token tests to utils_tests.go
Signed-off-by: Alvaro Iradier <airadier@gmail.com>
2020-09-18 12:36:54 +02:00
Alvaro Iradier
3c73c0c0cd Add --registry-token flags to support Bearer token authentication
Signed-off-by: Alvaro Iradier <airadier@gmail.com>
2020-09-18 11:42:54 +02:00
Wong Hoi Sing Edison
ec17cfcbf1 Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@gmail.com>
2020-09-17 09:04:41 +08:00
dependabot-preview[bot]
1d0b1671f8 Bump github.com/containers/image/v5 from 5.5.2 to 5.6.0
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.5.2 to 5.6.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.5.2...v5.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-15 06:16:04 -04:00
Daniel J Walsh
bbd800f974 Merge pull request #1042 from rhatdan/codespell
Fix problems found by codespell
2020-09-15 06:14:41 -04:00
Miloslav Trmač
12ab19f5fd Merge pull request #1043 from containers/dependabot/go_modules/github.com/containers/common-0.22.0
Bump github.com/containers/common from 0.21.0 to 0.22.0
2020-09-14 17:51:36 +02:00
dependabot-preview[bot]
05d172a1f5 Bump github.com/containers/common from 0.21.0 to 0.22.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.21.0...v0.22.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-09-14 16:43:36 +02:00
Daniel J Walsh
45a9efb37f Merge pull request #1039 from containers/dependabot/go_modules/github.com/containers/storage-1.23.5
Bump github.com/containers/storage from 1.23.4 to 1.23.5
2020-09-11 14:49:44 -04:00
Daniel J Walsh
62bafb102d Fix problems found by codespell
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-11 10:19:16 -04:00
dependabot-preview[bot]
4eda1d092d Bump github.com/containers/storage from 1.23.4 to 1.23.5
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.4 to 1.23.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.23.4...v1.23.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-11 06:18:49 -04:00
Daniel J Walsh
5dd09d76c3 Merge pull request #1033 from containers/dependabot/go_modules/github.com/containers/storage-1.23.4
Bump github.com/containers/storage from 1.23.3 to 1.23.4
2020-09-09 15:57:59 -04:00
Miloslav Trmač
23cb1b7f19 Remove an obsolete documentation of (make binary-static)
... which no longer works after #932.

This does not add documentation for the current static build approach,
nor does it add any other place where DISABLE_CGO is documented;
both are not tested by CI, and discouraged due to bad integration
with the rest of the system.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-09-09 10:14:50 +02:00
dependabot-preview[bot]
c1f984a176 Bump github.com/containers/storage from 1.23.3 to 1.23.4
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.3 to 1.23.4.
- [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.23.3...v1.23.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-08 06:05:35 -04:00
Daniel J Walsh
662f9ac8f7 Merge pull request #1031 from containers/dependabot/go_modules/github.com/containers/common-0.21.0
Bump github.com/containers/common from 0.20.3 to 0.21.0
2020-09-02 13:34:33 -04:00
Daniel J Walsh
ae26454014 Merge pull request #1008 from myback/master
fix build in docker container
2020-09-02 12:47:30 -04:00
Daniel J Walsh
5e1d64825c Merge pull request #1026 from alvistack/master-linux-amd64
Update nix pin with `make nixpkgs`
2020-09-02 12:46:36 -04:00
dependabot-preview[bot]
8767e73fe9 Bump github.com/containers/common from 0.20.3 to 0.21.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.20.3 to 0.21.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.20.3...v0.21.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-09-02 12:45:59 -04:00
Wong Hoi Sing Edison
071462199d Update nix pin with make nixpkgs
Signed-off-by: Wong Hoi Sing Edison <hswong3i@gmail.com>
2020-09-01 21:09:48 +08:00
myback
3bb23e355e use base image golang for build 2020-08-31 22:53:25 +07:00
Daniel J Walsh
c4998ebf3f Merge pull request #1027 from containers/dependabot/go_modules/github.com/containers/storage-1.23.2
Bump github.com/containers/storage from 1.23.1 to 1.23.2
2020-08-28 08:28:35 -04:00
Daniel J Walsh
a13b581760 Merge pull request #1028 from jarda-wien/master
Fix skopeo-login docs typo
2020-08-27 05:49:04 -04:00
dependabot-preview[bot]
c8c8d5db78 Bump github.com/containers/storage from 1.23.1 to 1.23.2
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.1 to 1.23.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.23.1...v1.23.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-27 05:48:03 -04:00
Jaroslav Stepanek
ad3d4aecbb Fix skopeo-login docs typo 2020-08-26 15:57:31 +02:00
Daniel J Walsh
87484a1754 Merge pull request #1023 from containers/dependabot/go_modules/github.com/containers/storage-1.23.1
Bump github.com/containers/storage from 1.23.0 to 1.23.1
2020-08-24 06:31:10 -04:00
Daniel J Walsh
58b9ec9e08 Merge pull request #1024 from containers/dependabot/go_modules/github.com/containers/common-0.20.3
Bump github.com/containers/common from 0.20.2 to 0.20.3
2020-08-24 06:30:50 -04:00
dependabot-preview[bot]
6911642122 Bump github.com/containers/storage from 1.23.0 to 1.23.1
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.23.0 to 1.23.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.23.0...v1.23.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-23 06:49:29 -04:00
dependabot-preview[bot]
3ede91cca6 Bump github.com/containers/common from 0.20.2 to 0.20.3
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.20.2 to 0.20.3.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.20.2...v0.20.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-23 06:48:48 -04:00
Daniel J Walsh
5d5756cc83 Merge pull request #1020 from containers/dependabot/go_modules/github.com/containers/image/v5-5.5.2
Bump github.com/containers/image/v5 from 5.5.1 to 5.5.2
2020-08-19 08:54:32 -04:00
Daniel J Walsh
5ad62b9415 Bump github.com/containers/image/v5 from 5.5.1 to 5.5.2
Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.5.1 to 5.5.2.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.5.1...v5.5.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-19 08:02:35 -04:00
Daniel J Walsh
88c8c47ce0 Merge pull request #1016 from XiaodongLoong/build-on-mips
-buildmode=pie is not supported for some arch
2020-08-19 07:59:41 -04:00
Daniel J Walsh
e4f656616c Merge pull request #1017 from containers/dependabot/go_modules/github.com/containers/common-0.20.2
Bump github.com/containers/common from 0.18.0 to 0.20.2
2020-08-19 07:56:07 -04:00
dependabot-preview[bot]
b05933fbc4 Bump github.com/containers/common from 0.18.0 to 0.20.2
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.18.0 to 0.20.2.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.18.0...v0.20.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-18 08:52:41 -04:00
Xiaodong Liu
e5f549099b -buildmode=pie is not supported for some arch
Signed-off-by: Xiaodong Liu <liuxiaodong@loongson.cn>
2020-08-14 17:52:48 +08:00
Daniel J Walsh
ea10e61f7d Merge pull request #973 from alvistack/master-linux-amd64
Build static binary with `buildGoModule`
2020-08-11 17:42:05 -04:00
Wong Hoi Sing Edison
915f40d12a Build static binary with buildGoModule
Signed-off-by: Wong Hoi Sing Edison <hswong3i@gmail.com>
2020-08-11 14:10:43 +08:00
Daniel J Walsh
0c2c7f4016 Update docs/skopeo.1.md
Co-authored-by: Tom Sweeney <tsweeney@redhat.com>
2020-08-10 09:45:08 +02:00
Miloslav Trmač
135ce43169 Add oci-archive to transport list, and link to the authoritative man page
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-08-10 09:45:08 +02:00
Daniel J Walsh
0f94dbcdb3 Merge pull request #1004 from mtrmac/copy-example
Use an inter-registry copy as the example for (skopeo copy)
2020-08-09 08:51:43 -04:00
Daniel J Walsh
f30bab47e6 Merge pull request #1003 from mtrmac/copy-independent
Add an extra clarification to skopeo-copy(1)
2020-08-09 08:50:29 -04:00
Miloslav Trmač
baeaad61d9 Merge pull request #1002 from QiWang19/common-retry
Use c/common retry package
2020-08-08 08:04:35 +02:00
Miloslav Trmač
c750be0107 Use an inter-registry copy as the example for (skopeo copy)
because that's what users are looking for, and instead of using
a containers-storage: source, which might not even work all that
well with all the automatic defaults Podman sets up.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-08-08 04:22:24 +02:00
Qi Wang
84d051fc01 Use c/common retry package
Use c/common retry package.

Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-08-07 21:17:05 -04:00
Miloslav Trmač
56f8222e12 Add an extra clarification to skopeo-copy(1)
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-08-08 02:24:46 +02:00
Miloslav Trmač
78d2f67016 Merge pull request #1001 from containers/dependabot/go_modules/github.com/containers/storage-1.22.0
Bump github.com/containers/storage from 1.21.2 to 1.22.0
2020-08-08 00:33:00 +02:00
dependabot-preview[bot]
c24363ccda Bump github.com/containers/storage from 1.21.2 to 1.22.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.21.2 to 1.22.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.21.2...v1.22.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-07 08:21:01 -04:00
Daniel J Walsh
c052ed7ec8 Merge pull request #992 from rhatdan/inspect
Make InspectOutput an external object
2020-08-03 13:26:18 -04:00
Miloslav Trmač
5e88eb5761 Merge pull request #995 from rhatdan/master
A couple of minor code cleanups.
2020-08-03 15:42:57 +02:00
Daniel J Walsh
4fb724fb7b Make InspectOutput an external object
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-02 07:08:48 -04:00
Daniel J Walsh
e23b780072 Fix make clean to actually remove binaries
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-02 07:04:51 -04:00
Daniel J Walsh
d9058b3021 Switch containers/libpod->containers/podman
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-08-02 07:04:51 -04:00
Daniel J Walsh
62fd5a76e1 Merge pull request #988 from containers/dependabot/go_modules/github.com/containers/common-0.18.0
Bump github.com/containers/common from 0.16.0 to 0.18.0
2020-07-31 07:34:20 -04:00
Daniel J Walsh
6252c22112 Merge pull request #994 from mrueg/dockerfile.build
Dockerfile.build: Upgrade to Ubuntu 20.04
2020-07-30 18:14:26 -04:00
Manuel Rüger
26e6db1cc7 Dockerfile.build: Upgrade to Ubuntu 20.04
19.10 is EOL since July 17, 2020

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2020-07-29 15:10:52 +02:00
dependabot-preview[bot]
b7cdcb00ac Bump github.com/containers/common from 0.16.0 to 0.18.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.16.0 to 0.18.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.16.0...v0.18.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-23 08:28:23 -04:00
Daniel J Walsh
153f18dc0a Merge pull request #986 from containers/dependabot/go_modules/github.com/containers/storage-1.21.2
Bump github.com/containers/storage from 1.21.1 to 1.21.2
2020-07-23 08:18:54 -04:00
dependabot-preview[bot]
4012d0e30c Bump github.com/containers/storage from 1.21.1 to 1.21.2
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.21.1 to 1.21.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.21.1...v1.21.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-22 06:57:31 -04:00
Miloslav Trmač
494d237789 Merge pull request #977 from QiWang19/commands-retry
Retry on skopeo subcommands
2020-07-18 21:55:52 +02:00
Qi Wang
84c53d104a Retry on skopeo subcommands
Applies retry on more skopeo subcommands.
Related issue: https://github.com/containers/skopeo/issues/918

Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-07-17 12:04:20 -04:00
Daniel J Walsh
89fb89a456 Merge pull request #980 from containers/dependabot/go_modules/github.com/containers/common-0.16.0
Bump github.com/containers/common from 0.15.2 to 0.16.0
2020-07-17 07:11:45 -04:00
dependabot-preview[bot]
960b610ff6 Bump github.com/containers/common from 0.15.2 to 0.16.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.15.2 to 0.16.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.15.2...v0.16.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-07-17 00:29:35 +02:00
Daniel J Walsh
29eec32795 Merge pull request #976 from containers/dependabot/go_modules/github.com/containers/storage-1.21.1
Bump github.com/containers/storage from 1.21.0 to 1.21.1
2020-07-16 17:16:50 -04:00
Miloslav Trmač
2fa7b998ba Merge pull request #978 from vrothberg/update-x/text
vendor golang.org/x/text@v0.3.3
2020-07-16 19:01:56 +02:00
Valentin Rothberg
ebc438266d vendor golang.org/x/text@v0.3.3
Fixes: CVE-2020-14040
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-07-16 11:17:54 +02:00
dependabot-preview[bot]
8f5eb45ba6 Bump github.com/containers/storage from 1.21.0 to 1.21.1
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.21.0 to 1.21.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.21.0...v1.21.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-14 21:26:24 -04:00
Daniel J Walsh
6284ceb2b6 Merge pull request #974 from containers/dependabot/go_modules/github.com/containers/storage-1.21.0
Bump github.com/containers/storage from 1.20.2 to 1.21.0
2020-07-11 09:29:08 -04:00
Daniel J Walsh
5e2264d2b5 Bump github.com/containers/storage from 1.20.2 to 1.21.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.20.2 to 1.21.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.20.2...v1.21.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-11 07:38:43 -04:00
Daniel J Walsh
6e295a2097 Merge pull request #975 from containers/dependabot/go_modules/github.com/hashicorp/go-multierror-1.1.0
Bump github.com/hashicorp/go-multierror from 1.0.0 to 1.1.0
2020-07-11 07:36:58 -04:00
dependabot-preview[bot]
19f9a5c2fa Bump github.com/hashicorp/go-multierror from 1.0.0 to 1.1.0
Bumps [github.com/hashicorp/go-multierror](https://github.com/hashicorp/go-multierror) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/hashicorp/go-multierror/releases)
- [Commits](https://github.com/hashicorp/go-multierror/compare/v1.0.0...v1.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-10 06:42:30 -04:00
Daniel J Walsh
f63685f3c8 Merge pull request #971 from containers/dependabot/go_modules/github.com/containers/ocicrypt-1.0.3
Bump github.com/containers/ocicrypt from 1.0.2 to 1.0.3
2020-07-10 06:41:12 -04:00
Miloslav Trmač
dc5f68fe5f Merge pull request #933 from QiWang19/retry
Retry skopeo inspect command
2020-07-09 18:56:51 +02:00
Qi Wang
0858cafffc Retry skopeo inspect command
Enables to retry skopeo inspect. Add `--retry-times` to set the number of times to retry. Use exponential backoff and  1s as default initial retry delay.

Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-07-09 11:57:13 -04:00
dependabot-preview[bot]
2e343342d5 Bump github.com/containers/ocicrypt from 1.0.2 to 1.0.3
Bumps [github.com/containers/ocicrypt](https://github.com/containers/ocicrypt) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/containers/ocicrypt/releases)
- [Commits](https://github.com/containers/ocicrypt/compare/v1.0.2...v1.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-07-09 16:31:10 +02:00
Miloslav Trmač
840c48752e Merge pull request #972 from mtrmac/brew-test
Fix macOS builds in Travis
2020-07-09 16:30:02 +02:00
Miloslav Trmač
0382b01687 Fix macOS builds in Travis
... which are currently failing with
> Error: The `brew link` step did not complete successfully
> The formula built, but is not symlinked into /usr/local
> Could not symlink Frameworks/Python.framework/Headers
> Target /usr/local/Frameworks/Python.framework/Headers
> is a symlink belonging to python@2. You can unlink it:
>   brew unlink python@2

because the Travis-installed machine apparently has quite a few
Homebrew formulae installed, with an old version of Homebrew,
including a now-removed python@2, and that prevents updates of
python@3.

Remove the obsolete motivation for running (brew update), and replace it
with a similarly-good motivation that the Travis images are just too old
to be relevant to users.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-07-09 02:17:50 +02:00
Miloslav Trmač
ee72e803ec Merge pull request #969 from containers/dependabot/go_modules/github.com/containers/common-0.15.2
Bump github.com/containers/common from 0.15.1 to 0.15.2
2020-07-08 23:19:06 +02:00
dependabot-preview[bot]
142142c040 Bump github.com/containers/common from 0.15.1 to 0.15.2
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.15.1 to 0.15.2.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.15.1...v0.15.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-07-06 14:53:30 -04:00
Daniel J Walsh
6182aa30b1 Merge pull request #964 from alvistack/master-linux-amd64
nix run -f channel:nixos-20.03
2020-07-02 06:11:50 -04:00
Daniel J Walsh
ec9f8acf00 Merge pull request #967 from containers/dependabot/go_modules/github.com/containers/common-0.15.1
Bump github.com/containers/common from 0.14.3 to 0.15.1
2020-07-02 06:10:46 -04:00
dependabot-preview[bot]
52b3a5bacc Bump github.com/containers/common from 0.14.3 to 0.15.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.14.3 to 0.15.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.14.3...v0.15.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-01 20:59:28 +02:00
Miloslav Trmač
ac6b871f66 Merge pull request #966 from lumjjb/doc_Change
update enc/dec docs to be consistent with buildah
2020-07-01 20:52:49 +02:00
Brandon Lum
b17fb08f8b update enc/dec docs to be consistent with buildah
Signed-off-by: Brandon Lum <lumjjb@gmail.com>
2020-06-30 21:46:57 +00:00
Wong Hoi Sing Edison
dd2e70e9b7 nix run -f channel:nixos-20.03
Switch from nix `channel:nixpkgs-unstable` to `channel:nixos-20.03` for better stability.

Signed-off-by: Wong Hoi Sing Edison <hswong3i@gmail.com>
2020-06-29 12:07:46 +08:00
Miloslav Trmač
ba8cbf589b Merge pull request #963 from containers/dependabot/go_modules/github.com/containers/common-0.14.3
Bump github.com/containers/common from 0.14.0 to 0.14.3
2020-06-26 20:01:02 +02:00
dependabot-preview[bot]
91dc0f3f4c Bump github.com/containers/common from 0.14.0 to 0.14.3
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.14.0 to 0.14.3.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.14.0...v0.14.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-26 06:06:56 -04:00
Daniel J Walsh
7815c8ac6f Merge pull request #952 from rhatdan/build
Cleanup Dockerfile builds
2020-06-22 11:21:21 -04:00
Miloslav Trmač
233e61cf9a Merge pull request #960 from mtrmac/htpasswd
Run htpasswd from our build-container instead of registry:2
2020-06-22 15:23:03 +02:00
Miloslav Trmač
0e2611d3a6 Run htpasswd from our build-container instead of registry:2
registry:2 no longer contains htpasswd.

Also don't use log_and_run ... >> $file
because that will cause the command to be logged to $file.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-06-19 19:44:52 +02:00
Daniel J Walsh
96bd4a0619 Merge pull request #958 from rhatdan/VERSION
Bump to v1.1.0
2020-06-18 15:28:31 -04:00
Daniel J Walsh
6b78619cd1 Merge pull request #932 from alvistack/master-linux-amd64
[nix] Add nix derivation for static builds
2020-06-18 10:24:32 -04:00
Wong Hoi Sing Edison
0f458eec76 Add nix derivation for static builds
Signed-off-by: Wong Hoi Sing Edison <hswong3i@gmail.com>
2020-06-18 20:57:55 +08:00
Daniel J Walsh
6b960ec031 Cleanup Dockerfile builds
Add `-y` options to yum clean all
Only delete below /var/cache/dnf so that I can use the
-v /var/cache/dnf:/var/cache/dnf:O option when building
to speed up builds.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-17 17:22:58 -04:00
Daniel J Walsh
fdc58131f8 Move to v1.1.1-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-17 16:41:59 -04:00
Daniel J Walsh
63085f5bef Bump to v1.1.0
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-17 16:41:19 -04:00
Miloslav Trmač
091f9248dc Merge pull request #957 from vrothberg/vendor-image
vendor github.com/containers/image/v5@v5.5.1
2020-06-17 18:24:01 +02:00
Valentin Rothberg
dd7dd75334 vendor github.com/containers/image/v5@v5.5.1
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-06-17 17:25:15 +02:00
Valentin Rothberg
b70dfae2ae vendor github.com/containers/common v0.14.0
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-06-17 09:55:53 +02:00
Daniel J Walsh
0bd78a0604 Merge pull request #943 from containers/dependabot/go_modules/github.com/stretchr/testify-1.6.1
Bump github.com/stretchr/testify from 1.6.0 to 1.6.1
2020-06-16 05:35:48 -04:00
Daniel J Walsh
9e0839c33f Merge pull request #948 from containers/dependabot/go_modules/github.com/containers/common-0.13.1
Bump github.com/containers/common from 0.13.0 to 0.13.1
2020-06-16 05:34:09 -04:00
dependabot-preview[bot]
9bafa7e80d Bump github.com/containers/common from 0.13.0 to 0.13.1
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.13.0...v0.13.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-15 09:06:14 -04:00
Daniel J Walsh
827293a13b Merge pull request #946 from yuhuijiang/patch-1
Correct a typo in docs/skopeo-sync.1.md
2020-06-11 15:04:35 -04:00
Yuhui Jiang
6198daeb2c Correct a typo in docs/skopeo-sync.1.md
To disable TLS verification need to set "tls-verify" to "false"
2020-06-11 01:29:37 +08:00
Miloslav Trmač
161ef5a224 Merge pull request #945 from containers/dependabot/go_modules/github.com/containers/common-0.13.0
Bump github.com/containers/common from 0.12.0 to 0.13.0
2020-06-09 21:18:10 +02:00
dependabot-preview[bot]
9e99ad99d4 Bump github.com/containers/common from 0.12.0 to 0.13.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.12.0 to 0.13.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.12.0...v0.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-09 10:59:38 -04:00
dependabot-preview[bot]
c36502ce31 Bump github.com/stretchr/testify from 1.6.0 to 1.6.1
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.6.0...v1.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-08 16:10:50 -04:00
Daniel J Walsh
f9b0d93ee0 Merge pull request #938 from containers/dependabot/go_modules/github.com/containers/storage-1.20.2
Bump github.com/containers/storage from 1.20.1 to 1.20.2
2020-06-04 16:07:53 -04:00
dependabot-preview[bot]
4eaaf31249 Bump github.com/containers/storage from 1.20.1 to 1.20.2
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.20.1 to 1.20.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.20.1...v1.20.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-06-04 08:36:51 -04:00
Daniel J Walsh
c6b488a82c Merge pull request #934 from containers/dependabot/go_modules/github.com/containers/common-0.12.0
Bump github.com/containers/common from 0.11.4 to 0.12.0
2020-05-29 09:02:18 -04:00
Daniel J Walsh
7cfc62922f Merge pull request #935 from containers/dependabot/go_modules/github.com/stretchr/testify-1.6.0
Bump github.com/stretchr/testify from 1.5.1 to 1.6.0
2020-05-29 09:01:55 -04:00
dependabot-preview[bot]
5284f6d832 Bump github.com/stretchr/testify from 1.5.1 to 1.6.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.5.1...v1.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-29 05:56:22 -04:00
dependabot-preview[bot]
ae97c667e3 Bump github.com/containers/common from 0.11.4 to 0.12.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.11.4 to 0.12.0.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.11.4...v0.12.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-29 05:55:57 -04:00
Miloslav Trmač
a2c1d46302 Merge pull request #930 from TomSweeneyRedHat/dev/tsweeney/skopeoimage2
Add upstream and testing container images
2020-05-25 17:42:30 +02:00
Miloslav Trmač
8b4b954332 Fix error handling on invalid regex
Say that the regex is the cause, include it in the error message,
and don't continue as if the compilation succeeded.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
c103d65284 Drop redundant fmt.Sprintf inside erorrs.Wrapf/Errorf
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
c5183d0e34 Use MatchString instead of Match with a manual conversion
Should not change behavior AFAICT.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
16b435257b Use reference.Tagged to extract the tag from a reference
... instead of manually parsing strings.

Should not change behavior, except maybe error messages if the
registry returns invalid tags.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
35f3595d02 Inline isTagSpecified into its only caller
We already parsed the input string in the caller,
so this is much simpler.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
0ee81dc9fe Use a reference.Named, not types.ImageReference, in imagesToCopy
This removes another string formatting use, and removes the
last recently introduced docker.Reference->reference.Named
redundancy.

Should not change behavior, apart from error messages.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
805885091f Clarify imagesToCopy control flow
... and remove one duplicate line.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
97ec6873fa Work with a reference.Named, not strings, in imagesToCopyFromRegistry
We now notice earlier if the user uses a non-repository input.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
d16cd39939 Use a reference.Named, not types.ImageReference, in imagesToCopyFromRepo
Right now that only complicates code by going through a
types.ImageReference->reference.Named->types.ImageReference sequence,
but that will change as we modify the callers as well.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
7439f94e22 Remove the repoReference parameter of imagesToCopyFromRepo
It is redundant, only used to form a tagged reference,
which can be done more safely using reference.WithTag.

Also move the *types.SystemContext parameter to the front,
as is usual.

Should not change behavior, apart from a few error messages.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
443380731e Don't use path.Join to form repository names
path.Join runs path.Clean, which interprets / and . and .. .

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
56c6325ba0 Share the logrus.WithFields settings over the loop bodies
to avoid the maddening repetitivenes.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
0ae9db5dd6 Clarify control flow when handling the tags list
Don't run the the "tags specified" loop when
tags should be discovered.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
677c29bf24 Only create a SystemContext once per registry
... because it does not change with each repository.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
72376c4144 Fix the recently added example in the man page.
- Improve the language
- Be consistent with the previous example about a trailing slash
- Don't unnecessarily quote :, it is not a shell metacharacter.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
Miloslav Trmač
322625eeca Use a separate field for the "sync images with tag matching regex" feature
Fields that magically change their behavior depending on type of the value
are too much hassle for no benefit.

For now, this just copies&pastes the full loop in imagesToCopyFromRegistry
to create another loop handling the new ImagesByTagRegex field. Simplifications
to reduce duplication will follow.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-25 11:58:19 +02:00
TomSweeneyRedHat
9c1936fd07 Add upstream and testing container images
This PR adds the Dockerfiles necessary to create the upstream
and testing variants of the Skopeo container images that will
reside in quay.io/skopeo/upstream and quay.io/skopeo/testing
repositories.  The only difference in the Dockerfile between
the stable and testing image is the option `--enablerepo updates-testing`
was added.  The testing variant is relatively the same, but
I'd to clone and install Skopeo in the container.

I've also added a README.md which explains all of the varities
of images and includes some sample usage.

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2020-05-23 18:04:49 -04:00
Daniel J Walsh
3a94432e42 Merge pull request #926 from containers/dependabot/go_modules/github.com/containers/storage-1.20.1
Bump github.com/containers/storage from 1.19.2 to 1.20.1
2020-05-23 05:53:22 -04:00
Daniel J Walsh
ce1f807aa0 Merge pull request #929 from containers/dependabot/go_modules/github.com/containers/common-0.11.4
Bump github.com/containers/common from 0.11.2 to 0.11.4
2020-05-23 05:52:59 -04:00
dependabot-preview[bot]
a51af64dd9 Bump github.com/containers/storage from 1.19.2 to 1.20.1
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.19.2 to 1.20.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.19.2...v1.20.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-22 13:36:27 -04:00
dependabot-preview[bot]
a31d6069dc Bump github.com/containers/common from 0.11.2 to 0.11.4
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.11.2 to 0.11.4.
- [Release notes](https://github.com/containers/common/releases)
- [Commits](https://github.com/containers/common/compare/v0.11.2...v0.11.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-22 13:35:57 -04:00
Miloslav Trmač
96353f2b64 Merge pull request #925 from GETandSELECT/master
there is a brew formula for skopeo
2020-05-21 19:14:34 +02:00
Kargins
2330455c8d there is a brew formula for skopeo 2020-05-21 07:56:35 +02:00
Daniel J Walsh
91a88de6a1 Merge pull request #919 from TomSweeneyRedHat/dev/tsweeney/quay
Add Skopeo Stable Image Dockerfile for Quay
2020-05-20 12:53:30 -04:00
Daniel J Walsh
2afe7a3e1e Merge pull request #920 from zhangguanzhang/master
Add tags to support regular expressions without breaking the old ones in yaml conf
2020-05-20 12:52:27 -04:00
zhangguanzhang
bec7f6977e Add tags to support regular expressions in yaml conf
add relevant test cases and documentation
update the sync doc
2020-05-20 09:23:00 +08:00
TomSweeneyRedHat
60ecaffbe8 Add Skopeo Stable Image Dockerfile for Quay
Adds the Dockerfile for building the Skopeo container
image on quay.io.  Once merged, this image will be
built automatically upon any merge into the master
branch.  The images will live at:
quay.io/containers/skopeo:latest
quay.io/skopeo/stable:latest

I've built an image using this Dockerfile and have pushed
it to both repositories if you want to play with that.

Once merged, I'll create similar Dockerfiles for
quay.io/skopeo/testing and quay.io/skopeo/upstream.

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2020-05-19 17:54:02 -04:00
Daniel J Walsh
dcaee948d3 Merge pull request #915 from rhatdan/VERSION
Bump to v1.0.0
2020-05-18 14:14:14 -04:00
Daniel J Walsh
2fe7087d52 Move to v1.0.1-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-18 13:23:09 -04:00
Daniel J Walsh
bd162028cd Bump to v1.0.0
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-18 13:23:09 -04:00
Daniel J Walsh
a214a305fd Merge pull request #917 from rhatdan/readme
Update skopeo readme and man page
2020-05-18 13:22:37 -04:00
Daniel J Walsh
5093d5b5f6 Update skopeo readme and man page
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-18 13:21:50 -04:00
Daniel J Walsh
0d9939dcd4 Merge pull request #914 from rhatdan/man
Add links to configuration man pages
2020-05-15 07:43:38 -04:00
Daniel J Walsh
1b2de8ec5d Update docs/skopeo-sync.1.md
Co-authored-by: Miloslav Trmač <mitr@redhat.com>
2020-05-15 07:42:54 -04:00
Daniel J Walsh
ab2300500a Add links to configuration man pages
Help users discover additonal man pages by completing
SEE ALSO section.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-14 15:38:34 -04:00
Daniel J Walsh
fbf061260c Merge pull request #913 from containers/dependabot/go_modules/github.com/opencontainers/go-digest-1.0.0
Bump github.com/opencontainers/go-digest from 1.0.0-rc1 to 1.0.0
2020-05-14 07:17:53 -04:00
dependabot-preview[bot]
4244d68240 Bump github.com/opencontainers/go-digest from 1.0.0-rc1 to 1.0.0
Bumps [github.com/opencontainers/go-digest](https://github.com/opencontainers/go-digest) from 1.0.0-rc1 to 1.0.0.
- [Release notes](https://github.com/opencontainers/go-digest/releases)
- [Commits](https://github.com/opencontainers/go-digest/compare/v1.0.0-rc1...v1.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-14 06:42:55 -04:00
Daniel J Walsh
dda31b3d4b Merge pull request #911 from containers/dependabot/go_modules/github.com/containers/storage-1.19.2
Bump github.com/containers/storage from 1.19.1 to 1.19.2
2020-05-14 06:42:02 -04:00
Miloslav Trmač
2af172653c Merge pull request #912 from containers/dependabot/go_modules/gopkg.in/yaml.v2-2.3.0
Bump gopkg.in/yaml.v2 from 2.2.8 to 2.3.0
2020-05-14 01:07:01 +02:00
dependabot-preview[bot]
3247c0d229 Bump gopkg.in/yaml.v2 from 2.2.8 to 2.3.0
Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.2.8 to 2.3.0.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.2.8...v2.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-13 15:57:23 -04:00
dependabot-preview[bot]
eb024319de Bump github.com/containers/storage from 1.19.1 to 1.19.2
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.19.1 to 1.19.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.19.1...v1.19.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-13 15:51:11 -04:00
Miloslav Trmač
4ca9b139bb Merge pull request #865 from QiWang19/login
Add skopeo Login from c/common
2020-05-12 01:54:12 +02:00
Qi Wang
b79a37ead9 v0.11.2 containers/common
Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-05-11 17:07:26 -04:00
Qi Wang
0ec2610f04 Add skopeo login&logout
Implements skopeo login&logout commands.

Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-05-11 16:35:46 -04:00
Daniel J Walsh
71a14d7df6 Merge pull request #910 from mtrmac/update-c-image
Update containers/image to v5.4.4
2020-05-11 14:26:43 -04:00
Daniel J Walsh
8936e76316 Merge pull request #909 from TomSweeneyRedHat/sec1
Add Security Policy
2020-05-11 11:03:43 -04:00
Miloslav Trmač
e21d6b3687 Update containers/image to v5.4.4
Only bumps the version number after the recent vendoring
from master, but Dependabot seems to be confused by that;
so, update to the final release to hopefully un-confuse it.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-11 15:54:04 +02:00
Miloslav Trmač
a6ab2291ba Add tests for using signatures with mirrors
... to test the fix for https://github.com/containers/image/pull/912 .

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-11 14:37:43 +02:00
Miloslav Trmač
8f845aac23 Update c/image for https://github.com/containers/image/pull/912
This is an unreleased version of c/image, but it is important to
to have the test added in in the next commit enforcing as soon as
possible.

> go get github.com/containers/image/v5@HEAD
> make vendor

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-11 14:37:43 +02:00
TomSweeneyRedHat
439ea83081 Add Security Policy
As the title says.

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
2020-05-09 18:10:29 -04:00
Daniel J Walsh
42f68c1c76 Merge pull request #908 from wushuyi/fix-doc
fix copy doc
2020-05-09 06:08:36 -04:00
wushuyi
8d252f82fd fix copy doc 2020-05-09 07:50:40 +08:00
Miloslav Trmač
1ddb736b5a Merge pull request #857 from QiWang19/cli
Use cobra in skopeo
2020-05-06 00:21:43 +02:00
Qi Wang
46fbbbd282 Use cobra in skopeo
Use cobra in skopeo can help share code with podman/buildah(code for skopeo login/logout CLI).
(libpod issue  #839)

Signed-off-by: Qi Wang <qiwan@redhat.com>
2020-05-04 14:50:15 -04:00
Daniel J Walsh
e7a7f018bd Merge pull request #903 from mtrmac/atomic-test-fix
Fix TestCopyAtomicExtension
2020-05-04 11:35:11 -04:00
Daniel J Walsh
311fc89548 Merge pull request #906 from containers/dependabot/go_modules/github.com/sirupsen/logrus-1.6.0
Bump github.com/sirupsen/logrus from 1.5.0 to 1.6.0
2020-05-04 11:33:30 -04:00
dependabot-preview[bot]
a6abdb8547 Bump github.com/sirupsen/logrus from 1.5.0 to 1.6.0
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.5.0...v1.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-05-04 08:35:48 -04:00
Miloslav Trmač
02407d98a5 Fix TestCopyAtomicExtension
Actually test that X-R-S-S signatures are usable using atomic:,
as the comment says.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2020-05-01 01:27:03 +02:00
Miloslav Trmač
b230a507e7 Merge pull request #899 from containers/dependabot/go_modules/github.com/containers/storage-1.19.0
Bump github.com/containers/storage from 1.18.2 to 1.19.0
2020-04-25 01:56:55 +02:00
dependabot-preview[bot]
116add9d00 Bump github.com/containers/storage from 1.18.2 to 1.19.0
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.18.2 to 1.19.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.18.2...v1.19.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-20 09:55:15 -04:00
Daniel J Walsh
2415f3fa4d Merge pull request #886 from rhatdan/master
Bump to v0.2.0
2020-04-09 15:11:11 -04:00
Daniel J Walsh
5f8d3fc639 Move to v0.2.1-dev
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2020-04-09 08:51:38 -04:00
1999 changed files with 221703 additions and 73321 deletions

150
.cirrus.yml Normal file
View File

@@ -0,0 +1,150 @@
---
# Main collection of env. vars to set for all tasks and scripts.
env:
####
#### Global variables used for all tasks
####
# Name of the ultimate destination branch for this CI run, PR or post-merge.
DEST_BRANCH: "main"
# Overrides default location (/tmp/cirrus) for repo clone
GOPATH: &gopath "/var/tmp/go"
GOBIN: "${GOPATH}/bin"
GOCACHE: "${GOPATH}/cache"
GOSRC: &gosrc "/var/tmp/go/src/github.com/containers/skopeo"
# Required for consistency with containers/image CI
SKOPEO_PATH: *gosrc
CIRRUS_WORKING_DIR: *gosrc
# The default is 'sh' if unspecified
CIRRUS_SHELL: "/bin/bash"
# Save a little typing (path relative to $CIRRUS_WORKING_DIR)
SCRIPT_BASE: "./contrib/cirrus"
####
#### Cache-image names to test with (double-quotes around names are critical)
####
FEDORA_NAME: "fedora-34"
PRIOR_FEDORA_NAME: "fedora-33"
UBUNTU_NAME: "ubuntu-2104"
PRIOR_UBUNTU_NAME: "ubuntu-2010"
# Google-cloud VM Images
IMAGE_SUFFIX: "c6032583541653504"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
PRIOR_UBUNTU_CACHE_IMAGE_NAME: "prior-ubuntu-${IMAGE_SUFFIX}"
# Container FQIN's
FEDORA_CONTAINER_FQIN: "quay.io/libpod/fedora_podman:${IMAGE_SUFFIX}"
PRIOR_FEDORA_CONTAINER_FQIN: "quay.io/libpod/prior-fedora_podman:${IMAGE_SUFFIX}"
UBUNTU_CONTAINER_FQIN: "quay.io/libpod/ubuntu_podman:${IMAGE_SUFFIX}"
PRIOR_UBUNTU_CONTAINER_FQIN: "quay.io/libpod/prior-ubuntu_podman:${IMAGE_SUFFIX}"
# Equivilent to image produced by 'make build-container'
SKOPEO_CI_CONTAINER_FQIN: "quay.io/skopeo/ci:${DEST_BRANCH}"
# Default timeout for each task
timeout_in: 45m
gcp_credentials: ENCRYPTED[52d9e807b531b37ab14e958cb5a72499460663f04c8d73e22ad608c027a31118420f1c80f0be0882fbdf96f49d8f9ac0]
validate_task:
# The git-validation tool doesn't work well on branch or tag push,
# under Cirrus-CI, due to challenges obtaining the starting commit ID.
# Only do validation for PRs.
only_if: $CIRRUS_PR != ''
container: &build_container
image: "${SKOPEO_CI_CONTAINER_FQIN}"
cpu: 4
memory: 8
script: make validate-local
#####
##### NOTE: This task is subtantially duplicated in the containers/image
##### repository's `.cirrus.yml`. Changes made here should be fully merged
##### prior to being manually duplicated and maintained in containers/image.
#####
test_skopeo_task:
alias: test_skopeo
depends_on:
- validate
gce_instance:
image_project: libpod-218412
zone: "us-central1-f"
cpu: 2
memory: "4Gb"
# Required to be 200gig, do not modify - has i/o performance impact
# according to gcloud CLI tool warning messages.
disk: 200
image_name: ${FEDORA_CACHE_IMAGE_NAME}
matrix:
- name: "Skopeo Test"
env:
BUILDTAGS: 'btrfs_noversion libdm_no_deferred_remove'
- name: "Skopeo Test w/ opengpg"
env:
BUILDTAGS: 'btrfs_noversion libdm_no_deferred_remove containers_image_openpgp'
setup_script: >-
"${GOSRC}/${SCRIPT_BASE}/runner.sh" setup
vendor_script: >-
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" vendor
build_script: >-
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" build
validate_script: >-
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" validate
unit_script: >-
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" unit
integration_script: >-
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" integration
system_script: >
"${SKOPEO_PATH}/${SCRIPT_BASE}/runner.sh" system
# This task is critical. It updates the "last-used by" timestamp stored
# in metadata for all VM images. This mechanism functions in tandem with
# an out-of-band pruning operation to remove disused VM images.
meta_task:
name: "VM img. keepalive"
alias: meta
container: &smallcontainer
cpu: 2
memory: 2
image: quay.io/libpod/imgts:latest
env:
# Space-separated list of images used by this repository state
IMGNAMES: >-
${FEDORA_CACHE_IMAGE_NAME}
${PRIOR_FEDORA_CACHE_IMAGE_NAME}
${UBUNTU_CACHE_IMAGE_NAME}
${PRIOR_UBUNTU_CACHE_IMAGE_NAME}
BUILDID: "${CIRRUS_BUILD_ID}"
REPOREF: "${CIRRUS_REPO_NAME}"
GCPJSON: ENCRYPTED[6867b5a83e960e7c159a98fe6c8360064567a071c6f4b5e7d532283ecd870aa65c94ccd74bdaa9bf7aadac9d42e20a67]
GCPNAME: ENCRYPTED[1cf558ae125e3c39ec401e443ad76452b25d790c45eb73d77c83eb059a0f7fd5085ef7e2f7e410b04ea6e83b0aab2eb1]
GCPPROJECT: libpod-218412
clone_script: &noop mkdir -p "$CIRRUS_WORKING_DIR"
script: /usr/local/bin/entrypoint.sh
# Status aggregator for all tests. This task simply ensures a defined
# set of tasks all passed, and allows confirming that based on the status
# of this task.
success_task:
name: "Total Success"
alias: success
# N/B: ALL tasks must be listed here, minus their '_task' suffix.
depends_on:
- validate
- test_skopeo
- meta
container: *smallcontainer
env:
CTR_FQIN: ${FEDORA_CONTAINER_FQIN}
TEST_ENVIRON: container
clone_script: *noop
script: /bin/true

10
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
time: "10:00"
timezone: Europe/Berlin
open-pull-requests-limit: 10

25
.github/workflow/stale.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Mark stale issues and pull requests
# Please refer to https://github.com/actions/stale/blob/master/action.yml
# to see all config knobs of the stale action.
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'A friendly reminder that this issue had no activity for 30 days.'
stale-pr-message: 'A friendly reminder that this PR had no activity for 30 days.'
stale-issue-label: 'stale-issue'
stale-pr-label: 'stale-pr'
days-before-stale: 30
days-before-close: 365
remove-stale-when-updated: true

6
.gitignore vendored
View File

@@ -1,6 +1,10 @@
*.1
/layers-*
/skopeo
result
# ignore JetBrains IDEs (GoLand) config folder
.idea
.idea
# Ignore the bin directory
bin

View File

@@ -1,28 +1,75 @@
language: go
matrix:
include:
- os: linux
sudo: required
services:
- docker
- os: osx
go:
- 1.13.x
- 1.15.x
notifications:
email: false
install:
# NOTE: The (brew update) should not be necessary, and slows things down;
# we include it as a workaround for https://github.com/Homebrew/brew/issues/3299
# ideally Travis should bake the (brew update) into its images
# (https://github.com/travis-ci/travis-ci/issues/8552 ), but thats only going
# to happen around November 2017 per https://blog.travis-ci.com/2017-10-16-a-new-default-os-x-image-is-coming .
# Remove the (brew update) at that time.
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install gpgme ; fi
env:
global:
# Multiarch manifest will support architectures from this list. It should be the same architectures, as ones in image-build-push step in this Travis config
- MULTIARCH_MANIFEST_ARCHITECTURES="amd64 s390x ppc64le"
# env variables for stable image build
- STABLE_IMAGE=quay.io/skopeo/stable:v1.2.0
- EXTRA_STABLE_IMAGE=quay.io/containers/skopeo:v1.2.0
# env variable for upstream image build
- UPSTREAM_IMAGE=quay.io/skopeo/upstream:master
script:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then hack/travis_osx.sh ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make vendor && ./hack/tree_status.sh && make check ; fi
# Just declaration of the image-build-push step with script actions to execute
x_base_steps:
- &image-build-push
services:
- docker
os: linux
dist: focal
script:
# skopeo upstream image build
- make -f release/Makefile build-image/upstream
# Push image in case if build is started via cron job or code is pushed to master
- if [ "$TRAVIS_EVENT_TYPE" == "push" ] || [ "$TRAVIS_EVENT_TYPE" == "cron" ]; then
make -f release/Makefile push-image/upstream ;
fi
# skopeo stable image build
- make -f release/Makefile build-image/stable
# Push image in case if build is started via cron job or code is pushed to master
- if [ "$TRAVIS_EVENT_TYPE" == "push" ] || [ "$TRAVIS_EVENT_TYPE" == "cron" ]; then
make -f release/Makefile push-image/stable ;
fi
# Just declaration of stage order to run
stages:
# Build and push image for 1 architecture
- name: image-build-push
if: branch = master
# Create and push image manifest to have multiarch image on top of architecture specific images
- name: manifest-multiarch-push
if: (type IN (push, cron)) AND branch = master
# Actual execution of steps
jobs:
include:
# Run 3 image-build-push tasks in parallel for linux/amd64, linux/s390x and linux/ppc64le platforms (for upstream and stable)
- stage: image-build-push
<<: *image-build-push
name: images for amd64
arch: amd64
- stage: image-build-push
<<: *image-build-push
name: images for s390x
arch: s390x
- stage: image-build-push
<<: *image-build-push
name: images for ppc64le
arch: ppc64le
# Run final task to generate multi-arch image manifests (for upstream and stable)
- stage: manifest-multiarch-push
os: linux
dist: focal
script:
- make -f release/Makefile push-manifest-multiarch/upstream
- make -f release/Makefile push-manifest-multiarch/stable

View File

@@ -134,7 +134,7 @@ When new PRs for [containers/image](https://github.com/containers/image) break `
- create out a new branch in your `skopeo` checkout and switch to it
- update `vendor.conf`. Find out the `containers/image` dependency; update it to vendor from your own branch and your own repository fork (e.g. `github.com/containers/image my-branch https://github.com/runcom/image`)
- run `make vendor`
- make any other necessary changes in the skopeo repo (e.g. add other dependencies now requied by `containers/image`, or update skopeo for changed `containers/image` API)
- make any other necessary changes in the skopeo repo (e.g. add other dependencies now required by `containers/image`, or update skopeo for changed `containers/image` API)
- optionally add new integration tests to the skopeo repo
- submit the resulting branch as a skopeo PR, marked “DO NOT MERGE”
- iterate until tests pass and the PR is reviewed
@@ -142,7 +142,7 @@ When new PRs for [containers/image](https://github.com/containers/image) break `
- as soon as possible after that, in the skopeo PR, restore the `containers/image` line in `vendor.conf` to use `containers/image:master`
- run `make vendor`
- update the skopeo PR with the result, drop the “DO NOT MERGE” marking
- after tests complete succcesfully again, merge the skopeo PR
- after tests complete successfully again, merge the skopeo PR
## Communications

View File

@@ -7,10 +7,13 @@ RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-md2ma
# gpgme bindings deps
libassuan-devel gpgme-devel \
gnupg \
# htpasswd for system tests
httpd-tools \
# 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 runc \
golint \
openssl \
&& dnf clean all
# Install two versions of the registry. The first is an older version that
@@ -18,6 +21,7 @@ RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-md2ma
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
RUN set -x \
&& export GO111MODULE=off \
&& REGISTRY_COMMIT_SCHEMA1=ec87e9b6971d831f0eff752ddb54fb64693e51cd \
&& REGISTRY_COMMIT=47a064d4195a9b56133891bbb13620c3ac83a827 \
&& export GOPATH="$(mktemp -d)" \
@@ -31,6 +35,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
RUN set -x \
&& export GO111MODULE=off \
&& export GOPATH=$(mktemp -d) \
&& git clone --depth 1 -b v1.5.0-alpha.3 git://github.com/openshift/origin "$GOPATH/src/github.com/openshift/origin" \
# The sed edits out a "go < 1.5" check which works incorrectly with go ≥ 1.10. \
@@ -43,6 +48,7 @@ RUN set -x \
ENV GOPATH /usr/share/gocode:/go
ENV PATH $GOPATH/bin:/usr/share/gocode/bin:$PATH
ENV container_magic 85531765-346b-4316-bdb8-358e4cca9e5d
RUN go version
WORKDIR /go/src/github.com/containers/skopeo
COPY . /go/src/github.com/containers/skopeo

View File

@@ -1,13 +1,12 @@
FROM ubuntu:19.10
FROM registry.fedoraproject.org/fedora:33
RUN apt-get update && apt-get install -y \
golang \
libbtrfs-dev \
git-core \
libdevmapper-dev \
libgpgme11-dev \
go-md2man \
libglib2.0-dev
RUN dnf update -y && \
dnf install -y \
btrfs-progs-devel \
device-mapper-devel \
golang \
gpgme-devel \
make
ENV GOPATH=/
WORKDIR /src/github.com/containers/skopeo

120
Makefile
View File

@@ -2,33 +2,37 @@
export GOPROXY=https://proxy.golang.org
ifeq ($(shell uname),Darwin)
PREFIX ?= ${DESTDIR}/usr/local
DARWIN_BUILD_TAG=
# On macOS, (brew install gpgme) installs it within /usr/local, but /usr/local/include is not in the default search path.
# Rather than hard-code this directory, use gpgme-config. Sadly that must be done at the top-level user
# instead of locally in the gpgme subpackage, because cgo supports only pkg-config, not general shell scripts,
# and gpgme does not install a pkg-config file.
# On some plaforms (eg. macOS, FreeBSD) gpgme is installed in /usr/local/ but /usr/local/include/ is
# not in the default search path. Rather than hard-code this directory, use gpgme-config.
# Sadly that must be done at the top-level user instead of locally in the gpgme subpackage, because cgo
# supports only pkg-config, not general shell scripts, and gpgme does not install a pkg-config file.
# If gpgme is not installed or gpgme-config cant be found for other reasons, the error is silently ignored
# (and the user will probably find out because the cgo compilation will fail).
GPGME_ENV := CGO_CFLAGS="$(shell gpgme-config --cflags 2>/dev/null)" CGO_LDFLAGS="$(shell gpgme-config --libs 2>/dev/null)"
else
PREFIX ?= ${DESTDIR}/usr
endif
INSTALLDIR=${PREFIX}/bin
MANINSTALLDIR=${PREFIX}/share/man
CONTAINERSSYSCONFIGDIR=${DESTDIR}/etc/containers
REGISTRIESDDIR=${CONTAINERSSYSCONFIGDIR}/registries.d
SIGSTOREDIR=${DESTDIR}/var/lib/containers/sigstore
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
# Normally empty, DESTDIR can be used to relocate the entire install-tree
DESTDIR ?=
CONTAINERSCONFDIR ?= ${DESTDIR}/etc/containers
REGISTRIESDDIR ?= ${CONTAINERSCONFDIR}/registries.d
SIGSTOREDIR ?= ${DESTDIR}/var/lib/containers/sigstore
PREFIX ?= ${DESTDIR}/usr/local
BINDIR ?= ${PREFIX}/bin
MANDIR ?= ${PREFIX}/share/man
BASHCOMPLETIONSDIR ?= ${PREFIX}/share/bash-completion/completions
GO ?= go
GOBIN := $(shell $(GO) env GOBIN)
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
ifeq ($(GOBIN),)
GOBIN := $(GOPATH)/bin
endif
# Required for integration-tests to detect they are running inside a specific
# container image. Env. var defined in image, make does not automatically
# pass to children unless explicitly exported
export container_magic
CONTAINER_RUNTIME := $(shell command -v podman 2> /dev/null || echo docker)
GOMD2MAN ?= $(shell command -v go-md2man || echo '$(GOBIN)/go-md2man')
@@ -43,8 +47,10 @@ ifeq ($(DEBUG), 1)
override GOGCFLAGS += -N -l
endif
ifeq ($(shell $(GO) env GOOS), linux)
GO_DYN_FLAGS="-buildmode=pie"
ifeq ($(GOOS), linux)
ifneq ($(GOARCH),$(filter $(GOARCH),mips mipsle mips64 mips64le ppc64 riscv64))
GO_DYN_FLAGS="-buildmode=pie"
endif
endif
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
@@ -62,12 +68,15 @@ CONTAINER_RUN := $(CONTAINER_CMD) "$(IMAGE)"
GIT_COMMIT := $(shell git rev-parse HEAD 2> /dev/null || true)
EXTRA_LDFLAGS ?=
SKOPEO_LDFLAGS := -ldflags '-X main.gitCommit=${GIT_COMMIT} $(EXTRA_LDFLAGS)'
MANPAGES_MD = $(wildcard docs/*.md)
MANPAGES ?= $(MANPAGES_MD:%.md=%)
BTRFS_BUILD_TAG = $(shell hack/btrfs_tag.sh) $(shell hack/btrfs_installed_tag.sh)
LIBDM_BUILD_TAG = $(shell hack/libdm_tag.sh)
LOCAL_BUILD_TAGS = $(BTRFS_BUILD_TAG) $(LIBDM_BUILD_TAG) $(DARWIN_BUILD_TAG)
LOCAL_BUILD_TAGS = $(BTRFS_BUILD_TAG) $(LIBDM_BUILD_TAG)
BUILDTAGS += $(LOCAL_BUILD_TAGS)
ifeq ($(DISABLE_CGO), 1)
@@ -78,14 +87,17 @@ endif
# Note: Uses the -N -l go compiler options to disable compiler optimizations
# and inlining. Using these build options allows you to subsequently
# use source debugging tools like delve.
all: binary docs-in-container
all: bin/skopeo docs
help:
@echo "Usage: make <target>"
@echo
@echo "Defaults to building bin/skopeo and docs"
@echo
@echo " * 'install' - Install binaries and documents to system locations"
@echo " * 'binary' - Build skopeo with a container"
@echo " * 'binary-local' - Build skopeo locally"
@echo " * 'static' - Build statically linked binary"
@echo " * 'bin/skopeo' - Build skopeo locally"
@echo " * 'test-unit' - Execute unit tests"
@echo " * 'test-integration' - Execute integration tests"
@echo " * 'validate' - Verify whether there is no conflict and all Go source files have been formatted, linted and vetted"
@@ -98,25 +110,37 @@ help:
binary: cmd/skopeo
${CONTAINER_RUNTIME} build ${BUILD_ARGS} -f Dockerfile.build -t skopeobuildimage .
${CONTAINER_RUNTIME} run --rm --security-opt label=disable -v $$(pwd):/src/github.com/containers/skopeo \
skopeobuildimage make binary-local $(if $(DEBUG),DEBUG=$(DEBUG)) BUILDTAGS='$(BUILDTAGS)'
skopeobuildimage make bin/skopeo $(if $(DEBUG),DEBUG=$(DEBUG)) BUILDTAGS='$(BUILDTAGS)'
binary-static: cmd/skopeo
${CONTAINER_RUNTIME} build ${BUILD_ARGS} -f Dockerfile.build -t skopeobuildimage .
${CONTAINER_RUNTIME} run --rm --security-opt label=disable -v $$(pwd):/src/github.com/containers/skopeo \
skopeobuildimage make binary-local-static $(if $(DEBUG),DEBUG=$(DEBUG)) BUILDTAGS='$(BUILDTAGS)'
# Update nix/nixpkgs.json its latest stable commit
.PHONY: nixpkgs
nixpkgs:
@nix run \
-f channel:nixos-20.09 nix-prefetch-git \
-c nix-prefetch-git \
--no-deepClone \
https://github.com/nixos/nixpkgs refs/heads/nixos-20.09 > nix/nixpkgs.json
# Build statically linked binary
.PHONY: static
static:
@nix build -f nix/
mkdir -p ./bin
cp -rfp ./result/bin/* ./bin/
# Build w/o using containers
binary-local:
$(GPGME_ENV) $(GO) build $(MOD_VENDOR) ${GO_DYN_FLAGS} -ldflags "-X main.gitCommit=${GIT_COMMIT}" -gcflags "$(GOGCFLAGS)" -tags "$(BUILDTAGS)" -o skopeo ./cmd/skopeo
binary-local-static:
$(GPGME_ENV) $(GO) build $(MOD_VENDOR) -ldflags "-extldflags \"-static\" -X main.gitCommit=${GIT_COMMIT}" -gcflags "$(GOGCFLAGS)" -tags "$(BUILDTAGS)" -o skopeo ./cmd/skopeo
.PHONY: bin/skopeo
bin/skopeo:
$(GPGME_ENV) $(GO) build $(MOD_VENDOR) ${GO_DYN_FLAGS} ${SKOPEO_LDFLAGS} -gcflags "$(GOGCFLAGS)" -tags "$(BUILDTAGS)" -o $@ ./cmd/skopeo
bin/skopeo.%:
GOOS=$(word 2,$(subst ., ,$@)) GOARCH=$(word 3,$(subst ., ,$@)) $(GO) build $(MOD_VENDOR) ${SKOPEO_LDFLAGS} -tags "containers_image_openpgp $(BUILDTAGS)" -o $@ ./cmd/skopeo
local-cross: bin/skopeo.darwin.amd64 bin/skopeo.linux.arm bin/skopeo.linux.arm64 bin/skopeo.windows.386.exe bin/skopeo.windows.amd64.exe
build-container:
${CONTAINER_RUNTIME} build ${BUILD_ARGS} -t "$(IMAGE)" .
$(MANPAGES): %: %.md
@sed -e 's/\((skopeo.*\.md)\)//' -e 's/\[\(skopeo.*\)\]/\1/' $< | $(GOMD2MAN) -in /dev/stdin -out $@
sed -e 's/\((skopeo.*\.md)\)//' -e 's/\[\(skopeo.*\)\]/\1/' $< | $(GOMD2MAN) -in /dev/stdin -out $@
docs: $(MANPAGES)
@@ -126,26 +150,26 @@ docs-in-container:
skopeobuildimage make docs $(if $(DEBUG),DEBUG=$(DEBUG)) BUILDTAGS='$(BUILDTAGS)'
clean:
rm -f skopeo docs/*.1
rm -rf bin docs/*.1
install: install-binary install-docs install-completions
install -d -m 755 ${SIGSTOREDIR}
install -d -m 755 ${CONTAINERSSYSCONFIGDIR}
install -m 644 default-policy.json ${CONTAINERSSYSCONFIGDIR}/policy.json
install -d -m 755 ${CONTAINERSCONFDIR}
install -m 644 default-policy.json ${CONTAINERSCONFDIR}/policy.json
install -d -m 755 ${REGISTRIESDDIR}
install -m 644 default.yaml ${REGISTRIESDDIR}/default.yaml
install-binary: ./skopeo
install -d -m 755 ${INSTALLDIR}
install -m 755 skopeo ${INSTALLDIR}/skopeo
install-binary: bin/skopeo
install -d -m 755 ${BINDIR}
install -m 755 bin/skopeo ${BINDIR}/skopeo
install-docs: docs
install -d -m 755 ${MANINSTALLDIR}/man1
install -m 644 docs/*.1 ${MANINSTALLDIR}/man1/
install -d -m 755 ${MANDIR}/man1
install -m 644 docs/*.1 ${MANDIR}/man1
install-completions:
install -m 755 -d ${BASHINSTALLDIR}
install -m 644 completions/bash/skopeo ${BASHINSTALLDIR}/skopeo
install -m 755 -d ${BASHCOMPLETIONSDIR}
install -m 644 completions/bash/skopeo ${BASHCOMPLETIONSDIR}/skopeo
shell: build-container
$(CONTAINER_RUN) bash
@@ -154,7 +178,11 @@ check: validate test-unit test-integration test-system
# The tests can run out of entropy and block in containers, so replace /dev/random.
test-integration: build-container
$(CONTAINER_RUN) bash -c 'rm -f /dev/random; ln -sf /dev/urandom /dev/random; SKOPEO_CONTAINER_TESTS=1 BUILDTAGS="$(BUILDTAGS)" hack/make.sh test-integration'
$(CONTAINER_RUN) bash -c 'rm -f /dev/random; ln -sf /dev/urandom /dev/random; SKOPEO_CONTAINER_TESTS=1 BUILDTAGS="$(BUILDTAGS)" $(MAKE) test-integration-local'
# Intended for CI, shortcut 'build-container' since already running inside container.
test-integration-local:
hack/make.sh test-integration
# complicated set of options needed to run podman-in-podman
test-system: build-container
@@ -162,11 +190,15 @@ test-system: build-container
$(CONTAINER_CMD) --privileged \
-v $$DTEMP:/var/lib/containers:Z -v /run/systemd/journal/socket:/run/systemd/journal/socket \
"$(IMAGE)" \
bash -c 'BUILDTAGS="$(BUILDTAGS)" hack/make.sh test-system'; \
bash -c 'BUILDTAGS="$(BUILDTAGS)" $(MAKE) test-system-local'; \
rc=$$?; \
$(RM) -rf $$DTEMP; \
exit $$rc
# Intended for CI, shortcut 'build-container' since already running inside container.
test-system-local:
hack/make.sh test-system
test-unit: build-container
# Just call (make test unit-local) here instead of worrying about environment differences
$(CONTAINER_RUN) make test-unit-local BUILDTAGS='$(BUILDTAGS)'

208
README.md
View File

@@ -7,29 +7,34 @@ skopeo [![Build Status](https://travis-ci.org/containers/skopeo.svg?branch=maste
`skopeo` is a command line utility that performs various operations on container images and image repositories.
`skopeo` does not require the user to be running as root to do most of its operations.
`skopeo` does not require a daemon to be running to perform its operations.
`skopeo` can work with [OCI images](https://github.com/opencontainers/image-spec) as well as the original Docker v2 images.
Skopeo works with API V2 registries such as Docker registries, the Atomic registry, private registries, local directories and local OCI-layout directories. Skopeo does not require a daemon to be running to perform these operations which consist of:
Skopeo works with API V2 container image registries such as [docker.io](https://docker.io) and [quay.io](https://quay.io) registries, private registries, local directories and local OCI-layout directories. Skopeo can perform operations which consist of:
* Copying an image from and to various storage mechanisms.
For example you can copy images from one registry to another, without requiring privilege.
* Inspecting a remote image showing its properties including its layers, without requiring you to pull the image to the host.
* Deleting an image from an image repository.
* Syncing an external image repository to an internal registry for air-gapped deployments.
* When required by the repository, skopeo can pass the appropriate credentials and certificates for authentication.
Skopeo operates on the following image and repository types:
* containers-storage:docker-reference
An image located in a local containers/storage image store. Location and image store specified in /etc/containers/storage.conf
An image located in a local containers/storage image store. Both the location and image store are specified in /etc/containers/storage.conf. (This is the backend for [Podman](https://podman.io), [CRI-O](https://cri-o.io), [Buildah](https://buildah.io) and friends)
* dir:path
An existing local directory path storing the manifest, layer tarballs and signatures as individual files. This is a non-standardized format, primarily useful for debugging or noninvasive container inspection.
* docker://docker-reference
An image in a registry implementing the "Docker Registry HTTP API V2". By default, uses the authorization state in $HOME/.docker/config.json, which is set e.g. using (docker login).
An image in a registry implementing the "Docker Registry HTTP API V2". By default, uses the authorization state in `$XDG_RUNTIME_DIR/containers/auth.json`, which is set using `skopeo login`.
* docker-archive:path[:docker-reference]
An image is stored in the `docker save` formated file. docker-reference is only used when creating such a file, and it must not contain a digest.
An image is stored in a `docker save`-formatted file. docker-reference is only used when creating such a file, and it must not contain a digest.
* docker-daemon:docker-reference
An image docker-reference stored in the docker daemon internal storage. docker-reference must contain either a tag or a digest. Alternatively, when reading images, the format can also be docker-daemon:algo:digest (an image ID).
@@ -37,138 +42,173 @@ Skopeo works with API V2 registries such as Docker registries, the Atomic regist
* oci:path:tag
An image tag in a directory compliant with "Open Container Image Layout Specification" at path.
Inspecting a repository
-
`skopeo` is able to _inspect_ a repository on a Docker registry and fetch images layers.
## Inspecting a repository
`skopeo` is able to _inspect_ a repository on a container registry and fetch images layers.
The _inspect_ command fetches the repository's manifest and it is able to show you a `docker inspect`-like
json output about a whole repository or a tag. This tool, in contrast to `docker inspect`, helps you gather useful information about
a repository or a tag before pulling it (using disk space). The inspect command can show you which tags are available for the given
repository, the labels the image has, the creation date and operating system of the image and more.
Examples:
```sh
# show properties of fedora:latest
$ skopeo inspect docker://docker.io/fedora
#### Show properties of fedora:latest
```console
$ skopeo inspect docker://registry.fedoraproject.org/fedora:latest
{
"Name": "docker.io/library/fedora",
"Tag": "latest",
"Digest": "sha256:cfd8f071bf8da7a466748f522406f7ae5908d002af1b1a1c0dcf893e183e5b32",
"Name": "registry.fedoraproject.org/fedora",
"Digest": "sha256:655721ff613ee766a4126cb5e0d5ae81598e1b0c3bcf7017c36c4d72cb092fe9",
"RepoTags": [
"20",
"21",
"22",
"23",
"heisenbug",
"latest",
"rawhide"
"24",
"25",
"26-modular",
...
],
"Created": "2016-03-04T18:40:02.92155334Z",
"DockerVersion": "1.9.1",
"Labels": {},
"Created": "2020-04-29T06:48:16Z",
"DockerVersion": "1.10.1",
"Labels": {
"license": "MIT",
"name": "fedora",
"vendor": "Fedora Project",
"version": "32"
},
"Architecture": "amd64",
"Os": "linux",
"Layers": [
"sha256:236608c7b546e2f4e7223526c74fc71470ba06d46ec82aeb402e704bfdee02a2",
"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
"sha256:3088721d7dbf674fc0be64cd3cf00c25aab921cacf35fa0e7b1578500a3e1653"
],
"Env": [
"DISTTAG=f32container",
"FGC=f32",
"container=oci"
]
}
# show unverifed image's digest
$ skopeo inspect docker://docker.io/fedora:rawhide | jq '.Digest'
"sha256:905b4846938c8aef94f52f3e41a11398ae5b40f5855fb0e40ed9c157e721d7f8"
```
Copying images
-
`skopeo` can copy container images between various storage mechanisms, including:
* Docker distribution based registries
#### Show container configuration from `fedora:latest`
- The Docker Hub, OpenShift, GCR, Artifactory, Quay ...
```console
$ skopeo inspect --config docker://registry.fedoraproject.org/fedora:latest | jq
{
"created": "2020-04-29T06:48:16Z",
"architecture": "amd64",
"os": "linux",
"config": {
"Env": [
"DISTTAG=f32container",
"FGC=f32",
"container=oci"
],
"Cmd": [
"/bin/bash"
],
"Labels": {
"license": "MIT",
"name": "fedora",
"vendor": "Fedora Project",
"version": "32"
}
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:a4c0fa2b217d3fd63d51e55a6fd59432e543d499c0df2b1acd48fbe424f2ddd1"
]
},
"history": [
{
"created": "2020-04-29T06:48:16Z",
"comment": "Created by Image Factory"
}
]
}
```
#### Show unverified image's digest
```console
$ skopeo inspect docker://registry.fedoraproject.org/fedora:latest | jq '.Digest'
"sha256:655721ff613ee766a4126cb5e0d5ae81598e1b0c3bcf7017c36c4d72cb092fe9"
```
## Copying images
`skopeo` can copy container images between various storage mechanisms, including:
* Container registries
- The Quay, Docker Hub, OpenShift, GCR, Artifactory ...
* Container Storage backends
- Docker daemon storage
- [github.com/containers/storage](https://github.com/containers/storage) (Backend for [Podman](https://podman.io), [CRI-O](https://cri-o.io), [Buildah](https://buildah.io) and friends)
- github.com/containers/storage (Backend for CRI-O, Buildah and friends)
- Docker daemon storage
* Local directories
* Local OCI-layout directories
```sh
$ skopeo copy docker://busybox:1-glibc atomic:myns/unsigned:streaming
$ skopeo copy docker://busybox:latest dir:existingemptydirectory
$ skopeo copy docker://busybox:latest oci:busybox_ocilayout:latest
```console
$ skopeo copy docker://quay.io/buildah/stable docker://registry.internal.company.com/buildah
$ skopeo copy oci:busybox_ocilayout:latest dir:existingemptydirectory
```
Deleting images
-
For example,
```sh
## Deleting images
```console
$ skopeo delete docker://localhost:5000/imagename:latest
```
Private registries with authentication
-
When interacting with private registries, `skopeo` first looks for `--creds` (for `skopeo inspect|delete`) or `--src-creds|--dest-creds` (for `skopeo copy`) flags. If those aren't provided, it looks for the Docker's cli config file (usually located at `$HOME/.docker/config.json`) to get the credentials needed to authenticate. The ultimate fallback, as Docker does, is to provide an empty authentication when interacting with those registries.
## Syncing registries
```console
$ skopeo sync --src docker --dest dir registry.example.com/busybox /media/usb
```
Examples:
```sh
$ cat /home/runcom/.docker/config.json
{
"auths": {
"myregistrydomain.com:5000": {
"auth": "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk",
"email": "stuf@ex.cm"
}
}
}
## Authenticating to a registry
# we can see I'm already authenticated via docker login so everything will be fine
#### Private registries with authentication
skopeo uses credentials from the --creds (for skopeo inspect|delete) or --src-creds|--dest-creds (for skopeo copy) flags, if set; otherwise it uses configuration set by skopeo login, podman login, buildah login, or docker login.
```console
$ skopeo login --username USER myregistrydomain.com:5000
Password:
$ skopeo inspect docker://myregistrydomain.com:5000/busybox
{"Tag":"latest","Digest":"sha256:473bb2189d7b913ed7187a33d11e743fdc2f88931122a44d91a301b64419f092","RepoTags":["latest"],"Comment":"","Created":"2016-01-15T18:06:41.282540103Z","ContainerConfig":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/sh","-c","#(nop) CMD [\"sh\"]"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"DockerVersion":"1.8.3","Author":"","Config":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["sh"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"Architecture":"amd64","Os":"linux"}
$ skopeo logout myregistrydomain.com:5000
```
# let's try now to fake a non existent Docker's config file
$ cat /home/runcom/.docker/config.json
{}
#### Using --creds directly
$ skopeo inspect docker://myregistrydomain.com:5000/busybox
FATA[0000] unauthorized: authentication required
# passing --creds - we can see that everything goes fine
```console
$ skopeo inspect --creds=testuser:testpassword docker://myregistrydomain.com:5000/busybox
{"Tag":"latest","Digest":"sha256:473bb2189d7b913ed7187a33d11e743fdc2f88931122a44d91a301b64419f092","RepoTags":["latest"],"Comment":"","Created":"2016-01-15T18:06:41.282540103Z","ContainerConfig":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/sh","-c","#(nop) CMD [\"sh\"]"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"DockerVersion":"1.8.3","Author":"","Config":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["sh"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"Architecture":"amd64","Os":"linux"}
```
# skopeo copy example:
```console
$ skopeo copy --src-creds=testuser:testpassword docker://myregistrydomain.com:5000/private oci:local_oci_image
```
If your cli config is found but it doesn't contain the necessary credentials for the queried registry
you'll get an error. You can fix this by either logging in (via `docker login`) or providing `--creds` or `--src-creds|--dest-creds`.
Obtaining skopeo
[Obtaining skopeo](./install.md)
-
For a detailed description how to install or build skopeo, see
[install.md](./install.md).
TODO
-
- list all images on registry?
- registry v2 search?
- show repo tags via flag or when reference isn't tagged or digested
- support rkt/appc image spec
NOT TODO
-
- provide a _format_ flag - just use the awesome [jq](https://stedolan.github.io/jq/)
CONTRIBUTING
Contributing
-
Please read the [contribution guide](CONTRIBUTING.md) if you want to collaborate in the project.
## Commands
| Command | Description |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------|
| [skopeo-copy(1)](/docs/skopeo-copy.1.md) | Copy an image (manifest, filesystem layers, signatures) from one location to another. |
| [skopeo-delete(1)](/docs/skopeo-delete.1.md) | Mark the image-name for later deletion by the registry's garbage collector. |
| [skopeo-inspect(1)](/docs/skopeo-inspect.1.md) | Return low-level information about image-name in a registry. |
| [skopeo-list-tags(1)](/docs/skopeo-list-tags.1.md) | Return a list of tags for the transport-specific image repository. |
| [skopeo-login(1)](/docs/skopeo-login.1.md) | Login to a container registry. |
| [skopeo-logout(1)](/docs/skopeo-logout.1.md) | Logout of a container registry. |
| [skopeo-manifest-digest(1)](/docs/skopeo-manifest-digest.1.md) | Compute a manifest digest for a manifest-file and write it to standard output. |
| [skopeo-standalone-sign(1)](/docs/skopeo-standalone-sign.1.md) | Debugging tool - Publish and sign an image in one step. |
| [skopeo-standalone-verify(1)](/docs/skopeo-standalone-verify.1.md)| Verify an image signature. |
| [skopeo-sync(1)](/docs/skopeo-sync.1.md) | Synchronize images between container registries and local directories. |
License
-
skopeo is licensed under the Apache License, Version 2.0. See

3
SECURITY.md Normal file
View File

@@ -0,0 +1,3 @@
## Security and Disclosure Information Policy for the skopeo Project
The skopeo Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects.

View File

@@ -4,107 +4,77 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"strings"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
encconfig "github.com/containers/ocicrypt/config"
enchelpers "github.com/containers/ocicrypt/helpers"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
type copyOptions struct {
global *globalOptions
srcImage *imageOptions
destImage *imageDestOptions
additionalTags cli.StringSlice // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these
removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
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
retryOpts *retry.RetryOptions
additionalTags []string // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these
removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
digestFile string // Write digest to this file
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 []int // The list of layers to encrypt
encryptionKeys []string // Keys needed to encrypt the image
decryptionKeys []string // Keys needed to decrypt the image
}
func copyCmd(global *globalOptions) cli.Command {
func copyCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
srcFlags, srcOpts := imageFlags(global, sharedOpts, "src-", "screds")
destFlags, destOpts := imageDestFlags(global, sharedOpts, "dest-", "dcreds")
retryFlags, retryOpts := retryFlags()
opts := copyOptions{global: global,
srcImage: srcOpts,
destImage: destOpts,
retryOpts: retryOpts,
}
cmd := &cobra.Command{
Use: "copy [command options] SOURCE-IMAGE DESTINATION-IMAGE",
Short: "Copy an IMAGE-NAME from one location to another",
Long: fmt.Sprintf(`Container "IMAGE-NAME" uses a "transport":"details" format.
return cli.Command{
Name: "copy",
Usage: "Copy an IMAGE-NAME from one location to another",
Description: fmt.Sprintf(`
Supported transports:
%s
Container "IMAGE-NAME" uses a "transport":"details" format.
Supported transports:
%s
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
ArgsUsage: "SOURCE-IMAGE DESTINATION-IMAGE",
Action: commandAction(opts.run),
// FIXME: Do we need to namespace the GPG aspect?
Flags: append(append(append([]cli.Flag{
cli.StringSliceFlag{
Name: "additional-tag",
Usage: "additional tags (supports docker-archive)",
Value: &opts.additionalTags, // Surprisingly StringSliceFlag does not support Destination:, but modifies Value: in place.
},
cli.BoolFlag{
Name: "quiet, q",
Usage: "Suppress output information when copying images",
Destination: &opts.quiet,
},
cli.BoolFlag{
Name: "all, a",
Usage: "Copy all images if SOURCE-IMAGE is a list",
Destination: &opts.all,
},
cli.BoolFlag{
Name: "remove-signatures",
Usage: "Do not copy signatures from SOURCE-IMAGE",
Destination: &opts.removeSignatures,
},
cli.StringFlag{
Name: "sign-by",
Usage: "Sign the image using a GPG key with the specified `FINGERPRINT`",
Destination: &opts.signByFingerprint,
},
cli.GenericFlag{
Name: "format, f",
Usage: "`MANIFEST TYPE` (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)",
Value: newOptionalStringValue(&opts.format),
},
cli.StringSliceFlag{
Name: "encryption-key",
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",
Value: &opts.decryptionKeys,
},
}, sharedFlags...), srcFlags...), destFlags...),
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
RunE: commandAction(opts.run),
Example: `skopeo copy docker://quay.io/skopeo/stable:latest docker://registry.example.com/skopeo:latest`,
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&srcFlags)
flags.AddFlagSet(&destFlags)
flags.AddFlagSet(&retryFlags)
flags.StringSliceVar(&opts.additionalTags, "additional-tag", []string{}, "additional tags (supports docker-archive)")
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress output information when copying images")
flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list")
flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE-IMAGE")
flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
flags.StringVar(&opts.digestFile, "digestfile", "", "Write the digest of the pushed image to the specified file")
flags.VarP(newOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)`)
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", []string{}, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
flags.IntSliceVar(&opts.encryptLayer, "encrypt-layer", []int{}, "*Experimental* the 0-indexed layer indices, with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer)")
flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", []string{}, "*Experimental* key needed to decrypt the image")
return cmd
}
func (opts *copyOptions) run(args []string, stdout io.Writer) error {
@@ -143,15 +113,9 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
var manifestType string
if opts.format.present {
switch opts.format.value {
case "oci":
manifestType = imgspecv1.MediaTypeImageManifest
case "v2s1":
manifestType = manifest.DockerV2Schema1SignedMediaType
case "v2s2":
manifestType = manifest.DockerV2Schema2MediaType
default:
return fmt.Errorf("unknown format %q. Choose one of the supported formats: 'oci', 'v2s1', or 'v2s2'", opts.format.value)
manifestType, err = parseManifestFormat(opts.format.value)
if err != nil {
return err
}
}
@@ -178,7 +142,7 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
imageListSelection = copy.CopyAllImages
}
if len(opts.encryptionKeys.Value()) > 0 && len(opts.decryptionKeys.Value()) > 0 {
if len(opts.encryptionKeys) > 0 && len(opts.decryptionKeys) > 0 {
return fmt.Errorf("--encryption-key and --decryption-key cannot be specified together")
}
@@ -186,15 +150,15 @@ 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 {
if len(opts.encryptLayer) > 0 && len(opts.encryptionKeys) == 0 {
return fmt.Errorf("--encrypt-layer can only be used with --encryption-key")
}
if len(opts.encryptionKeys.Value()) > 0 {
if len(opts.encryptionKeys) > 0 {
// encryption
p := opts.encryptLayer.Value()
p := opts.encryptLayer
encLayers = &p
encryptionKeys := opts.encryptionKeys.Value()
encryptionKeys := opts.encryptionKeys
ecc, err := enchelpers.CreateCryptoConfig(encryptionKeys, []string{})
if err != nil {
return fmt.Errorf("Invalid encryption keys: %v", err)
@@ -203,9 +167,9 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
encConfig = cc.EncryptConfig
}
if len(opts.decryptionKeys.Value()) > 0 {
if len(opts.decryptionKeys) > 0 {
// decryption
decryptionKeys := opts.decryptionKeys.Value()
decryptionKeys := opts.decryptionKeys
dcc, err := enchelpers.CreateCryptoConfig([]string{}, decryptionKeys)
if err != nil {
return fmt.Errorf("Invalid decryption keys: %v", err)
@@ -214,17 +178,31 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
decConfig = cc.DecryptConfig
}
_, err = copy.Image(ctx, policyContext, destRef, srcRef, &copy.Options{
RemoveSignatures: opts.removeSignatures,
SignBy: opts.signByFingerprint,
ReportWriter: stdout,
SourceCtx: sourceCtx,
DestinationCtx: destinationCtx,
ForceManifestMIMEType: manifestType,
ImageListSelection: imageListSelection,
OciDecryptConfig: decConfig,
OciEncryptLayers: encLayers,
OciEncryptConfig: encConfig,
})
return err
return retry.RetryIfNecessary(ctx, func() error {
manifestBytes, err := copy.Image(ctx, policyContext, destRef, srcRef, &copy.Options{
RemoveSignatures: opts.removeSignatures,
SignBy: opts.signByFingerprint,
ReportWriter: stdout,
SourceCtx: sourceCtx,
DestinationCtx: destinationCtx,
ForceManifestMIMEType: manifestType,
ImageListSelection: imageListSelection,
OciDecryptConfig: decConfig,
OciEncryptLayers: encLayers,
OciEncryptConfig: encConfig,
})
if err != nil {
return err
}
if opts.digestFile != "" {
manifestDigest, err := manifest.Digest(manifestBytes)
if err != nil {
return err
}
if err = ioutil.WriteFile(opts.digestFile, []byte(manifestDigest.String()), 0644); err != nil {
return fmt.Errorf("Failed to write digest to file %q: %w", opts.digestFile, err)
}
}
return nil
}, opts.retryOpts)
}

View File

@@ -6,38 +6,44 @@ import (
"io"
"strings"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
type deleteOptions struct {
global *globalOptions
image *imageOptions
global *globalOptions
image *imageOptions
retryOpts *retry.RetryOptions
}
func deleteCmd(global *globalOptions) cli.Command {
func deleteCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
retryFlags, retryOpts := retryFlags()
opts := deleteOptions{
global: global,
image: imageOpts,
global: global,
image: imageOpts,
retryOpts: retryOpts,
}
return cli.Command{
Name: "delete",
Usage: "Delete image IMAGE-NAME",
Description: fmt.Sprintf(`
Delete an "IMAGE_NAME" from a transport
Supported transports:
%s
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
ArgsUsage: "IMAGE-NAME",
Action: commandAction(opts.run),
Flags: append(sharedFlags, imageFlags...),
cmd := &cobra.Command{
Use: "delete [command options] IMAGE-NAME",
Short: "Delete image IMAGE-NAME",
Long: fmt.Sprintf(`Delete an "IMAGE_NAME" from a transport
Supported transports:
%s
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
RunE: commandAction(opts.run),
Example: `skopeo delete docker://registry.example.com/example/pause:latest`,
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&imageFlags)
flags.AddFlagSet(&retryFlags)
return cmd
}
func (opts *deleteOptions) run(args []string, stdout io.Writer) error {
@@ -62,5 +68,8 @@ func (opts *deleteOptions) run(args []string, stdout io.Writer) error {
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
return ref.DeleteImage(ctx, sys)
return retry.RetryIfNecessary(ctx, func() error {
return ref.DeleteImage(ctx, sys)
}, opts.retryOpts)
}

View File

@@ -3,7 +3,7 @@ package main
import (
"strconv"
"github.com/urfave/cli"
"github.com/spf13/pflag"
)
// optionalBool is a boolean with a separate presence flag.
@@ -15,10 +15,18 @@ type optionalBool struct {
// optionalBool is a cli.Generic == flag.Value implementation equivalent to
// the one underlying flag.Bool, except that it records whether the flag has been set.
// This is distinct from optionalBool to (pretend to) force callers to use
// newOptionalBool
// optionalBoolFlag
type optionalBoolValue optionalBool
func newOptionalBoolValue(p *optionalBool) cli.Generic {
func optionalBoolFlag(fs *pflag.FlagSet, p *optionalBool, name, usage string) *pflag.Flag {
flag := fs.VarPF(internalNewOptionalBoolValue(p), name, "", usage)
flag.NoOptDefVal = "true"
return flag
}
// WARNING: Do not directly use this method to define optionalBool flag.
// Caller should use optionalBoolFlag
func internalNewOptionalBoolValue(p *optionalBool) pflag.Value {
p.present = false
return (*optionalBoolValue)(p)
}
@@ -40,6 +48,10 @@ func (ob *optionalBoolValue) String() string {
return strconv.FormatBool(ob.value)
}
func (ob *optionalBoolValue) Type() string {
return "bool"
}
func (ob *optionalBoolValue) IsBoolFlag() bool {
return true
}
@@ -56,7 +68,7 @@ type optionalString struct {
// newoptionalString
type optionalStringValue optionalString
func newOptionalStringValue(p *optionalString) cli.Generic {
func newOptionalStringValue(p *optionalString) pflag.Value {
p.present = false
return (*optionalStringValue)(p)
}
@@ -74,6 +86,10 @@ func (ob *optionalStringValue) String() string {
return ob.value
}
func (ob *optionalStringValue) Type() string {
return "string"
}
// optionalInt is a int with a separate presence flag.
type optionalInt struct {
present bool
@@ -86,7 +102,7 @@ type optionalInt struct {
// newoptionalIntValue
type optionalIntValue optionalInt
func newOptionalIntValue(p *optionalInt) cli.Generic {
func newOptionalIntValue(p *optionalInt) pflag.Value {
p.present = false
return (*optionalIntValue)(p)
}
@@ -107,3 +123,7 @@ func (ob *optionalIntValue) String() string {
}
return strconv.Itoa(int(ob.value))
}
func (ob *optionalIntValue) Type() string {
return "int"
}

View File

@@ -3,9 +3,9 @@ package main
import (
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
)
func TestOptionalBoolSet(t *testing.T) {
@@ -34,7 +34,7 @@ func TestOptionalBoolSet(t *testing.T) {
{"2", false, false},
} {
var ob optionalBool
v := newOptionalBoolValue(&ob)
v := internalNewOptionalBoolValue(&ob)
require.False(t, ob.present)
err := v.Set(c.input)
if c.accepted {
@@ -51,30 +51,23 @@ func TestOptionalBoolSet(t *testing.T) {
// is not called in any possible situation).
var globalOB, commandOB optionalBool
actionRun := false
app := cli.NewApp()
app.EnableBashCompletion = true
app.Flags = []cli.Flag{
cli.GenericFlag{
Name: "global-OB",
Value: newOptionalBoolValue(&globalOB),
},
app := &cobra.Command{
Use: "app",
}
app.Commands = []cli.Command{{
Name: "cmd",
Flags: []cli.Flag{
cli.GenericFlag{
Name: "command-OB",
Value: newOptionalBoolValue(&commandOB),
},
},
Action: func(*cli.Context) error {
optionalBoolFlag(app.PersistentFlags(), &globalOB, "global-OB", "")
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.False(t, globalOB.present)
assert.False(t, commandOB.present)
actionRun = true
return nil
},
}}
err := app.Run([]string{"app", "cmd"})
}
optionalBoolFlag(cmd.Flags(), &commandOB, "command-OB", "")
app.AddCommand(cmd)
app.SetArgs([]string{"cmd"})
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
@@ -90,7 +83,7 @@ func TestOptionalBoolString(t *testing.T) {
{optionalBool{present: false, value: false}, ""},
} {
var ob optionalBool
v := newOptionalBoolValue(&ob)
v := internalNewOptionalBoolValue(&ob)
ob = c.input
res := v.String()
assert.Equal(t, c.expected, res)
@@ -114,23 +107,21 @@ func TestOptionalBoolIsBoolFlag(t *testing.T) {
} {
var ob optionalBool
actionRun := false
app := cli.NewApp()
app.Commands = []cli.Command{{
Name: "cmd",
Flags: []cli.Flag{
cli.GenericFlag{
Name: "OB",
Value: newOptionalBoolValue(&ob),
},
},
Action: func(ctx *cli.Context) error {
app := &cobra.Command{Use: "app"}
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.Equal(t, c.expectedOB, ob)
assert.Equal(t, c.expectedArgs, ([]string)(ctx.Args()))
assert.Equal(t, c.expectedArgs, args)
actionRun = true
return nil
},
}}
err := app.Run(append([]string{"app", "cmd"}, c.input...))
}
optionalBoolFlag(cmd.Flags(), &ob, "OB", "")
app.AddCommand(cmd)
app.SetArgs(append([]string{"cmd"}, c.input...))
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
@@ -152,30 +143,23 @@ func TestOptionalStringSet(t *testing.T) {
// is not called in any possible situation).
var globalOS, commandOS optionalString
actionRun := false
app := cli.NewApp()
app.EnableBashCompletion = true
app.Flags = []cli.Flag{
cli.GenericFlag{
Name: "global-OS",
Value: newOptionalStringValue(&globalOS),
},
app := &cobra.Command{
Use: "app",
}
app.Commands = []cli.Command{{
Name: "cmd",
Flags: []cli.Flag{
cli.GenericFlag{
Name: "command-OS",
Value: newOptionalStringValue(&commandOS),
},
},
Action: func(*cli.Context) error {
app.PersistentFlags().Var(newOptionalStringValue(&globalOS), "global-OS", "")
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.False(t, globalOS.present)
assert.False(t, commandOS.present)
actionRun = true
return nil
},
}}
err := app.Run([]string{"app", "cmd"})
}
cmd.Flags().Var(newOptionalStringValue(&commandOS), "command-OS", "")
app.AddCommand(cmd)
app.SetArgs([]string{"cmd"})
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
@@ -216,23 +200,22 @@ func TestOptionalStringIsBoolFlag(t *testing.T) {
} {
var os optionalString
actionRun := false
app := cli.NewApp()
app.Commands = []cli.Command{{
Name: "cmd",
Flags: []cli.Flag{
cli.GenericFlag{
Name: "OS",
Value: newOptionalStringValue(&os),
},
},
Action: func(ctx *cli.Context) error {
app := &cobra.Command{
Use: "app",
}
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.Equal(t, c.expectedOS, os)
assert.Equal(t, c.expectedArgs, ([]string)(ctx.Args()))
assert.Equal(t, c.expectedArgs, args)
actionRun = true
return nil
},
}}
err := app.Run(append([]string{"app", "cmd"}, c.input...))
}
cmd.Flags().Var(newOptionalStringValue(&os), "OS", "")
app.AddCommand(cmd)
app.SetArgs(append([]string{"cmd"}, c.input...))
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}

View File

@@ -4,83 +4,84 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"strings"
"time"
"text/tabwriter"
"text/template"
"github.com/containers/common/pkg/report"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports"
digest "github.com/opencontainers/go-digest"
"github.com/containers/image/v5/types"
"github.com/containers/skopeo/cmd/skopeo/inspect"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
// inspectOutput is the output format of (skopeo inspect), primarily so that we can format it with a simple json.MarshalIndent.
type inspectOutput struct {
Name string `json:",omitempty"`
Tag string `json:",omitempty"`
Digest digest.Digest
RepoTags []string
Created *time.Time
DockerVersion string
Labels map[string]string
Architecture string
Os string
Layers []string
Env []string
}
type inspectOptions struct {
global *globalOptions
image *imageOptions
raw bool // Output the raw manifest instead of parsing information about the image
config bool // Output the raw config blob instead of parsing information about the image
global *globalOptions
image *imageOptions
retryOpts *retry.RetryOptions
format string
raw bool // Output the raw manifest instead of parsing information about the image
config bool // Output the raw config blob instead of parsing information about the image
}
func inspectCmd(global *globalOptions) cli.Command {
func inspectCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
retryFlags, retryOpts := retryFlags()
opts := inspectOptions{
global: global,
image: imageOpts,
global: global,
image: imageOpts,
retryOpts: retryOpts,
}
return cli.Command{
Name: "inspect",
Usage: "Inspect image IMAGE-NAME",
Description: fmt.Sprintf(`
Return low-level information about "IMAGE-NAME" in a registry/transport
cmd := &cobra.Command{
Use: "inspect [command options] IMAGE-NAME",
Short: "Inspect image IMAGE-NAME",
Long: fmt.Sprintf(`Return low-level information about "IMAGE-NAME" in a registry/transport
Supported transports:
%s
Supported transports:
%s
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
ArgsUsage: "IMAGE-NAME",
Flags: append(append([]cli.Flag{
cli.BoolFlag{
Name: "raw",
Usage: "output raw manifest or configuration",
Destination: &opts.raw,
},
cli.BoolFlag{
Name: "config",
Usage: "output configuration",
Destination: &opts.config,
},
}, sharedFlags...), imageFlags...),
Action: commandAction(opts.run),
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
RunE: commandAction(opts.run),
Example: `skopeo inspect docker://registry.fedoraproject.org/fedora
skopeo inspect --config docker://docker.io/alpine
skopeo inspect --format "Name: {{.Name}} Digest: {{.Digest}}" docker://registry.access.redhat.com/ubi8`,
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.BoolVar(&opts.raw, "raw", false, "output raw manifest or configuration")
flags.BoolVar(&opts.config, "config", false, "output configuration")
flags.StringVarP(&opts.format, "format", "f", "", "Format the output to a Go template")
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&imageFlags)
flags.AddFlagSet(&retryFlags)
return cmd
}
func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error) {
var (
rawManifest []byte
src types.ImageSource
imgInspect *types.ImageInspectInfo
data []interface{}
)
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
if len(args) != 1 {
return errors.New("Exactly one argument expected")
}
if opts.raw && opts.format != "" {
return errors.New("raw output does not support format option")
}
imageName := args[0]
if err := reexecIfNecessaryForImages(imageName); err != nil {
@@ -92,9 +93,11 @@ func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error)
return err
}
src, err := parseImageSource(ctx, opts.image, imageName)
if err != nil {
return fmt.Errorf("Error parsing image name %q: %v", imageName, err)
if err := retry.RetryIfNecessary(ctx, func() error {
src, err = parseImageSource(ctx, opts.image, imageName)
return err
}, opts.retryOpts); err != nil {
return errors.Wrapf(err, "Error parsing image name %q", imageName)
}
defer func() {
@@ -103,9 +106,11 @@ func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error)
}
}()
rawManifest, _, err := src.GetManifest(ctx, nil)
if err != nil {
return fmt.Errorf("Error retrieving manifest for image: %v", err)
if err := retry.RetryIfNecessary(ctx, func() error {
rawManifest, _, err = src.GetManifest(ctx, nil)
return err
}, opts.retryOpts); err != nil {
return errors.Wrapf(err, "Error retrieving manifest for image")
}
if opts.raw && !opts.config {
@@ -113,45 +118,65 @@ func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error)
if err != nil {
return fmt.Errorf("Error writing manifest to standard output: %v", err)
}
return nil
}
img, err := image.FromUnparsedImage(ctx, sys, image.UnparsedInstance(src, nil))
if err != nil {
return fmt.Errorf("Error parsing manifest for image: %v", err)
return errors.Wrapf(err, "Error parsing manifest for image")
}
if opts.config && opts.raw {
configBlob, err := img.ConfigBlob(ctx)
if err != nil {
return fmt.Errorf("Error reading configuration blob: %v", err)
var configBlob []byte
if err := retry.RetryIfNecessary(ctx, func() error {
configBlob, err = img.ConfigBlob(ctx)
return err
}, opts.retryOpts); err != nil {
return errors.Wrapf(err, "Error reading configuration blob")
}
_, err = stdout.Write(configBlob)
if err != nil {
return fmt.Errorf("Error writing configuration blob to standard output: %v", err)
return errors.Wrapf(err, "Error writing configuration blob to standard output")
}
return nil
} else if opts.config {
config, err := img.OCIConfig(ctx)
if err != nil {
return fmt.Errorf("Error reading OCI-formatted configuration data: %v", err)
var config *v1.Image
if err := retry.RetryIfNecessary(ctx, func() error {
config, err = img.OCIConfig(ctx)
return err
}, opts.retryOpts); err != nil {
return errors.Wrapf(err, "Error reading OCI-formatted configuration data")
}
if report.IsJSON(opts.format) || opts.format == "" {
var out []byte
out, err = json.MarshalIndent(config, "", " ")
if err == nil {
fmt.Fprintf(stdout, "%s\n", string(out))
}
} else {
row := "{{range . }}" + report.NormalizeFormat(opts.format) + "{{end}}"
data = append(data, config)
err = printTmpl(row, data)
}
err = json.NewEncoder(stdout).Encode(config)
if err != nil {
return fmt.Errorf("Error writing OCI-formatted configuration data to standard output: %v", err)
return errors.Wrapf(err, "Error writing OCI-formatted configuration data to standard output")
}
return nil
}
imgInspect, err := img.Inspect(ctx)
if err != nil {
if err := retry.RetryIfNecessary(ctx, func() error {
imgInspect, err = img.Inspect(ctx)
return err
}, opts.retryOpts); err != nil {
return err
}
outputData := inspectOutput{
outputData := inspect.Output{
Name: "", // Set below if DockerReference() is known
Tag: imgInspect.Tag,
// Digest is set below.
RepoTags: []string{}, // Possibly overriden for docker.Transport.
RepoTags: []string{}, // Possibly overridden for docker.Transport.
Created: imgInspect.Created,
DockerVersion: imgInspect.DockerVersion,
Labels: imgInspect.Labels,
@@ -162,7 +187,7 @@ func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error)
}
outputData.Digest, err = manifest.Digest(rawManifest)
if err != nil {
return fmt.Errorf("Error computing manifest digest: %v", err)
return errors.Wrapf(err, "Error computing manifest digest")
}
if dockerRef := img.Reference().DockerReference(); dockerRef != nil {
outputData.Name = dockerRef.Name()
@@ -180,15 +205,35 @@ func (opts *inspectOptions) run(args []string, stdout io.Writer) (retErr error)
// In addition, AWS ECR rejects it with 403 (Forbidden) if the "ecr:ListImages"
// action is not allowed.
if !strings.Contains(err.Error(), "401") && !strings.Contains(err.Error(), "403") {
return fmt.Errorf("Error determining repository tags: %v", err)
return errors.Wrapf(err, "Error determining repository tags")
}
logrus.Warnf("Registry disallows tag list retrieval; skipping")
}
}
out, err := json.MarshalIndent(outputData, "", " ")
if report.IsJSON(opts.format) || opts.format == "" {
out, err := json.MarshalIndent(outputData, "", " ")
if err == nil {
fmt.Fprintf(stdout, "%s\n", string(out))
}
return err
}
row := "{{range . }}" + report.NormalizeFormat(opts.format) + "{{end}}"
data = append(data, outputData)
return printTmpl(row, data)
}
func inspectNormalize(row string) string {
r := strings.NewReplacer(
".ImageID", ".Image",
)
return r.Replace(row)
}
func printTmpl(row string, data []interface{}) error {
t, err := template.New("skopeo inspect").Parse(row)
if err != nil {
return err
}
fmt.Fprintf(stdout, "%s\n", string(out))
return nil
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
return t.Execute(w, data)
}

View File

@@ -0,0 +1,23 @@
package inspect
import (
"time"
digest "github.com/opencontainers/go-digest"
)
// Output is the output format of (skopeo inspect),
// primarily so that we can format it with a simple json.MarshalIndent.
type Output struct {
Name string `json:",omitempty"`
Tag string `json:",omitempty"`
Digest digest.Digest
RepoTags []string
Created *time.Time
DockerVersion string
Labels map[string]string
Architecture string
Os string
Layers []string
Env []string
}

View File

@@ -7,35 +7,43 @@ import (
"os"
"strings"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/directory"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/pkg/blobinfocache"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
type layersOptions struct {
global *globalOptions
image *imageOptions
global *globalOptions
image *imageOptions
retryOpts *retry.RetryOptions
}
func layersCmd(global *globalOptions) cli.Command {
func layersCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
retryFlags, retryOpts := retryFlags()
opts := layersOptions{
global: global,
image: imageOpts,
global: global,
image: imageOpts,
retryOpts: retryOpts,
}
return cli.Command{
Name: "layers",
Usage: "Get layers of IMAGE-NAME",
ArgsUsage: "IMAGE-NAME [LAYER...]",
Hidden: true,
Action: commandAction(opts.run),
Flags: append(sharedFlags, imageFlags...),
cmd := &cobra.Command{
Hidden: true,
Use: "layers [command options] IMAGE-NAME [LAYER...]",
Short: "Get layers of IMAGE-NAME",
RunE: commandAction(opts.run),
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&imageFlags)
flags.AddFlagSet(&retryFlags)
return cmd
}
func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
@@ -57,12 +65,20 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
return err
}
cache := blobinfocache.DefaultCache(sys)
rawSource, err := parseImageSource(ctx, opts.image, imageName)
if err != nil {
var (
rawSource types.ImageSource
src types.ImageCloser
)
if err = retry.RetryIfNecessary(ctx, func() error {
rawSource, err = parseImageSource(ctx, opts.image, imageName)
return err
}, opts.retryOpts); err != nil {
return err
}
src, err := image.FromSource(ctx, sys, rawSource)
if err != nil {
if err = retry.RetryIfNecessary(ctx, func() error {
src, err = image.FromSource(ctx, sys, rawSource)
return err
}, opts.retryOpts); err != nil {
if closeErr := rawSource.Close(); closeErr != nil {
return errors.Wrapf(err, " (close error: %v)", closeErr)
}
@@ -126,8 +142,14 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
}()
for _, bd := range blobDigests {
r, blobSize, err := rawSource.GetBlob(ctx, types.BlobInfo{Digest: bd.digest, Size: -1}, cache)
if err != nil {
var (
r io.ReadCloser
blobSize int64
)
if err = retry.RetryIfNecessary(ctx, func() error {
r, blobSize, err = rawSource.GetBlob(ctx, types.BlobInfo{Digest: bd.digest, Size: -1}, cache)
return err
}, opts.retryOpts); err != nil {
return err
}
if _, err := dest.PutBlob(ctx, r, types.BlobInfo{Digest: bd.digest, Size: blobSize}, cache, bd.isConfig); err != nil {
@@ -138,8 +160,11 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
}
}
manifest, _, err := src.Manifest(ctx)
if err != nil {
var manifest []byte
if err = retry.RetryIfNecessary(ctx, func() error {
manifest, _, err = src.Manifest(ctx)
return err
}, opts.retryOpts); err != nil {
return err
}
if err := dest.PutManifest(ctx, manifest, nil); err != nil {

View File

@@ -4,15 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/containers/common/pkg/retry"
"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"
"github.com/spf13/cobra"
)
// tagListOutput is the output format of (skopeo list-tags), primarily so that we can format it with a simple json.MarshalIndent.
@@ -22,34 +23,40 @@ type tagListOutput struct {
}
type tagsOptions struct {
global *globalOptions
image *imageOptions
global *globalOptions
image *imageOptions
retryOpts *retry.RetryOptions
}
func tagsCmd(global *globalOptions) cli.Command {
func tagsCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, "", "")
retryFlags, retryOpts := retryFlags()
opts := tagsOptions{
global: global,
image: imageOpts,
global: global,
image: imageOpts,
retryOpts: retryOpts,
}
cmd := &cobra.Command{
Use: "list-tags [command options] REPOSITORY-NAME",
Short: "List tags in the transport/repository specified by the REPOSITORY-NAME",
Long: `Return the list of tags from the transport/repository "REPOSITORY-NAME"
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
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),
See skopeo-list-tags(1) section "REPOSITORY NAMES" for the expected format
`,
RunE: commandAction(opts.run),
Example: `skopeo list-tags docker://docker.io/fedora`,
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&imageFlags)
flags.AddFlagSet(&retryFlags)
return cmd
}
// Customized version of the alltransports.ParseImageName and docker.ParseReference that does not place a default tag in the reference
@@ -116,8 +123,12 @@ func (opts *tagsOptions) run(args []string, stdout io.Writer) (retErr error) {
return err
}
repositoryName, tagListing, err := listDockerTags(ctx, sys, imgRef)
if err != nil {
var repositoryName string
var tagListing []string
if err = retry.RetryIfNecessary(ctx, func() error {
repositoryName, tagListing, err = listDockerTags(ctx, sys, imgRef)
return err
}, opts.retryOpts); err != nil {
return err
}

View File

@@ -1,9 +1,10 @@
package main
import (
"testing"
"github.com/containers/image/v5/transports/alltransports"
"github.com/stretchr/testify/assert"
"testing"
)
// Tests the kinds of inputs allowed and expected to the command

47
cmd/skopeo/login.go Normal file
View File

@@ -0,0 +1,47 @@
package main
import (
"io"
"os"
"github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/types"
"github.com/spf13/cobra"
)
type loginOptions struct {
global *globalOptions
loginOpts auth.LoginOptions
getLogin optionalBool
tlsVerify optionalBool
}
func loginCmd(global *globalOptions) *cobra.Command {
opts := loginOptions{
global: global,
}
cmd := &cobra.Command{
Use: "login",
Short: "Login to a container registry",
Long: "Login to a container registry on a specified server.",
RunE: commandAction(opts.run),
Example: `skopeo login quay.io`,
}
adjustUsage(cmd)
flags := cmd.Flags()
optionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry")
flags.AddFlagSet(auth.GetLoginFlags(&opts.loginOpts))
return cmd
}
func (opts *loginOptions) run(args []string, stdout io.Writer) error {
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
opts.loginOpts.Stdout = stdout
opts.loginOpts.Stdin = os.Stdin
sys := opts.global.newSystemContext()
if opts.tlsVerify.present {
sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
return auth.Login(ctx, sys, &opts.loginOpts, args)
}

35
cmd/skopeo/logout.go Normal file
View File

@@ -0,0 +1,35 @@
package main
import (
"io"
"github.com/containers/common/pkg/auth"
"github.com/spf13/cobra"
)
type logoutOptions struct {
global *globalOptions
logoutOpts auth.LogoutOptions
}
func logoutCmd(global *globalOptions) *cobra.Command {
opts := logoutOptions{
global: global,
}
cmd := &cobra.Command{
Use: "logout",
Short: "Logout of a container registry",
Long: "Logout of a container registry on a specified server.",
RunE: commandAction(opts.run),
Example: `skopeo logout quay.io`,
}
adjustUsage(cmd)
cmd.Flags().AddFlagSet(auth.GetLogoutFlags(&opts.logoutOpts))
return cmd
}
func (opts *logoutOptions) run(args []string, stdout io.Writer) error {
opts.logoutOpts.Stdout = stdout
sys := opts.global.newSystemContext()
return auth.Logout(sys, &opts.logoutOpts, args)
}

View File

@@ -3,20 +3,22 @@ package main
import (
"context"
"fmt"
"os"
"time"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types"
"github.com/containers/skopeo/version"
"github.com/containers/storage/pkg/reexec"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
// gitCommit will be the hash that the binary was built from
// and will be populated by the Makefile
var gitCommit = ""
var defaultUserAgent = "skopeo/" + version.Version
type globalOptions struct {
debug bool // Enable debug output
tlsVerify optionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:)
@@ -31,96 +33,61 @@ type globalOptions struct {
tmpDir string // Path to use for big temporary files
}
// createApp returns a cli.App, and the underlying globalOptions object, to be run or tested.
func createApp() (*cli.App, *globalOptions) {
// createApp returns a cobra.Command, and the underlying globalOptions object, to be run or tested.
func createApp() (*cobra.Command, *globalOptions) {
opts := globalOptions{}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Name = "skopeo"
rootCommand := &cobra.Command{
Use: "skopeo",
Long: "Various operations with container images and container image registries",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return opts.before(cmd)
},
SilenceUsage: true,
SilenceErrors: true,
}
if gitCommit != "" {
app.Version = fmt.Sprintf("%s commit: %s", version.Version, gitCommit)
rootCommand.Version = fmt.Sprintf("%s commit: %s", version.Version, gitCommit)
} else {
app.Version = version.Version
rootCommand.Version = version.Version
}
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.BoolFlag{
Name: "insecure-policy",
Usage: "run the tool without any policy check",
Destination: &opts.insecurePolicy,
},
cli.StringFlag{
Name: "override-arch",
Usage: "use `ARCH` instead of the architecture of the machine for choosing images",
Destination: &opts.overrideArch,
},
cli.StringFlag{
Name: "override-os",
Usage: "use `OS` instead of the running OS for choosing images",
Destination: &opts.overrideOS,
},
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",
Usage: "path to the registries.conf file",
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,
},
// Override default `--version` global flag to enable `-v` shorthand
var dummyVersion bool
rootCommand.Flags().BoolVarP(&dummyVersion, "version", "v", false, "Version for Skopeo")
rootCommand.PersistentFlags().BoolVar(&opts.debug, "debug", false, "enable debug output")
flag := optionalBoolFlag(rootCommand.PersistentFlags(), &opts.tlsVerify, "tls-verify", "Require HTTPS and verify certificates when accessing the registry")
flag.Hidden = true
rootCommand.PersistentFlags().StringVar(&opts.policyPath, "policy", "", "Path to a trust policy file")
rootCommand.PersistentFlags().BoolVar(&opts.insecurePolicy, "insecure-policy", false, "run the tool without any policy check")
rootCommand.PersistentFlags().StringVar(&opts.registriesDirPath, "registries.d", "", "use registry configuration files in `DIR` (e.g. for container signature storage)")
rootCommand.PersistentFlags().StringVar(&opts.overrideArch, "override-arch", "", "use `ARCH` instead of the architecture of the machine for choosing images")
rootCommand.PersistentFlags().StringVar(&opts.overrideOS, "override-os", "", "use `OS` instead of the running OS for choosing images")
rootCommand.PersistentFlags().StringVar(&opts.overrideVariant, "override-variant", "", "use `VARIANT` instead of the running architecture variant for choosing images")
rootCommand.PersistentFlags().DurationVar(&opts.commandTimeout, "command-timeout", 0, "timeout for the command execution")
rootCommand.PersistentFlags().StringVar(&opts.registriesConfPath, "registries-conf", "", "path to the registries.conf file")
if err := rootCommand.PersistentFlags().MarkHidden("registries-conf"); err != nil {
logrus.Fatal("unable to mark registries-conf flag as hidden")
}
app.Before = opts.before
app.Commands = []cli.Command{
rootCommand.PersistentFlags().StringVar(&opts.tmpDir, "tmpdir", "", "directory used to store temporary files")
rootCommand.AddCommand(
copyCmd(&opts),
deleteCmd(&opts),
inspectCmd(&opts),
layersCmd(&opts),
tagsCmd(&opts),
loginCmd(&opts),
logoutCmd(&opts),
manifestDigestCmd(),
syncCmd(&opts),
standaloneSignCmd(),
standaloneVerifyCmd(),
syncCmd(&opts),
tagsCmd(&opts),
untrustedSignatureDumpCmd(),
}
return app, &opts
)
return rootCommand, &opts
}
// before is run by the cli package for any command, before running the command-specific handler.
func (opts *globalOptions) before(ctx *cli.Context) error {
func (opts *globalOptions) before(cmd *cobra.Command) error {
if opts.debug {
logrus.SetLevel(logrus.DebugLevel)
}
@@ -134,8 +101,8 @@ func main() {
if reexec.Init() {
return
}
app, _ := createApp()
if err := app.Run(os.Args); err != nil {
rootCmd, _ := createApp()
if err := rootCmd.Execute(); err != nil {
logrus.Fatal(err)
}
}
@@ -167,3 +134,22 @@ func (opts *globalOptions) commandTimeoutContext() (context.Context, context.Can
}
return ctx, cancel
}
// newSystemContext returns a *types.SystemContext corresponding to opts.
// It is guaranteed to return a fresh instance, so it is safe to make additional updates to it.
func (opts *globalOptions) newSystemContext() *types.SystemContext {
ctx := &types.SystemContext{
RegistriesDirPath: opts.registriesDirPath,
ArchitectureChoice: opts.overrideArch,
OSChoice: opts.overrideOS,
VariantChoice: opts.overrideVariant,
SystemRegistriesConfPath: opts.registriesConfPath,
BigFilesTemporaryDir: opts.tmpDir,
DockerRegistryUserAgent: defaultUserAgent,
}
// DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided.
if opts.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
return ctx
}

View File

@@ -1,14 +1,51 @@
package main
import "bytes"
import (
"bytes"
"testing"
"github.com/containers/image/v5/types"
"github.com/stretchr/testify/assert"
)
// runSkopeo creates an app object and runs it with args, with an implied first "skopeo".
// Returns output intended for stdout and the returned error, if any.
func runSkopeo(args ...string) (string, error) {
app, _ := createApp()
stdout := bytes.Buffer{}
app.Writer = &stdout
args = append([]string{"skopeo"}, args...)
err := app.Run(args)
app.SetOut(&stdout)
app.SetArgs(args)
err := app.Execute()
return stdout.String(), err
}
func TestGlobalOptionsNewSystemContext(t *testing.T) {
// Default state
opts, _ := fakeGlobalOptions(t, []string{})
res := opts.newSystemContext()
assert.Equal(t, &types.SystemContext{
// User-Agent is set by default.
DockerRegistryUserAgent: defaultUserAgent,
}, res)
// Set everything to non-default values.
opts, _ = fakeGlobalOptions(t, []string{
"--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch",
"--override-os", "overridden-os",
"--override-variant", "overridden-variant",
"--tmpdir", "/srv",
"--registries-conf", "/srv/registries.conf",
"--tls-verify=false",
})
res = opts.newSystemContext()
assert.Equal(t, &types.SystemContext{
RegistriesDirPath: "/srv/registries.d",
ArchitectureChoice: "overridden-arch",
OSChoice: "overridden-os",
VariantChoice: "overridden-variant",
BigFilesTemporaryDir: "/srv",
SystemRegistriesConfPath: "/srv/registries.conf",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
DockerRegistryUserAgent: defaultUserAgent,
}, res)
}

View File

@@ -7,20 +7,22 @@ import (
"io/ioutil"
"github.com/containers/image/v5/manifest"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
type manifestDigestOptions struct {
}
func manifestDigestCmd() cli.Command {
opts := manifestDigestOptions{}
return cli.Command{
Name: "manifest-digest",
Usage: "Compute a manifest digest of a file",
ArgsUsage: "MANIFEST",
Action: commandAction(opts.run),
func manifestDigestCmd() *cobra.Command {
var opts manifestDigestOptions
cmd := &cobra.Command{
Use: "manifest-digest MANIFEST",
Short: "Compute a manifest digest of a file",
RunE: commandAction(opts.run),
Example: "skopeo manifest-digest manifest.json",
}
adjustUsage(cmd)
return cmd
}
func (opts *manifestDigestOptions) run(args []string, stdout io.Writer) error {

View File

@@ -17,8 +17,8 @@ func TestManifestDigest(t *testing.T) {
}
// Error reading manifest
out, err := runSkopeo("manifest-digest", "/this/doesnt/exist")
assertTestFailed(t, out, err, "/this/doesnt/exist")
out, err := runSkopeo("manifest-digest", "/this/does/not/exist")
assertTestFailed(t, out, err, "/this/does/not/exist")
// Error computing manifest
out, err = runSkopeo("manifest-digest", "fixtures/v2s1-invalid-signatures.manifest.json")

View File

@@ -8,28 +8,24 @@ import (
"io/ioutil"
"github.com/containers/image/v5/signature"
"github.com/urfave/cli"
"github.com/spf13/cobra"
)
type standaloneSignOptions struct {
output string // Output file path
}
func standaloneSignCmd() cli.Command {
func standaloneSignCmd() *cobra.Command {
opts := standaloneSignOptions{}
return cli.Command{
Name: "standalone-sign",
Usage: "Create a signature using local files",
ArgsUsage: "MANIFEST DOCKER-REFERENCE KEY-FINGERPRINT",
Action: commandAction(opts.run),
Flags: []cli.Flag{
cli.StringFlag{
Name: "output, o",
Usage: "output the signature to `SIGNATURE`",
Destination: &opts.output,
},
},
cmd := &cobra.Command{
Use: "standalone-sign [command options] MANIFEST DOCKER-REFERENCE KEY-FINGERPRINT",
Short: "Create a signature using local files",
RunE: commandAction(opts.run),
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.StringVarP(&opts.output, "output", "o", "", "output the signature to `SIGNATURE`")
return cmd
}
func (opts *standaloneSignOptions) run(args []string, stdout io.Writer) error {
@@ -64,14 +60,15 @@ func (opts *standaloneSignOptions) run(args []string, stdout io.Writer) error {
type standaloneVerifyOptions struct {
}
func standaloneVerifyCmd() cli.Command {
func standaloneVerifyCmd() *cobra.Command {
opts := standaloneVerifyOptions{}
return cli.Command{
Name: "standalone-verify",
Usage: "Verify a signature using local files",
ArgsUsage: "MANIFEST DOCKER-REFERENCE KEY-FINGERPRINT SIGNATURE",
Action: commandAction(opts.run),
cmd := &cobra.Command{
Use: "standalone-verify MANIFEST DOCKER-REFERENCE KEY-FINGERPRINT SIGNATURE",
Short: "Verify a signature using local files",
RunE: commandAction(opts.run),
}
adjustUsage(cmd)
return cmd
}
func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error {
@@ -115,15 +112,16 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
type untrustedSignatureDumpOptions struct {
}
func untrustedSignatureDumpCmd() cli.Command {
func untrustedSignatureDumpCmd() *cobra.Command {
opts := untrustedSignatureDumpOptions{}
return cli.Command{
Name: "untrusted-signature-dump-without-verification",
Usage: "Dump contents of a signature WITHOUT VERIFYING IT",
ArgsUsage: "SIGNATURE",
Hidden: true,
Action: commandAction(opts.run),
cmd := &cobra.Command{
Use: "untrusted-signature-dump-without-verification SIGNATURE",
Short: "Dump contents of a signature WITHOUT VERIFYING IT",
RunE: commandAction(opts.run),
Hidden: true,
}
adjustUsage(cmd)
return cmd
}
func (opts *untrustedSignatureDumpOptions) run(args []string, stdout io.Writer) error {

View File

@@ -58,8 +58,8 @@ func TestStandaloneSign(t *testing.T) {
// Error reading manifest
out, err := runSkopeo("standalone-sign", "-o", "/dev/null",
"/this/doesnt/exist", dockerReference, fixturesTestKeyFingerprint)
assertTestFailed(t, out, err, "/this/doesnt/exist")
"/this/does/not/exist", dockerReference, fixturesTestKeyFingerprint)
assertTestFailed(t, out, err, "/this/does/not/exist")
// Invalid Docker reference
out, err = runSkopeo("standalone-sign", "-o", "/dev/null",
@@ -117,14 +117,14 @@ func TestStandaloneVerify(t *testing.T) {
}
// Error reading manifest
out, err := runSkopeo("standalone-verify", "/this/doesnt/exist",
out, err := runSkopeo("standalone-verify", "/this/does/not/exist",
dockerReference, fixturesTestKeyFingerprint, signaturePath)
assertTestFailed(t, out, err, "/this/doesnt/exist")
assertTestFailed(t, out, err, "/this/does/not/exist")
// Error reading signature
out, err = runSkopeo("standalone-verify", manifestPath,
dockerReference, fixturesTestKeyFingerprint, "/this/doesnt/exist")
assertTestFailed(t, out, err, "/this/doesnt/exist")
dockerReference, fixturesTestKeyFingerprint, "/this/does/not/exist")
assertTestFailed(t, out, err, "/this/does/not/exist")
// Error verifying signature
out, err = runSkopeo("standalone-verify", manifestPath,
@@ -151,8 +151,8 @@ func TestUntrustedSignatureDump(t *testing.T) {
// Error reading manifest
out, err := runSkopeo("untrusted-signature-dump-without-verification",
"/this/doesnt/exist")
assertTestFailed(t, out, err, "/this/doesnt/exist")
"/this/does/not/exist")
assertTestFailed(t, out, err, "/this/does/not/exist")
// Error reading signature (input is not a signature)
out, err = runSkopeo("untrusted-signature-dump-without-verification", "fixtures/image.manifest.json")

View File

@@ -8,40 +8,46 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/copy"
"github.com/containers/image/v5/directory"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
// syncOptions contains information retrieved from the skopeo sync command line.
type syncOptions struct {
global *globalOptions // Global (not command dependant) skopeo options
global *globalOptions // Global (not command dependent) skopeo options
srcImage *imageOptions // Source image options
destImage *imageDestOptions // Destination image options
removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
source string // Source repository name
destination string // Destination registry name
scoped bool // When true, namespace copied images at destination using the source repository name
retryOpts *retry.RetryOptions
removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
format optionalString // Force conversion of the image to a specified format
source string // Source repository name
destination string // Destination registry name
scoped bool // When true, namespace copied images at destination using the source repository name
all bool // Copy all of the images if an image in the source is a list
}
// repoDescriptor contains information of a single repository used as a sync source.
type repoDescriptor struct {
DirBasePath string // base path when source is 'dir'
TaggedImages []types.ImageReference // List of tagged image found for the repository
Context *types.SystemContext // SystemContext for the sync command
DirBasePath string // base path when source is 'dir'
ImageRefs []types.ImageReference // List of tagged image found for the repository
Context *types.SystemContext // SystemContext for the sync command
}
// tlsVerify is an implementation of the Unmarshaler interface, used to
// tlsVerifyConfig is an implementation of the Unmarshaler interface, used to
// customize the unmarshaling behaviour of the tls-verify YAML key.
type tlsVerifyConfig struct {
skip types.OptionalBool // skip TLS verification check (false by default)
@@ -50,72 +56,59 @@ type tlsVerifyConfig struct {
// registrySyncConfig contains information about a single registry, read from
// the source YAML file
type registrySyncConfig struct {
Images map[string][]string // Images map images name to slices with the images' tags
Credentials types.DockerAuthConfig // Username and password used to authenticate with the registry
TLSVerify tlsVerifyConfig `yaml:"tls-verify"` // TLS verification mode (enabled by default)
CertDir string `yaml:"cert-dir"` // Path to the TLS certificates of the registry
Images map[string][]string // Images map images name to slices with the images' references (tags, digests)
ImagesByTagRegex map[string]string `yaml:"images-by-tag-regex"` // Images map images name to regular expression with the images' tags
Credentials types.DockerAuthConfig // Username and password used to authenticate with the registry
TLSVerify tlsVerifyConfig `yaml:"tls-verify"` // TLS verification mode (enabled by default)
CertDir string `yaml:"cert-dir"` // Path to the TLS certificates of the registry
}
// sourceConfig contains all registries information read from the source YAML file
type sourceConfig map[string]registrySyncConfig
func syncCmd(global *globalOptions) cli.Command {
func syncCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags()
srcFlags, srcOpts := dockerImageFlags(global, sharedOpts, "src-", "screds")
destFlags, destOpts := dockerImageFlags(global, sharedOpts, "dest-", "dcreds")
retryFlags, retryOpts := retryFlags()
opts := syncOptions{
global: global,
srcImage: srcOpts,
destImage: &imageDestOptions{imageOptions: destOpts},
retryOpts: retryOpts,
}
return cli.Command{
Name: "sync",
Usage: "Synchronize one or more images from one location to another",
Description: fmt.Sprint(`
cmd := &cobra.Command{
Use: "sync [command options] --src SOURCE-LOCATION --dest DESTINATION-LOCATION SOURCE DESTINATION",
Short: "Synchronize one or more images from one location to another",
Long: fmt.Sprint(`Copy all the images from a SOURCE to a DESTINATION.
Copy all the images from a SOURCE to a DESTINATION.
Allowed SOURCE transports (specified with --src): docker, dir, yaml.
Allowed DESTINATION transports (specified with --dest): docker, dir.
Allowed SOURCE transports (specified with --src): docker, dir, yaml.
Allowed DESTINATION transports (specified with --dest): docker, dir.
See skopeo-sync(1) for details.
`),
ArgsUsage: "--src SOURCE-LOCATION --dest DESTINATION-LOCATION SOURCE DESTINATION",
Action: commandAction(opts.run),
// FIXME: Do we need to namespace the GPG aspect?
Flags: append(append(append([]cli.Flag{
cli.BoolFlag{
Name: "remove-signatures",
Usage: "Do not copy signatures from SOURCE images",
Destination: &opts.removeSignatures,
},
cli.StringFlag{
Name: "sign-by",
Usage: "Sign the image using a GPG key with the specified `FINGERPRINT`",
Destination: &opts.signByFingerprint,
},
cli.StringFlag{
Name: "src, s",
Usage: "SOURCE transport type",
Destination: &opts.source,
},
cli.StringFlag{
Name: "dest, d",
Usage: "DESTINATION transport type",
Destination: &opts.destination,
},
cli.BoolFlag{
Name: "scoped",
Usage: "Images at DESTINATION are prefix using the full source image path as scope",
Destination: &opts.scoped,
},
}, sharedFlags...), srcFlags...), destFlags...),
See skopeo-sync(1) for details.
`),
RunE: commandAction(opts.run),
Example: `skopeo sync --src docker --dest dir --scoped registry.example.com/busybox /media/usb`,
}
adjustUsage(cmd)
flags := cmd.Flags()
flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE images")
flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
flags.VarP(newOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use when syncing image(s) to a destination (default is manifest type of source)`)
flags.StringVarP(&opts.source, "src", "s", "", "SOURCE transport type")
flags.StringVarP(&opts.destination, "dest", "d", "", "DESTINATION transport type")
flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope")
flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list")
flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&srcFlags)
flags.AddFlagSet(&destFlags)
flags.AddFlagSet(&retryFlags)
return cmd
}
// unmarshalYAML is the implementation of the Unmarshaler interface method
// UnmarshalYAML is the implementation of the Unmarshaler interface method
// method for the tlsVerifyConfig type.
// It unmarshals the 'tls-verify' YAML key so that, when they key is not
// specified, tls verification is enforced.
@@ -144,6 +137,18 @@ func newSourceConfig(yamlFile string) (sourceConfig, error) {
return cfg, nil
}
// parseRepositoryReference parses input into a reference.Named, and verifies that it names a repository, not an image.
func parseRepositoryReference(input string) (reference.Named, error) {
ref, err := reference.ParseNormalizedNamed(input)
if err != nil {
return nil, err
}
if !reference.IsNameOnly(ref) {
return nil, errors.Errorf("input names a reference, not a repository")
}
return ref, nil
}
// destinationReference creates an image reference using the provided transport.
// It returns a image reference to be used as destination of an image copy and
// any error encountered.
@@ -157,15 +162,14 @@ func destinationReference(destination string, transport string) (types.ImageRefe
case directory.Transport.Name():
_, err := os.Stat(destination)
if err == nil {
return nil, errors.Errorf(fmt.Sprintf("Refusing to overwrite destination directory %q", destination))
return nil, errors.Errorf("Refusing to overwrite destination directory %q", destination)
}
if !os.IsNotExist(err) {
return nil, errors.Wrap(err, "Destination directory could not be used")
}
// the directory holding the image must be created here
if err = os.MkdirAll(destination, 0755); err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("Error creating directory for image %s",
destination))
return nil, errors.Wrapf(err, "Error creating directory for image %s", destination)
}
imageTransport = directory.Transport
default:
@@ -175,21 +179,26 @@ func destinationReference(destination string, transport string) (types.ImageRefe
destRef, err := imageTransport.ParseReference(destination)
if err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("Cannot obtain a valid image reference for transport %q and reference %q", imageTransport.Name(), destination))
return nil, errors.Wrapf(err, "Cannot obtain a valid image reference for transport %q and reference %q", imageTransport.Name(), destination)
}
return destRef, nil
}
// getImageTags retrieves all the tags associated to an image hosted on a
// container registry.
// getImageTags lists all tags in a repository.
// It returns a string slice of tags and any error encountered.
func getImageTags(ctx context.Context, sysCtx *types.SystemContext, imgRef types.ImageReference) ([]string, error) {
name := imgRef.DockerReference().Name()
func getImageTags(ctx context.Context, sysCtx *types.SystemContext, repoRef reference.Named) ([]string, error) {
name := repoRef.Name()
logrus.WithFields(logrus.Fields{
"image": name,
}).Info("Getting tags")
tags, err := docker.GetRepositoryTags(ctx, sysCtx, imgRef)
// Ugly: NewReference rejects IsNameOnly references, and GetRepositoryTags ignores the tag/digest.
// So, we use TagNameOnly here only to shut up NewReference
dockerRef, err := docker.NewReference(reference.TagNameOnly(repoRef))
if err != nil {
return nil, err // Should never happen for a reference with tag and no digest
}
tags, err := docker.GetRepositoryTags(ctx, sysCtx, dockerRef)
switch err := err.(type) {
case nil:
@@ -200,51 +209,38 @@ func getImageTags(ctx context.Context, sysCtx *types.SystemContext, imgRef types
logrus.Warnf("Registry disallows tag list retrieval: %s", err)
break
default:
return tags, errors.Wrapf(err, fmt.Sprintf("Error determining repository tags for image %s", name))
return tags, errors.Wrapf(err, "Error determining repository tags for image %s", name)
}
return tags, nil
}
// isTagSpecified checks if an image name includes a tag and returns any errors
// encountered.
func isTagSpecified(imageName string) (bool, error) {
normNamed, err := reference.ParseNormalizedNamed(imageName)
if err != nil {
return false, err
}
tagged := !reference.IsNameOnly(normNamed)
logrus.WithFields(logrus.Fields{
"imagename": imageName,
"tagged": tagged,
}).Info("Tag presence check")
return tagged, nil
}
// imagesTopCopyFromRepo builds a list of image references from the tags
// found in the source repository.
// imagesToCopyFromRepo builds a list of image references from the tags
// found in a source repository.
// It returns an image reference slice with as many elements as the tags found
// and any error encountered.
func imagesToCopyFromRepo(repoReference types.ImageReference, repoName string, sourceCtx *types.SystemContext) ([]types.ImageReference, error) {
var sourceReferences []types.ImageReference
tags, err := getImageTags(context.Background(), sourceCtx, repoReference)
func imagesToCopyFromRepo(sys *types.SystemContext, repoRef reference.Named) ([]types.ImageReference, error) {
tags, err := getImageTags(context.Background(), sys, repoRef)
if err != nil {
return sourceReferences, err
return nil, err
}
var sourceReferences []types.ImageReference
for _, tag := range tags {
imageAndTag := fmt.Sprintf("%s:%s", repoName, tag)
ref, err := docker.ParseReference(imageAndTag)
taggedRef, err := reference.WithTag(repoRef, tag)
if err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("Cannot obtain a valid image reference for transport %q and reference %q", docker.Transport.Name(), imageAndTag))
return nil, errors.Wrapf(err, "Error creating a reference for repository %s and tag %q", repoRef.Name(), tag)
}
ref, err := docker.NewReference(taggedRef)
if err != nil {
return nil, errors.Wrapf(err, "Cannot obtain a valid image reference for transport %q and reference %s", docker.Transport.Name(), taggedRef.String())
}
sourceReferences = append(sourceReferences, ref)
}
return sourceReferences, nil
}
// imagesTopCopyFromDir builds a list of image references from the images found
// imagesToCopyFromDir builds a list of image references from the images found
// in the source directory.
// It returns an image reference slice with as many elements as the images found
// and any error encountered.
@@ -258,7 +254,7 @@ func imagesToCopyFromDir(dirPath string) ([]types.ImageReference, error) {
dirname := filepath.Dir(path)
ref, err := directory.Transport.ParseReference(dirname)
if err != nil {
return errors.Wrapf(err, fmt.Sprintf("Cannot obtain a valid image reference for transport %q and reference %q", directory.Transport.Name(), dirname))
return errors.Wrapf(err, "Cannot obtain a valid image reference for transport %q and reference %q", directory.Transport.Name(), dirname)
}
sourceReferences = append(sourceReferences, ref)
return filepath.SkipDir
@@ -268,86 +264,144 @@ func imagesToCopyFromDir(dirPath string) ([]types.ImageReference, error) {
if err != nil {
return sourceReferences,
errors.Wrapf(err, fmt.Sprintf("Error walking the path %q", dirPath))
errors.Wrapf(err, "Error walking the path %q", dirPath)
}
return sourceReferences, nil
}
// imagesTopCopyFromDir builds a list of repository descriptors from the images
// imagesToCopyFromRegistry builds a list of repository descriptors from the images
// in a registry configuration.
// It returns a repository descriptors slice with as many elements as the images
// found and any error encountered. Each element of the slice is a list of
// tagged image references, to be used as sync source.
// image references, to be used as sync source.
func imagesToCopyFromRegistry(registryName string, cfg registrySyncConfig, sourceCtx types.SystemContext) ([]repoDescriptor, error) {
serverCtx := &sourceCtx
// override ctx with per-registryName options
serverCtx.DockerCertPath = cfg.CertDir
serverCtx.DockerDaemonCertPath = cfg.CertDir
serverCtx.DockerDaemonInsecureSkipTLSVerify = (cfg.TLSVerify.skip == types.OptionalBoolTrue)
serverCtx.DockerInsecureSkipTLSVerify = cfg.TLSVerify.skip
if cfg.Credentials != (types.DockerAuthConfig{}) {
serverCtx.DockerAuthConfig = &cfg.Credentials
}
var repoDescList []repoDescriptor
for imageName, tags := range cfg.Images {
repoName := fmt.Sprintf("//%s", path.Join(registryName, imageName))
logrus.WithFields(logrus.Fields{
for imageName, refs := range cfg.Images {
repoLogger := logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
}).Info("Processing repo")
serverCtx := &sourceCtx
// override ctx with per-registryName options
serverCtx.DockerCertPath = cfg.CertDir
serverCtx.DockerDaemonCertPath = cfg.CertDir
serverCtx.DockerDaemonInsecureSkipTLSVerify = (cfg.TLSVerify.skip == types.OptionalBoolTrue)
serverCtx.DockerInsecureSkipTLSVerify = cfg.TLSVerify.skip
serverCtx.DockerAuthConfig = &cfg.Credentials
var sourceReferences []types.ImageReference
for _, tag := range tags {
source := fmt.Sprintf("%s:%s", repoName, tag)
imageRef, err := docker.ParseReference(source)
if err != nil {
logrus.WithFields(logrus.Fields{
"tag": source,
}).Error("Error processing tag, skipping")
logrus.Errorf("Error getting image reference: %s", err)
continue
}
sourceReferences = append(sourceReferences, imageRef)
})
repoRef, err := parseRepositoryReference(fmt.Sprintf("%s/%s", registryName, imageName))
if err != nil {
repoLogger.Error("Error parsing repository name, skipping")
logrus.Error(err)
continue
}
if len(tags) == 0 {
logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
}).Info("Querying registry for image tags")
repoLogger.Info("Processing repo")
imageRef, err := docker.ParseReference(repoName)
if err != nil {
logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
}).Error("Error processing repo, skipping")
logrus.Error(err)
continue
var sourceReferences []types.ImageReference
if len(refs) != 0 {
for _, ref := range refs {
tagLogger := logrus.WithFields(logrus.Fields{"ref": ref})
var named reference.Named
// first try as digest
if d, err := digest.Parse(ref); err == nil {
named, err = reference.WithDigest(repoRef, d)
if err != nil {
tagLogger.Error("Error processing ref, skipping")
logrus.Error(err)
continue
}
} else {
tagLogger.Debugf("Ref was not a digest, trying as a tag: %s", err)
named, err = reference.WithTag(repoRef, ref)
if err != nil {
tagLogger.Error("Error parsing ref, skipping")
logrus.Error(err)
continue
}
}
imageRef, err := docker.NewReference(named)
if err != nil {
tagLogger.Error("Error processing ref, skipping")
logrus.Errorf("Error getting image reference: %s", err)
continue
}
sourceReferences = append(sourceReferences, imageRef)
}
sourceReferences, err = imagesToCopyFromRepo(imageRef, repoName, serverCtx)
} else { // len(refs) == 0
repoLogger.Info("Querying registry for image tags")
sourceReferences, err = imagesToCopyFromRepo(serverCtx, repoRef)
if err != nil {
logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
}).Error("Error processing repo, skipping")
repoLogger.Error("Error processing repo, skipping")
logrus.Error(err)
continue
}
}
if len(sourceReferences) == 0 {
logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
}).Warnf("No tags to sync found")
repoLogger.Warnf("No refs to sync found")
continue
}
repoDescList = append(repoDescList, repoDescriptor{
TaggedImages: sourceReferences,
Context: serverCtx})
ImageRefs: sourceReferences,
Context: serverCtx})
}
for imageName, tagRegex := range cfg.ImagesByTagRegex {
repoLogger := logrus.WithFields(logrus.Fields{
"repo": imageName,
"registry": registryName,
})
repoRef, err := parseRepositoryReference(fmt.Sprintf("%s/%s", registryName, imageName))
if err != nil {
repoLogger.Error("Error parsing repository name, skipping")
logrus.Error(err)
continue
}
repoLogger.Info("Processing repo")
var sourceReferences []types.ImageReference
tagReg, err := regexp.Compile(tagRegex)
if err != nil {
repoLogger.WithFields(logrus.Fields{
"regex": tagRegex,
}).Error("Error parsing regex, skipping")
logrus.Error(err)
continue
}
repoLogger.Info("Querying registry for image tags")
allSourceReferences, err := imagesToCopyFromRepo(serverCtx, repoRef)
if err != nil {
repoLogger.Error("Error processing repo, skipping")
logrus.Error(err)
continue
}
repoLogger.Infof("Start filtering using the regular expression: %v", tagRegex)
for _, sReference := range allSourceReferences {
tagged, isTagged := sReference.DockerReference().(reference.Tagged)
if !isTagged {
repoLogger.Errorf("Internal error, reference %s does not have a tag, skipping", sReference.DockerReference())
continue
}
if tagReg.MatchString(tagged.Tag()) {
sourceReferences = append(sourceReferences, sReference)
}
}
if len(sourceReferences) == 0 {
repoLogger.Warnf("No refs to sync found")
continue
}
repoDescList = append(repoDescList, repoDescriptor{
ImageRefs: sourceReferences,
Context: serverCtx})
}
return repoDescList, nil
@@ -366,32 +420,29 @@ func imagesToCopy(source string, transport string, sourceCtx *types.SystemContex
desc := repoDescriptor{
Context: sourceCtx,
}
refName := fmt.Sprintf("//%s", source)
srcRef, err := docker.ParseReference(refName)
named, err := reference.ParseNormalizedNamed(source) // May be a repository or an image.
if err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("Cannot obtain a valid image reference for transport %q and reference %q", docker.Transport.Name(), refName))
return nil, errors.Wrapf(err, "Cannot obtain a valid image reference for transport %q and reference %q", docker.Transport.Name(), source)
}
imageTagged, err := isTagSpecified(source)
if err != nil {
return descriptors, err
}
imageTagged := !reference.IsNameOnly(named)
logrus.WithFields(logrus.Fields{
"imagename": source,
"tagged": imageTagged,
}).Info("Tag presence check")
if imageTagged {
desc.TaggedImages = append(desc.TaggedImages, srcRef)
descriptors = append(descriptors, desc)
break
}
desc.TaggedImages, err = imagesToCopyFromRepo(
srcRef,
fmt.Sprintf("//%s", source),
sourceCtx)
if err != nil {
return descriptors, err
}
if len(desc.TaggedImages) == 0 {
return descriptors, errors.Errorf("No images to sync found in %q", source)
srcRef, err := docker.NewReference(named)
if err != nil {
return nil, errors.Wrapf(err, "Cannot obtain a valid image reference for transport %q and reference %q", docker.Transport.Name(), named.String())
}
desc.ImageRefs = []types.ImageReference{srcRef}
} else {
desc.ImageRefs, err = imagesToCopyFromRepo(sourceCtx, named)
if err != nil {
return descriptors, err
}
if len(desc.ImageRefs) == 0 {
return descriptors, errors.Errorf("No images to sync found in %q", source)
}
}
descriptors = append(descriptors, desc)
@@ -405,11 +456,11 @@ func imagesToCopy(source string, transport string, sourceCtx *types.SystemContex
}
desc.DirBasePath = source
var err error
desc.TaggedImages, err = imagesToCopyFromDir(source)
desc.ImageRefs, err = imagesToCopyFromDir(source)
if err != nil {
return descriptors, err
}
if len(desc.TaggedImages) == 0 {
if len(desc.ImageRefs) == 0 {
return descriptors, errors.Errorf("No images to sync found in %q", source)
}
descriptors = append(descriptors, desc)
@@ -420,7 +471,7 @@ func imagesToCopy(source string, transport string, sourceCtx *types.SystemContex
return descriptors, err
}
for registryName, registryConfig := range cfg {
if len(registryConfig.Images) == 0 {
if len(registryConfig.Images) == 0 && len(registryConfig.ImagesByTagRegex) == 0 {
logrus.WithFields(logrus.Fields{
"registry": registryName,
}).Warn("No images specified for registry")
@@ -477,14 +528,33 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
return errors.New("sync from 'dir' to 'dir' not implemented, consider using rsync instead")
}
imageListSelection := copy.CopySystemImage
if opts.all {
imageListSelection = copy.CopyAllImages
}
sourceCtx, err := opts.srcImage.newSystemContext()
if err != nil {
return err
}
var manifestType string
if opts.format.present {
manifestType, err = parseManifestFormat(opts.format.value)
if err != nil {
return err
}
}
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
sourceArg := args[0]
srcRepoList, err := imagesToCopy(sourceArg, opts.source, sourceCtx)
if err != nil {
var srcRepoList []repoDescriptor
if err = retry.RetryIfNecessary(ctx, func() error {
srcRepoList, err = imagesToCopy(sourceArg, opts.source, sourceCtx)
return err
}, opts.retryOpts); err != nil {
return err
}
@@ -494,20 +564,20 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
return err
}
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
imagesNumber := 0
options := copy.Options{
RemoveSignatures: opts.removeSignatures,
SignBy: opts.signByFingerprint,
ReportWriter: os.Stdout,
DestinationCtx: destinationCtx,
RemoveSignatures: opts.removeSignatures,
SignBy: opts.signByFingerprint,
ReportWriter: os.Stdout,
DestinationCtx: destinationCtx,
ImageListSelection: imageListSelection,
OptimizeDestinationImageAlreadyExists: true,
ForceManifestMIMEType: manifestType,
}
for _, srcRepo := range srcRepoList {
options.SourceCtx = srcRepo.Context
for counter, ref := range srcRepo.TaggedImages {
for counter, ref := range srcRepo.ImageRefs {
var destSuffix string
switch ref.Transport() {
case docker.Transport:
@@ -534,11 +604,13 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
logrus.WithFields(logrus.Fields{
"from": transports.ImageName(ref),
"to": transports.ImageName(destRef),
}).Infof("Copying image tag %d/%d", counter+1, len(srcRepo.TaggedImages))
}).Infof("Copying image ref %d/%d", counter+1, len(srcRepo.ImageRefs))
_, err = copy.Image(ctx, policyContext, destRef, ref, &options)
if err != nil {
return errors.Wrapf(err, fmt.Sprintf("Error copying tag %q", transports.ImageName(ref)))
if err = retry.RetryIfNecessary(ctx, func() error {
_, err = copy.Image(ctx, policyContext, destRef, ref, &options)
return err
}, opts.retryOpts); err != nil {
return errors.Wrapf(err, "Error copying ref %q", transports.ImageName(ref))
}
imagesNumber++
}

View File

@@ -2,15 +2,20 @@ package main
import (
"context"
"fmt"
"io"
"os"
"strings"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// errorShouldDisplayUsage is a subtype of error used by command handlers to indicate that cli.ShowSubcommandHelp should be called.
@@ -18,16 +23,16 @@ type errorShouldDisplayUsage struct {
error
}
// commandAction intermediates between the cli.ActionFunc interface and the real handler,
// primarily to ensure that cli.Context is not available to the handler, which in turn
// makes sure that the cli.String() etc. flag access functions are not used,
// and everything is done using the *Options structures and the Destination: members of cli.Flag.
// handler may return errorShouldDisplayUsage to cause cli.ShowSubcommandHelp to be called.
func commandAction(handler func(args []string, stdout io.Writer) error) cli.ActionFunc {
return func(c *cli.Context) error {
err := handler(([]string)(c.Args()), c.App.Writer)
// commandAction intermediates between the RunE interface and the real handler,
// primarily to ensure that cobra.Command is not available to the handler, which in turn
// makes sure that the cmd.Flags() etc. flag access functions are not used,
// and everything is done using the *Options structures and the *Var() methods of cmd.Flag().
// handler may return errorShouldDisplayUsage to cause c.Help to be called.
func commandAction(handler func(args []string, stdout io.Writer) error) func(cmd *cobra.Command, args []string) error {
return func(c *cobra.Command, args []string) error {
err := handler(args, c.OutOrStdout())
if _, ok := err.(errorShouldDisplayUsage); ok {
cli.ShowSubcommandHelp(c)
c.Help()
}
return err
}
@@ -39,20 +44,15 @@ type sharedImageOptions struct {
authFilePath string // Path to a */containers/auth.json
}
// imageFlags prepares a collection of CLI flags writing into sharedImageOptions, and the managed sharedImageOptions structure.
func sharedImageFlags() ([]cli.Flag, *sharedImageOptions) {
// sharedImageFlags prepares a collection of CLI flags writing into sharedImageOptions, and the managed sharedImageOptions structure.
func sharedImageFlags() (pflag.FlagSet, *sharedImageOptions) {
opts := sharedImageOptions{}
return []cli.Flag{
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Example: ${XDG_RUNTIME_DIR}/containers/auth.json",
Value: os.Getenv("REGISTRY_AUTH_FILE"),
Destination: &opts.authFilePath,
},
}, &opts
fs := pflag.FlagSet{}
fs.StringVar(&opts.authFilePath, "authfile", os.Getenv("REGISTRY_AUTH_FILE"), "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json")
return fs, &opts
}
// imageOptions collects CLI flags specific to the "docker" transport, which are
// dockerImageOptions collects CLI flags specific to the "docker" transport, which are
// the same across subcommands, but may be different for each image
// (e.g. may differ between the source and destination of a copy)
type dockerImageOptions struct {
@@ -60,6 +60,7 @@ type dockerImageOptions struct {
shared *sharedImageOptions // May be shared across several imageOptions instances.
authFilePath optionalString // Path to a */containers/auth.json (prefixed version to override shared image option).
credsOption optionalString // username[:password] for accessing a registry
registryToken optionalString // token to be used directly as a Bearer token when accessing the registry
dockerCertPath string // A directory using Docker-like *.{crt,cert,key} files for connecting to a registry or a daemon
tlsVerify optionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:)
noCreds bool // Access the registry anonymously
@@ -75,101 +76,72 @@ type imageOptions struct {
// dockerImageFlags prepares a collection of docker-transport specific CLI flags
// writing into imageOptions, and the managed imageOptions structure.
func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageOptions) {
opts := imageOptions{
func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) {
flags := imageOptions{
dockerImageOptions: dockerImageOptions{
global: global,
shared: shared,
},
}
// This is horribly ugly, but we need to support the old option forms of (skopeo copy) for compatibility.
// Don't add any more cases like this.
credsOptionExtra := ""
if credsOptionAlias != "" {
credsOptionExtra += "," + credsOptionAlias
}
var flags []cli.Flag
fs := pflag.FlagSet{}
if flagPrefix != "" {
// the non-prefixed flag is handled by a shared flag.
flags = append(flags,
cli.GenericFlag{
Name: flagPrefix + "authfile",
Usage: "path of the authentication file. Example: ${XDG_RUNTIME_DIR}/containers/auth.json",
Value: newOptionalStringValue(&opts.authFilePath),
},
)
fs.Var(newOptionalStringValue(&flags.authFilePath), flagPrefix+"authfile", "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json")
}
flags = append(flags,
cli.GenericFlag{
Name: flagPrefix + "creds" + credsOptionExtra,
Usage: "Use `USERNAME[:PASSWORD]` for accessing the registry",
Value: newOptionalStringValue(&opts.credsOption),
},
cli.StringFlag{
Name: flagPrefix + "cert-dir",
Usage: "use certificates at `PATH` (*.crt, *.cert, *.key) to connect to the registry or daemon",
Destination: &opts.dockerCertPath,
},
cli.GenericFlag{
Name: flagPrefix + "tls-verify",
Usage: "require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)",
Value: newOptionalBoolValue(&opts.tlsVerify),
},
cli.BoolFlag{
Name: flagPrefix + "no-creds",
Usage: "Access the registry anonymously",
Destination: &opts.noCreds,
},
)
return flags, &opts
fs.Var(newOptionalStringValue(&flags.credsOption), flagPrefix+"creds", "Use `USERNAME[:PASSWORD]` for accessing the registry")
if credsOptionAlias != "" {
// This is horribly ugly, but we need to support the old option forms of (skopeo copy) for compatibility.
// Don't add any more cases like this.
f := fs.VarPF(newOptionalStringValue(&flags.credsOption), credsOptionAlias, "", "Use `USERNAME[:PASSWORD]` for accessing the registry")
f.Hidden = true
}
fs.Var(newOptionalStringValue(&flags.registryToken), flagPrefix+"registry-token", "Provide a Bearer token for accessing the registry")
fs.StringVar(&flags.dockerCertPath, flagPrefix+"cert-dir", "", "use certificates at `PATH` (*.crt, *.cert, *.key) to connect to the registry or daemon")
optionalBoolFlag(&fs, &flags.tlsVerify, flagPrefix+"tls-verify", "require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)")
fs.BoolVar(&flags.noCreds, flagPrefix+"no-creds", false, "Access the registry anonymously")
return fs, &flags
}
// imageFlags prepares a collection of CLI flags writing into imageOptions, and the managed imageOptions structure.
func imageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageOptions) {
func imageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) {
dockerFlags, opts := dockerImageFlags(global, shared, flagPrefix, credsOptionAlias)
return append(dockerFlags, []cli.Flag{
cli.StringFlag{
Name: flagPrefix + "shared-blob-dir",
Usage: "`DIRECTORY` to use to share blobs across OCI repositories",
Destination: &opts.sharedBlobDir,
},
cli.StringFlag{
Name: flagPrefix + "daemon-host",
Usage: "use docker daemon host at `HOST` (docker-daemon: only)",
Destination: &opts.dockerDaemonHost,
},
}...), opts
fs := pflag.FlagSet{}
fs.StringVar(&opts.sharedBlobDir, flagPrefix+"shared-blob-dir", "", "`DIRECTORY` to use to share blobs across OCI repositories")
fs.StringVar(&opts.dockerDaemonHost, flagPrefix+"daemon-host", "", "use docker daemon host at `HOST` (docker-daemon: only)")
fs.AddFlagSet(&dockerFlags)
return fs, opts
}
type retryOptions struct {
maxRetry int // The number of times to possibly retry
}
func retryFlags() (pflag.FlagSet, *retry.RetryOptions) {
opts := retry.RetryOptions{}
fs := pflag.FlagSet{}
fs.IntVar(&opts.MaxRetry, "retry-times", 0, "the number of times to possibly retry")
return fs, &opts
}
// newSystemContext returns a *types.SystemContext corresponding to opts.
// It is guaranteed to return a fresh instance, so it is safe to make additional updates to it.
func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
ctx := &types.SystemContext{
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,
}
// *types.SystemContext instance from globalOptions
// imageOptions option overrides the instance if both are present.
ctx := opts.global.newSystemContext()
ctx.DockerCertPath = opts.dockerCertPath
ctx.OCISharedBlobDirPath = opts.sharedBlobDir
ctx.AuthFilePath = opts.shared.authFilePath
ctx.DockerDaemonHost = opts.dockerDaemonHost
ctx.DockerDaemonCertPath = opts.dockerCertPath
if opts.dockerImageOptions.authFilePath.present {
ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value
}
if opts.tlsVerify.present {
ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.value
}
// DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided.
if opts.global.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.global.tlsVerify.value)
}
if opts.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
@@ -183,6 +155,9 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
return nil, err
}
}
if opts.registryToken.present {
ctx.DockerBearerRegistryToken = opts.registryToken.value
}
if opts.noCreds {
ctx.DockerAuthConfig = &types.DockerAuthConfig{}
}
@@ -190,7 +165,7 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
return ctx, nil
}
// imageDestOptions is a superset of imageOptions specialized for iamge destinations.
// imageDestOptions is a superset of imageOptions specialized for image destinations.
type imageDestOptions struct {
*imageOptions
dirForceCompression bool // Compress layers when saving to the dir: transport
@@ -200,32 +175,16 @@ type imageDestOptions struct {
}
// imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure.
func imageDestFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageDestOptions) {
func imageDestFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageDestOptions) {
genericFlags, genericOptions := imageFlags(global, shared, flagPrefix, credsOptionAlias)
opts := imageDestOptions{imageOptions: genericOptions}
return append(genericFlags, []cli.Flag{
cli.BoolFlag{
Name: flagPrefix + "compress",
Usage: "Compress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)",
Destination: &opts.dirForceCompression,
},
cli.BoolFlag{
Name: flagPrefix + "oci-accept-uncompressed-layers",
Usage: "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)",
Destination: &opts.ociAcceptUncompressedLayers,
},
cli.StringFlag{
Name: flagPrefix + "compress-format",
Usage: "`FORMAT` to use for the compression",
Destination: &opts.compressionFormat,
},
cli.GenericFlag{
Name: flagPrefix + "compress-level",
Usage: "`LEVEL` to use for the compression",
Value: newOptionalIntValue(&opts.compressionLevel),
},
}...), &opts
fs := pflag.FlagSet{}
fs.AddFlagSet(&genericFlags)
fs.BoolVar(&opts.dirForceCompression, flagPrefix+"compress", false, "Compress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)")
fs.BoolVar(&opts.ociAcceptUncompressedLayers, flagPrefix+"oci-accept-uncompressed-layers", false, "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)")
fs.StringVar(&opts.compressionFormat, flagPrefix+"compress-format", "", "`FORMAT` to use for the compression")
fs.Var(newOptionalIntValue(&opts.compressionLevel), flagPrefix+"compress-level", "`LEVEL` to use for the compression")
return fs, &opts
}
// newSystemContext returns a *types.SystemContext corresponding to opts.
@@ -276,20 +235,6 @@ func getDockerAuth(creds string) (*types.DockerAuthConfig, error) {
}, nil
}
// parseImage converts image URL-like string to an initialized handler for that image.
// The caller must call .Close() on the returned ImageCloser.
func parseImage(ctx context.Context, opts *imageOptions, name string) (types.ImageCloser, error) {
ref, err := alltransports.ParseImageName(name)
if err != nil {
return nil, err
}
sys, err := opts.newSystemContext()
if err != nil {
return nil, err
}
return ref.NewImage(ctx, sys)
}
// parseImageSource converts image URL-like string to an ImageSource.
// The caller must call .Close() on the returned ImageSource.
func parseImageSource(ctx context.Context, opts *imageOptions, name string) (types.ImageSource, error) {
@@ -303,3 +248,47 @@ func parseImageSource(ctx context.Context, opts *imageOptions, name string) (typ
}
return ref.NewImageSource(ctx, sys)
}
// parseManifestFormat parses format parameter for copy and sync command.
// It returns string value to use as manifest MIME type
func parseManifestFormat(manifestFormat string) (string, error) {
switch manifestFormat {
case "oci":
return imgspecv1.MediaTypeImageManifest, nil
case "v2s1":
return manifest.DockerV2Schema1SignedMediaType, nil
case "v2s2":
return manifest.DockerV2Schema2MediaType, nil
default:
return "", fmt.Errorf("unknown format %q. Choose one of the supported formats: 'oci', 'v2s1', or 'v2s2'", manifestFormat)
}
}
// usageTemplate returns the usage template for skopeo commands
// This blocks the displaying of the global options. The main skopeo
// command should not use this.
const usageTemplate = `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
{{end}}
`
// adjustUsage uses usageTemplate template to get rid the GlobalOption from usage
// and disable [flag] at the end of command usage
func adjustUsage(c *cobra.Command) {
c.SetUsageTemplate(usageTemplate)
c.DisableFlagsInUseLine = true
}

View File

@@ -1,42 +1,35 @@
package main
import (
"flag"
"os"
"testing"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// fakeGlobalOptions creates globalOptions and sets it according to flags.
// NOTE: This is QUITE FAKE; none of the urfave/cli normalization and the like happens.
func fakeGlobalOptions(t *testing.T, flags []string) *globalOptions {
func fakeGlobalOptions(t *testing.T, flags []string) (*globalOptions, *cobra.Command) {
app, opts := createApp()
flagSet := flag.NewFlagSet(app.Name, flag.ContinueOnError)
for _, f := range app.Flags {
f.Apply(flagSet)
}
err := flagSet.Parse(flags)
cmd := &cobra.Command{}
app.AddCommand(cmd)
err := cmd.ParseFlags(flags)
require.NoError(t, err)
return opts
return opts, cmd
}
// fakeImageOptions creates imageOptions and sets it according to globalFlags/cmdFlags.
// NOTE: This is QUITE FAKE; none of the urfave/cli normalization and the like happens.
func fakeImageOptions(t *testing.T, flagPrefix string, globalFlags []string, cmdFlags []string) *imageOptions {
globalOpts := fakeGlobalOptions(t, globalFlags)
globalOpts, cmd := fakeGlobalOptions(t, globalFlags)
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(globalOpts, sharedOpts, flagPrefix, "")
flagSet := flag.NewFlagSet("fakeImageOptions", flag.ContinueOnError)
for _, f := range append(sharedFlags, imageFlags...) {
f.Apply(flagSet)
}
err := flagSet.Parse(cmdFlags)
cmd.Flags().AddFlagSet(&sharedFlags)
cmd.Flags().AddFlagSet(&imageFlags)
err := cmd.ParseFlags(cmdFlags)
require.NoError(t, err)
return imageOpts
}
@@ -46,7 +39,9 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
opts := fakeImageOptions(t, "dest-", []string{}, []string{})
res, err := opts.newSystemContext()
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{}, res)
assert.Equal(t, &types.SystemContext{
DockerRegistryUserAgent: defaultUserAgent,
}, res)
// Set everything to non-default values.
opts = fakeImageOptions(t, "dest-", []string{
@@ -63,6 +58,7 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
"--dest-daemon-host", "daemon-host.example.com",
"--dest-tls-verify=false",
"--dest-creds", "creds-user:creds-password",
"--dest-registry-token", "faketoken",
})
res, err = opts.newSystemContext()
require.NoError(t, err)
@@ -76,9 +72,11 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
DockerCertPath: "/srv/cert-dir",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"},
DockerBearerRegistryToken: "faketoken",
DockerDaemonCertPath: "/srv/cert-dir",
DockerDaemonHost: "daemon-host.example.com",
DockerDaemonInsecureSkipTLSVerify: true,
DockerRegistryUserAgent: defaultUserAgent,
BigFilesTemporaryDir: "/srv",
}, res)
@@ -120,17 +118,13 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
}
// fakeImageDestOptions creates imageDestOptions and sets it according to globalFlags/cmdFlags.
// NOTE: This is QUITE FAKE; none of the urfave/cli normalization and the like happens.
func fakeImageDestOptions(t *testing.T, flagPrefix string, globalFlags []string, cmdFlags []string) *imageDestOptions {
globalOpts := fakeGlobalOptions(t, globalFlags)
globalOpts, cmd := fakeGlobalOptions(t, globalFlags)
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageDestFlags(globalOpts, sharedOpts, flagPrefix, "")
flagSet := flag.NewFlagSet("fakeImageDestOptions", flag.ContinueOnError)
for _, f := range append(sharedFlags, imageFlags...) {
f.Apply(flagSet)
}
err := flagSet.Parse(cmdFlags)
cmd.Flags().AddFlagSet(&sharedFlags)
cmd.Flags().AddFlagSet(&imageFlags)
err := cmd.ParseFlags(cmdFlags)
require.NoError(t, err)
return imageOpts
}
@@ -140,7 +134,9 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
opts := fakeImageDestOptions(t, "dest-", []string{}, []string{})
res, err := opts.newSystemContext()
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{}, res)
assert.Equal(t, &types.SystemContext{
DockerRegistryUserAgent: defaultUserAgent,
}, res)
oldXRD, hasXRD := os.LookupEnv("REGISTRY_AUTH_FILE")
defer func() {
@@ -160,7 +156,10 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
})
res, err = opts.newSystemContext()
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{AuthFilePath: authFile}, res)
assert.Equal(t, &types.SystemContext{
AuthFilePath: authFile,
DockerRegistryUserAgent: defaultUserAgent,
}, res)
// Set everything to non-default values.
opts = fakeImageDestOptions(t, "dest-", []string{
@@ -177,6 +176,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
"--dest-daemon-host", "daemon-host.example.com",
"--dest-tls-verify=false",
"--dest-creds", "creds-user:creds-password",
"--dest-registry-token", "faketoken",
})
res, err = opts.newSystemContext()
require.NoError(t, err)
@@ -190,9 +190,11 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
DockerCertPath: "/srv/cert-dir",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"},
DockerBearerRegistryToken: "faketoken",
DockerDaemonCertPath: "/srv/cert-dir",
DockerDaemonHost: "daemon-host.example.com",
DockerDaemonInsecureSkipTLSVerify: true,
DockerRegistryUserAgent: defaultUserAgent,
DirForceCompress: true,
BigFilesTemporaryDir: "/srv",
}, res)
@@ -203,6 +205,38 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
assert.Error(t, err)
}
func TestParseManifestFormat(t *testing.T) {
for _, testCase := range []struct {
formatParam string
expectedManifestType string
expectErr bool
}{
{"oci",
imgspecv1.MediaTypeImageManifest,
false},
{"v2s1",
manifest.DockerV2Schema1SignedMediaType,
false},
{"v2s2",
manifest.DockerV2Schema2MediaType,
false},
{"",
"",
true},
{"badValue",
"",
true},
} {
manifestType, err := parseManifestFormat(testCase.formatParam)
if testCase.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
assert.Equal(t, manifestType, testCase.expectedManifestType)
}
}
// since there is a shared authfile image option and a non-shared (prefixed) one, make sure the override logic
// works correctly.
func TestImageOptionsAuthfileOverride(t *testing.T) {
@@ -242,7 +276,8 @@ func TestImageOptionsAuthfileOverride(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, &types.SystemContext{
AuthFilePath: testCase.expectedAuthfilePath,
AuthFilePath: testCase.expectedAuthfilePath,
DockerRegistryUserAgent: defaultUserAgent,
}, res)
}
}

View File

@@ -49,6 +49,8 @@ _skopeo_copy() {
--dest-tls-verify
--src-daemon-host
--dest-daemon-host
--src-registry-token
--dest-registry-token
"
local boolean_options="
@@ -68,11 +70,50 @@ _skopeo_copy() {
_complete_ "$options_with_args" "$boolean_options" "$transports"
}
_skopeo_sync() {
local options_with_args="
--authfile
--dest
--dest-authfile
--dest-cert-
--dest-creds
--dest-registry-token string
--format
--retry-times
--sign-by
--src
--src-authfile
--src-cert-dir
--src-creds
--src-registry-token
"
local boolean_options="
--all
--dest-no-creds
--dest-tls-verify
--remove-signatures
--scoped
--src-no-creds
--src-tls-verify
"
local transports
transports="
$(_skopeo_supported_transports "${FUNCNAME//"_skopeo_"/}")
"
_complete_ "$options_with_args" "$boolean_options" "$transports"
}
_skopeo_inspect() {
local options_with_args="
--authfile
--creds
--cert-dir
--format
--retry-times
--registry-token
"
local boolean_options="
--config
@@ -119,6 +160,7 @@ _skopeo_delete() {
--authfile
--creds
--cert-dir
--registry-token
"
local boolean_options="
--tls-verify
@@ -135,11 +177,14 @@ _skopeo_delete() {
_skopeo_layers() {
local options_with_args="
--authfile
--creds
--cert-dir
--registry-token
"
local boolean_options="
--tls-verify
--no-creds
"
_complete_ "$options_with_args" "$boolean_options"
}
@@ -149,6 +194,7 @@ _skopeo_list_repository_tags() {
--authfile
--creds
--cert-dir
--registry-token
"
local boolean_options="
@@ -158,8 +204,35 @@ _skopeo_list_repository_tags() {
_complete_ "$options_with_args" "$boolean_options"
}
_skopeo_login() {
local options_with_args="
--authfile
--cert-dir
--password -p
--username -u
"
local boolean_options="
--get-login
--tls-verify
--password-stdin
"
_complete_ "$options_with_args" "$boolean_options"
}
_skopeo_logout() {
local options_with_args="
--authfile
"
local boolean_options="
--all -a
"
_complete_ "$options_with_args" "$boolean_options"
}
_skopeo_skopeo() {
# XXX: Changes here need to be refleceted in the manually expanded
# XXX: Changes here need to be reflected in the manually expanded
# string in the `case` statement below as well.
local options_with_args="
--policy
@@ -177,8 +250,23 @@ _skopeo_skopeo() {
--help -h
"
local commands=(
copy
delete
inspect
list-tags
login
logout
manifest-digest
standalone-sign
standalone-verify
sync
help
h
)
case "$prev" in
# XXX: Changes here need to be refleceted in $options_with_args as well.
# XXX: Changes here need to be reflected in $options_with_args as well.
--policy|--registries.d|--override-arch|--override-os|--override-variant|--command-timeout)
return
;;
@@ -189,8 +277,6 @@ _skopeo_skopeo() {
while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "$boolean_options $options_with_args" -- "$cur")
;;
*)
commands=$( "${COMP_WORDS[@]:0:$COMP_CWORD}" --generate-bash-completion )
while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${commands[*]} help" -- "$cur")
;;
esac
@@ -210,7 +296,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|list-repository-tags)
skopeo|copy|sync|inspect|delete|manifest-digest|standalone-sign|standalone-verify|help|h|list-repository-tags)
command="${words[$counter]//-/_}"
cpos=$counter
(( cpos++ ))

102
contrib/cirrus/runner.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
# This script is intended to be executed by automation or humans
# under a hack/get_ci_vm.sh context. Use under any other circumstances
# is unlikely to function.
set -e
_EOL=20250501
if [[ $(date +%Y%m%d) -ge $_EOL ]]; then
die "As of $_EOL this branch is probably
no longer supported in RHEL 8.4, please
confirm this with RHEL Program Management. If so:
It should be removed from Cirrus-Cron,
the .cirrus.yml file removed, and
the VM images (manually) unmarked
'permanent=true'"
fi
if [[ -r "/etc/automation_environment" ]]; then
source /etc/automation_environment
source $AUTOMATION_LIB_PATH/common_lib.sh
else
(
echo "WARNING: It does not appear that containers/automation was installed."
echo " Functionality of most of ${BASH_SOURCE[0]} will be negatively"
echo " impacted."
) > /dev/stderr
fi
OS_RELEASE_ID="$(source /etc/os-release; echo $ID)"
# GCE image-name compatible string representation of distribution _major_ version
OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | tr -d '.')"
# Combined to ease some usage
OS_REL_VER="${OS_RELEASE_ID}-${OS_RELEASE_VER}"
export "PATH=$PATH:$GOPATH/bin"
podmanmake() {
req_env_vars GOPATH SKOPEO_PATH SKOPEO_CI_CONTAINER_FQIN
warn "Accumulated technical-debt requires execution inside a --privileged container. This is very likely hiding bugs!"
showrun podman run -it --rm --privileged \
-e GOPATH=$GOPATH \
-v $GOPATH:$GOPATH:Z \
-w $SKOPEO_PATH \
$SKOPEO_CI_CONTAINER_FQIN \
make "$@"
}
_run_setup() {
if [[ "$OS_RELEASE_ID" == "fedora" ]]; then
# This is required as part of the standard Fedora VM setup
growpart /dev/sda 1
resize2fs /dev/sda1
# VM's come with the distro. skopeo pre-installed
dnf erase -y skopeo
else
die "Unknown/unsupported distro. $OS_REL_VER"
fi
}
_run_vendor() {
podmanmake vendor BUILDTAGS="$BUILDTAGS"
}
_run_build() {
podmanmake bin/skopeo BUILDTAGS="$BUILDTAGS"
}
_run_validate() {
podmanmake validate-local BUILDTAGS="$BUILDTAGS"
}
_run_unit() {
podmanmake test-integration-local BUILDTAGS="$BUILDTAGS"
}
_run_integration() {
podmanmake test-integration-local BUILDTAGS="$BUILDTAGS"
}
_run_system() {
# Ensure we start with a clean-slate
podman system reset --force
# Executes with containers required for testing.
showrun make test-system-local BUILDTAGS="$BUILDTAGS"
}
req_env_vars SKOPEO_PATH BUILDTAGS
handler="_run_${1}"
if [ "$(type -t $handler)" != "function" ]; then
die "Unknown/Unsupported command-line argument '$1'"
fi
msg "************************************************************"
msg "Runner executing $1 on $OS_REL_VER"
msg "************************************************************"
cd "$SKOPEO_PATH"
$handler

View File

@@ -0,0 +1,43 @@
<img src="https://cdn.rawgit.com/containers/skopeo/master/docs/skopeo.svg" width="250">
----
# skopeoimage
## Overview
This directory contains the Dockerfiles necessary to create the three skopeoimage container
images that are housed on quay.io under the skopeo account. All three repositories where
the images live are public and can be pulled without credentials. These container images
are secured and the resulting containers can run safely. The container images are built
using the latest Fedora and then Skopeo is installed into them:
* quay.io/skopeo/stable - This image is built using the latest stable version of Skopeo in a Fedora based container. Built with skopeoimage/stable/Dockerfile.
* quay.io/skopeo/upstream - This image is built using the latest code found in this GitHub repository. When someone creates a commit and pushes it, the image is created. Due to that the image changes frequently and is not guaranteed to be stable. Built with skopeoimage/upstream/Dockerfile.
* quay.io/skopeo/testing - This image is built using the latest version of Skopeo that is or was in updates testing for Fedora. At times this may be the same as the stable image. This container image will primarily be used by the development teams for verification testing when a new package is created. Built with skopeoimage/testing/Dockerfile.
## Multiarch images
Multiarch images are available for Skopeo upstream and stable versions. Supported architectures are `amd64`, `s390x`, `ppc64le`.
Available images are `quay.io/skopeo/upstream:master`, `quay.io/skopeo/stable:v1.2.0`, `quay.io/containers/skopeo:v1.2.0`.
Images can be used the same way as in a single architecture case, no extra setup is required. For samples see next chapter.
## Sample Usage
Although not required, it is suggested that [Podman](https://github.com/containers/podman) be used with these container images.
```
# Get Help on Skopeo
podman run docker://quay.io/skopeo/stable:latest --help
# Get help on the Skopeo Copy command
podman run docker://quay.io/skopeo/stable:latest copy --help
# Copy the Skopeo container image from quay.io to
# a private registry
podman run docker://quay.io/skopeo/stable:latest copy docker://quay.io/skopeo/stable docker://registry.internal.company.com/skopeo
# Inspect the fedora:latest image
podman run docker://quay.io/skopeo/stable:latest inspect --config docker://registry.fedoraproject.org/fedora:latest | jq
```

View File

@@ -0,0 +1,33 @@
# stable/Dockerfile
#
# Build a Skopeo container image from the latest
# stable version of Skopeo on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=skopeo
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM registry.fedoraproject.org/fedora:33
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space. Also reinstall shadow-utils as without
# doing so, the setuid/setgid bits on newuidmap
# and newgidmap are lost in the Fedora images.
RUN useradd skopeo; yum -y update; yum -y reinstall shadow-utils; yum -y install skopeo fuse-overlayfs --exclude container-selinux; yum -y clean all; rm -rf /var/cache/dnf/* /var/log/dnf* /var/log/yum*
# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
# Setup the ability to use additional stores
# with this container image.
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
# Setup skopeo's uid/guid entries
RUN echo skopeo:100000:65536 > /etc/subuid
RUN echo skopeo:100000:65536 > /etc/subgid
# Point to the Authorization file
ENV REGISTRY_AUTH_FILE=/tmp/auth.json
# Set the entrypoint
ENTRYPOINT ["/usr/bin/skopeo"]

View File

@@ -0,0 +1,34 @@
# testing/Dockerfile
#
# Build a Skopeo container image from the latest
# version of Skopeo that is in updates-testing
# on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=skopeo
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM registry.fedoraproject.org/fedora:33
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space. Also reinstall shadow-utils as without
# doing so, the setuid/setgid bits on newuidmap
# and newgidmap are lost in the Fedora images.
RUN useradd skopeo; yum -y update; yum -y reinstall shadow-utils; yum -y install skopeo fuse-overlayfs --enablerepo updates-testing --exclude container-selinux; yum -y clean all; rm -rf /var/cache/dnf/* /var/log/dnf* /var/log/yum*
# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
# Setup the ability to use additional stores
# with this container image.
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
# Setup skopeo's uid/guid entries
RUN echo skopeo:100000:65536 > /etc/subuid
RUN echo skopeo:100000:65536 > /etc/subgid
# Point to the Authorization file
ENV REGISTRY_AUTH_FILE=/tmp/auth.json
# Set the entrypoint
ENTRYPOINT ["/usr/bin/skopeo"]

View File

@@ -0,0 +1,54 @@
# upstream/Dockerfile
#
# Build a Skopeo container image from the latest
# upstream version of Skopeo on GitHub.
# https://github.com/containers/skopeo
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM registry.fedoraproject.org/fedora:33
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space. Also reinstall shadow-utils as without
# doing so, the setuid/setgid bits on newuidmap
# and newgidmap are lost in the Fedora images.
RUN useradd skopeo; yum -y update; yum -y reinstall shadow-utils; \
yum -y install make \
golang \
git \
go-md2man \
fuse-overlayfs \
fuse3 \
containers-common \
gpgme-devel \
libassuan-devel \
btrfs-progs-devel \
device-mapper-devel --enablerepo updates-testing --exclude container-selinux; \
mkdir /root/skopeo; \
git clone https://github.com/containers/skopeo /root/skopeo/src/github.com/containers/skopeo; \
export GOPATH=/root/skopeo; \
cd /root/skopeo/src/github.com/containers/skopeo; \
make bin/skopeo;\
make PREFIX=/usr install;\
rm -rf /root/skopeo/*; \
yum -y remove git golang go-md2man make; \
yum -y clean all; yum -y clean all; rm -rf /var/cache/dnf/* /var/log/dnf* /var/log/yum*
# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
# Setup the ability to use additional stores
# with this container image.
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
# Setup skopeo's uid/guid entries
RUN echo skopeo:100000:65536 > /etc/subuid
RUN echo skopeo:100000:65536 > /etc/subgid
# Point to the Authorization file
ENV REGISTRY_AUTH_FILE=/tmp/auth.json
# Set the entrypoint
ENTRYPOINT ["/usr/bin/skopeo"]

View File

@@ -15,6 +15,9 @@ Uses the system's trust policy to validate images, rejects images not trusted by
_destination-image_ use the "image name" format described above
_source-image_ and _destination-image_ are interpreted completely independently; e.g. the destination name does not
automatically inherit any parts of the source name.
## OPTIONS
**--all**
@@ -25,7 +28,7 @@ the images in the list, and the list itself.
**--authfile** _path_
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `skopeo 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
@@ -39,6 +42,10 @@ Path of the authentication file for the source registry. Uses path given by `--a
Path of the authentication file for the destination registry. Uses path given by `--authfile`, if not provided.
**--digestfile** _path_
After copying the image, write the digest of the resulting image to the file.
**--format, -f** _manifest-type_ Manifest type (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)
**--quiet, -q** suppress output information when copying images
@@ -47,29 +54,29 @@ Path of the authentication file for the destination registry. Uses path given by
**--sign-by=**_key-id_ add a signature using that key ID for an image name corresponding to _destination-image_
**--encryption-key** _Key_ a reference prefixed with the encryption protocol to use. The supported protocols are JWE, PGP and PKCS7. For instance, jwe:/path/to/key.pem or pgp:admin@example.com or pkcs7:/path/to/x509-file. This feature is still *experimental*.
**--encryption-key** _protocol:keyfile_ specifies the encryption protocol, which can be JWE (RFC7516), PGP (RFC4880), and PKCS7 (RFC2315) and the key material required for image encryption. For instance, jwe:/path/to/key.pem or pgp:admin@example.com or pkcs7:/path/to/x509-file.
**--decryption-key** _Key_ a reference required to perform decryption of container images. This should point to files which represent keys and/or certificates that can be used for decryption. Decryption will be tried with all keys. This feature is still *experimental*.
**--decryption-key** _key[:passphrase]_ to be used for decryption of images. Key can point to keys and/or certificates. Decryption will be tried with all keys. If the key is protected by a passphrase, it is required to be passed in the argument and omitted otherwise.
**--src-creds** _username[:password]_ for accessing the source registry
**--src-creds** _username[:password]_ for accessing the source registry.
**--dest-compress** _bool-value_ Compress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)
**--dest-compress** _bool-value_ Compress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source).
**--dest-oci-accept-uncompressed-layers** _bool-value_ Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)
**--dest-oci-accept-uncompressed-layers** _bool-value_ Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed).
**--dest-creds** _username[:password]_ for accessing the destination registry
**--dest-creds** _username[:password]_ for accessing the destination registry.
**--src-cert-dir** _path_ Use certificates at _path_ (*.crt, *.cert, *.key) to connect to the source registry or daemon
**--src-cert-dir** _path_ Use certificates at _path_ (*.crt, *.cert, *.key) to connect to the source registry or daemon.
**--src-no-creds** _bool-value_ Access the registry anonymously.
**--src-tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container source registry or daemon (defaults to true)
**--src-tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container source registry or daemon (defaults to true).
**--dest-cert-dir** _path_ Use certificates at _path_ (*.crt, *.cert, *.key) to connect to the destination registry or daemon
**--dest-cert-dir** _path_ Use certificates at _path_ (*.crt, *.cert, *.key) to connect to the destination registry or daemon.
**--dest-no-creds** _bool-value_ Access the registry anonymously.
**--dest-tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container destination registry or daemon (defaults to true)
**--dest-tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container destination registry or daemon (defaults to true).
**--src-daemon-host** _host_ Copy from docker daemon at _host_. If _host_ starts with `tcp://`, HTTPS is enabled by default. To use plain HTTP, use the form `http://` (default is `unix:///var/run/docker.sock`).
@@ -81,8 +88,17 @@ Existing signatures, if any, are preserved as well.
**--dest-compress-level** _format_ Specifies the compression level to use. The value is specific to the compression algorithm used, e.g. for zstd the accepted values are in the range 1-20 (inclusive), while for gzip it is 1-9 (inclusive).
**--src-registry-token** _Bearer token_ for accessing the source registry.
**--dest-registry-token** _Bearer token_ for accessing the destination registry.
## EXAMPLES
To just copy an image from one registry to another:
```sh
$ skopeo copy docker://quay.io/skopeo/stable:latest docker://registry.example.com/skopeo:latest
```
To copy the layers of the docker.io busybox image to a local directory:
```sh
$ mkdir -p /var/lib/images/busybox
@@ -96,7 +112,7 @@ $ ls /var/lib/images/busybox/*
To copy and sign an image:
```sh
# skopeo copy --sign-by dev@example.com container-storage:example/busybox:streaming docker://example/busybox:gold
# skopeo copy --sign-by dev@example.com containers-storage:example/busybox:streaming docker://example/busybox:gold
```
To encrypt an image:
@@ -132,7 +148,7 @@ skopeo copy --encryption-key jwe:./public.key --encrypt-layer 1 oci:local_nginx
```
## SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5), containers-policy.json(5), containers-transports(5)
## AUTHORS

View File

@@ -1,7 +1,7 @@
% skopeo-delete(1)
## NAME
skopeo\-delete - Mark _image-name_ for deletion.
skopeo\-delete - Mark the _image-name_ for later deletion by the registry's garbage collector.
## SYNOPSIS
**skopeo delete** _image-name_
@@ -21,19 +21,21 @@ $ docker exec -it registry /usr/bin/registry garbage-collect /etc/docker-distrib
**--authfile** _path_
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `skopeo 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
**--creds** _username[:password]_ for accessing the registry.
**--cert-dir** _path_ Use certificates at _path_ (*.crt, *.cert, *.key) to connect to 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)
**--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.
Additionally, the registry must allow deletions by setting `REGISTRY_STORAGE_DELETE_ENABLED=true` for the registry daemon.
**--registry-token** _Bearer token_ for accessing the registry.
## EXAMPLES
Mark image example/pause for deletion from the registry.example.com registry:
@@ -44,7 +46,7 @@ See above for additional details on using the command **delete**.
## SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5)
## AUTHORS

View File

@@ -1,37 +1,61 @@
% skopeo-inspect(1)
## NAME
skopeo\-inspect - Return low-level information about _image-name_ in a registry
skopeo\-inspect - Return low-level information about _image-name_ in a registry.
## SYNOPSIS
**skopeo inspect** [**--raw**] [**--config**] _image-name_
**skopeo inspect** [*options*] _image-name_
## DESCRIPTION
Return low-level information about _image-name_ in a registry
**--raw** output raw manifest, default is to format in JSON
_image-name_ name of image to retrieve information about
_image-name_ name of image to retrieve information about
## OPTIONS
**--config** output configuration in OCI format, default is to format in JSON
**--authfile** _path_
_image-name_ name of image to retrieve configuration for
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `skopeo login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
**--config** **--raw** output configuration in raw format
**--cert-dir** _path_
_image-name_ name of image to retrieve configuration for
Use certificates at _path_ (\*.crt, \*.cert, \*.key) to connect to the registry.
**--authfile** _path_
**--config**
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`.
Output configuration in OCI format, default is to format in JSON format.
**--creds** _username[:password]_ for accessing the registry
**--creds** _username[:password]_
**--cert-dir** _path_ Use certificates at _path_ (\*.crt, \*.cert, \*.key) to connect to the registry
Username and password for accessing the registry.
**--tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to container registries (defaults to true)
**--format**, **-f**=*format*
**--no-creds** _bool-value_ Access the registry anonymously.
Format the output using the given Go template.
The keys of the returned JSON can be used as the values for the --format flag (see examples below).
**--no-creds**
Access the registry anonymously.
**--raw**
Output raw manifest or config data depending on --config option.
The --format option is not supported with --raw option.
**--registry-token** _Bearer token_
Registry token for accessing the registry.
**--retry-times**
The number of times to retry; retry wait time will be exponentially increased based on the number of failed attempts.
**--tls-verify**
Require HTTPS and verify certificates when talking to container registries (defaults to true).
## EXAMPLES
@@ -42,14 +66,14 @@ $ skopeo inspect docker://docker.io/fedora
"Name": "docker.io/library/fedora",
"Digest": "sha256:a97914edb6ba15deb5c5acf87bd6bd5b6b0408c96f48a5cbd450b5b04509bb7d",
"RepoTags": [
"20",
"21",
"22",
"23",
"24",
"heisenbug",
"latest",
"rawhide"
"20",
"21",
"22",
"23",
"24",
"heisenbug",
"latest",
"rawhide"
],
"Created": "2016-06-20T19:33:43.220526898Z",
"DockerVersion": "1.10.3",
@@ -57,15 +81,24 @@ $ skopeo inspect docker://docker.io/fedora
"Architecture": "amd64",
"Os": "linux",
"Layers": [
"sha256:7c91a140e7a1025c3bc3aace4c80c0d9933ac4ee24b8630a6b0b5d8b9ce6b9d4"
"sha256:7c91a140e7a1025c3bc3aace4c80c0d9933ac4ee24b8630a6b0b5d8b9ce6b9d4"
]
}
```
```
$ /bin/skopeo inspect --config docker://registry.fedoraproject.org/fedora --format "{{ .Architecture }}"
amd64
```
```
$ /bin/skopeo inspect --format '{{ .Env }}' docker://registry.access.redhat.com/ubi8
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin container=oci]
```
# SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5)
## AUTHORS
Antonio Murdaca <runcom@redhat.com>, Miloslav Trmac <mitr@redhat.com>, Jhon Honce <jhonce@redhat.com>

View File

@@ -1,7 +1,7 @@
% skopeo-list-tags(1)
## NAME
skopeo\-list\-tags - Return a list of tags the transport-specific image repository
skopeo\-list\-tags - Return a list of tags for the transport-specific image repository.
## SYNOPSIS
**skopeo list-tags** _repository-name_
@@ -12,17 +12,19 @@ Return a list of tags from _repository-name_ in a registry.
**--authfile** _path_
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `skopeo 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
**--creds** _username[:password]_ for accessing the registry.
**--cert-dir** _path_ Use certificates at _path_ (\*.crt, \*.cert, \*.key) to connect to 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)
**--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.
**--registry-token** _Bearer token_ for accessing the registry.
## 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.
@@ -30,7 +32,7 @@ Repository names are transport-specific references as each transport may have it
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 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 `(skopeo 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:
@@ -94,7 +96,7 @@ $ skopeo list-tags docker://localhost:5000/fedora
```
# SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5)
## AUTHORS

101
docs/skopeo-login.1.md Normal file
View File

@@ -0,0 +1,101 @@
% skopeo-login(1)
## NAME
skopeo\-login - Login to a container registry.
## SYNOPSIS
**skopeo login** [*options*] *registry*
## DESCRIPTION
**skopeo login** logs into a specified registry server with the correct username
and password. **skopeo login** reads in the username and password from STDIN.
The username and password can also be set using the **username** and **password** flags.
The path of the authentication file can be specified by the user by setting the **authfile**
flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**.
## OPTIONS
**--password**, **-p**=*password*
Password for registry
**--password-stdin**
Take the password from stdin
**--username**, **-u**=*username*
Username for registry
**--authfile**=*path*
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json
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`
**--get-login**
Return the logged-in user for the registry. Return error if no login is found.
**--cert-dir**=*path*
Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
Default certificates directory is _/etc/containers/certs.d_.
**--tls-verify**=*true|false*
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
**--help**, **-h**
Print usage statement
## EXAMPLES
```
$ skopeo login docker.io
Username: testuser
Password:
Login Succeeded!
```
```
$ skopeo login -u testuser -p testpassword localhost:5000
Login Succeeded!
```
```
$ skopeo login --authfile authdir/myauths.json docker.io
Username: testuser
Password:
Login Succeeded!
```
```
$ skopeo login --tls-verify=false -u test -p test localhost:5000
Login Succeeded!
```
```
$ skopeo login --cert-dir /etc/containers/certs.d/ -u foo -p bar localhost:5000
Login Succeeded!
```
```
$ skopeo login -u testuser --password-stdin < testpassword.txt docker.io
Login Succeeded!
```
```
$ echo $testpassword | skopeo login -u testuser --password-stdin docker.io
Login Succeeded!
```
## SEE ALSO
skopeo(1), skopeo-logout(1), containers-auth.json(5), containers-registries.conf(5), containers-certs.d.5.md
## HISTORY
May 2020, Originally compiled by Qi Wang <qiwan@redhat.com>

53
docs/skopeo-logout.1.md Normal file
View File

@@ -0,0 +1,53 @@
% skopeo-logout(1)
## NAME
skopeo\-logout - Logout of a container registry.
## SYNOPSIS
**skopeo logout** [*options*] *registry*
## DESCRIPTION
**skopeo logout** logs out of a specified registry server by deleting the cached credentials
stored in the **auth.json** file. The path of the authentication file can be overridden by the user by setting the **authfile** flag.
The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**.
All the cached credentials can be removed by setting the **all** flag.
## OPTIONS
**--authfile**=*path*
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json
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`
**--all**, **-a**
Remove the cached credentials for all registries in the auth file
**--help**, **-h**
Print usage statement
## EXAMPLES
```
$ skopeo logout docker.io
Remove login credentials for docker.io
```
```
$ skopeo logout --authfile authdir/myauths.json docker.io
Remove login credentials for docker.io
```
```
$ skopeo logout --all
Remove login credentials for all registries
```
## SEE ALSO
skopeo(1), skopeo-login(1), containers-auth.json(5)
## HISTORY
May 2020, Originally compiled by Qi Wang <qiwan@redhat.com>

View File

@@ -1,7 +1,7 @@
% skopeo-manifest-digest(1)
## NAME
skopeo\-manifest\-digest -Compute a manifest digest of manifest-file and write it to standard output.
skopeo\-manifest\-digest - Compute a manifest digest for a manifest-file and write it to standard output.
## SYNOPSIS
**skopeo manifest-digest** _manifest-file_

View File

@@ -1,7 +1,7 @@
% skopeo-standalone-sign(1)
## NAME
skopeo\-standalone-sign - Simple Sign an image
skopeo\-standalone-sign - Debugging tool - Publish and sign an image in one step.
## SYNOPSIS
**skopeo standalone-sign** _manifest docker-reference key-fingerprint_ **--output**|**-o** _signature_
@@ -26,7 +26,7 @@ $
```
## SEE ALSO
skopeo(1), skopeo-copy(1)
skopeo(1), skopeo-copy(1), containers-signature(5)
## AUTHORS

View File

@@ -1,7 +1,7 @@
% skopeo-standalone-verify(1)
## NAME
skopeo\-standalone\-verify - Verify an image signature
skopeo\-standalone\-verify - Verify an image signature.
## SYNOPSIS
**skopeo standalone-verify** _manifest docker-reference key-fingerprint signature_
@@ -28,7 +28,7 @@ Signature verified, digest sha256:20bf21ed457b390829cdbeec8795a7bea1626991fda603
```
## SEE ALSO
skopeo(1)
skopeo(1), containers-signature(5)
## AUTHORS

View File

@@ -32,9 +32,14 @@ When the `--scoped` option is specified, images are prefixed with the source ima
name can be stored at _destination_.
## OPTIONS
**--all**
If one of the images in __src__ 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, --override-arch and --override-variant options), attempt to copy all of
the images in the list, and the list itself.
**--authfile** _path_
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `skopeo login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
**--src-authfile** _path_
@@ -49,6 +54,8 @@ Path of the authentication file for the destination registry. Uses path given by
**--dest** _transport_ Destination transport.
**--format, -f** _manifest-type_ Manifest Type (oci, v2s1, or v2s2) to use when syncing image(s) to a destination (default is manifest type of source).
**--scoped** Prefix images with the source image path, so that multiple images with the same name can be stored at _destination_.
**--remove-signatures** Do not copy signatures, if any, from _source-image_. This is necessary when copying a signed image to a destination which does not support signatures.
@@ -71,6 +78,10 @@ Path of the authentication file for the destination registry. Uses path given by
**--dest-tls-verify** _bool-value_ Require HTTPS and verify certificates when talking to a container destination registry or daemon (defaults to true).
**--src-registry-token** _Bearer token_ for accessing the source registry.
**--dest-registry-token** _Bearer token_ for accessing the destination registry.
## EXAMPLES
### Synchronizing to a local directory
@@ -86,6 +97,21 @@ Images are located at:
/media/usb/busybox:latest
```
### Synchronizing to a container registry from local
Images are located at:
```
/media/usb/busybox:1-glibc
```
Sync run
```
$ skopeo sync --src dir --dest docker /media/usb/busybox:1-glibc my-registry.local.lan/test/
```
Destination registry content:
```
REPO TAGS
my-registry.local.lan/test/busybox 1-glibc
```
### Synchronizing to a local directory, scoped
```
$ skopeo sync --src docker --dest dir --scoped registry.example.com/busybox /media/usb
@@ -128,6 +154,9 @@ registry.example.com:
redis:
- "1.0"
- "2.0"
- "sha256:0000000000000000000000000000000011111111111111111111111111111111"
images-by-tag-regex:
nginx: ^1\.13\.[12]-alpine-perl$
credentials:
username: john
password: this is a secret
@@ -139,22 +168,25 @@ quay.io:
coreos/etcd:
- latest
```
If the yaml filename is `sync.yml`, sync run:
```
skopeo sync --src yaml --dest docker sync.yml my-registry.local.lan/repo/
```
This will copy the following images:
- Repository `registry.example.com/busybox`: all images, as no tags are specified.
- Repository `registry.example.com/redis`: images tagged "1.0" and "2.0".
- Repository `registry.example.com/redis`: images tagged "1.0" and "2.0" along with image with digest "sha256:0000000000000000000000000000000011111111111111111111111111111111".
- Repository `registry.example.com/nginx`: images tagged "1.13.1-alpine-perl" and "1.13.2-alpine-perl".
- Repository `quay.io/coreos/etcd`: images tagged "latest".
For the registry `registry.example.com`, the "john"/"this is a secret" credentials are used, with server TLS certificates located at `/home/john/certs`.
TLS verification is normally enabled, and it can be disabled setting `tls-verify` to `true`.
In the above example, TLS verification is enabled for `reigstry.example.com`, while is
TLS verification is normally enabled, and it can be disabled setting `tls-verify` to `false`.
In the above example, TLS verification is enabled for `registry.example.com`, while is
disabled for `quay.io`.
## SEE ALSO
skopeo(1), podman-login(1), docker-login(1)
skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5), containers-policy.json(5), containers-transports(5)
## AUTHORS
Flavio Castelli <fcastelli@suse.com>, Marco Vedovati <mvedovati@suse.com>

View File

@@ -27,13 +27,13 @@ its functionality. It also does not require root, unless you are copying images
Most commands refer to container images, using a _transport_`:`_details_ format. The following formats are supported:
**containers-storage:**_docker-reference_
An image located in a local containers/storage image store. Location and image store specified in /etc/containers/storage.conf
An image located in a local containers/storage image store. Both the location and image store are specified in /etc/containers/storage.conf. (Backend for Podman, CRI-O, Buildah and friends)
**dir:**_path_
An existing local directory _path_ storing the manifest, layer tarballs and signatures as individual files. This is a non-standardized format, primarily useful for debugging or noninvasive container inspection.
**docker://**_docker-reference_
An image 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)`.
An image 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 `(skopeo login)`. If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using `(docker login)`.
**docker-archive:**_path_[**:**_docker-reference_]
An image is stored in the `docker save` formatted file. _docker-reference_ is only used when creating such a file, and it must not contain a digest.
@@ -44,6 +44,11 @@ Most commands refer to container images, using a _transport_`:`_details_ format.
**oci:**_path_**:**_tag_
An image _tag_ in a directory compliant with "Open Container Image Layout Specification" at _path_.
**oci-archive:**_path_**:**_tag_
An image _tag_ in a tar archive compliant with "Open Container Image Layout Specification" at _path_.
See [containers-transports(5)](https://github.com/containers/image/blob/master/docs/containers-transports.5.md) for details.
## OPTIONS
**--command-timeout** _duration_ Timeout for the command execution.
@@ -76,6 +81,8 @@ Most commands refer to container images, using a _transport_`:`_details_ format.
| [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-login(1)](skopeo-login.1.md) | Login to a container registry. |
| [skopeo-logout(1)](skopeo-logout.1.md) | Logout of a container registry. |
| [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. |
@@ -84,14 +91,14 @@ Most commands refer to container images, using a _transport_`:`_details_ format.
## FILES
**/etc/containers/policy.json**
Default trust policy file, if **--policy** is not specified.
The policy format is documented in https://github.com/containers/image/blob/master/docs/containers-policy.json.5.md .
The policy format is documented in [containers-policy.json(5)](https://github.com/containers/image/blob/master/docs/containers-policy.json.5.md) .
**/etc/containers/registries.d**
Default directory containing registry configuration, if **--registries.d** is not specified.
The contents of this directory are documented in https://github.com/containers/image/blob/master/docs/containers-policy.json.5.md .
The contents of this directory are documented in [containers-policy.json(5)](https://github.com/containers/image/blob/master/docs/containers-policy.json.5.md).
## SEE ALSO
podman-login(1), docker-login(1)
skopeo-login(1), docker-login(1), containers-auth.json(5), containers-storage.conf(5), containers-policy.json(5), containers-transports(5)
## AUTHORS

27
go.mod
View File

@@ -3,24 +3,23 @@ module github.com/containers/skopeo
go 1.12
require (
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/containers/common v0.38.12
github.com/containers/image/v5 v5.12.0
github.com/containers/ocicrypt v1.1.1
github.com/containers/storage v1.31.3
github.com/docker/docker v20.10.6+incompatible
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // 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/go-digest v1.0.0
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.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/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
go4.org v0.0.0-20190218023631-ce4c26f7be8e // indirect
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v2 v2.4.0
)

984
go.sum

File diff suppressed because it is too large Load Diff

61
hack/get_ci_vm.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
#
# For help and usage information, simply execute the script w/o any arguments.
#
# This script is intended to be run by Red Hat skopeo developers who need
# to debug problems specifically related to Cirrus-CI automated testing.
# It requires that you have been granted prior access to create VMs in
# google-cloud. For non-Red Hat contributors, VMs are available as-needed,
# with supervision upon request.
set -e
SCRIPT_FILEPATH=$(realpath "${BASH_SOURCE[0]}")
SCRIPT_DIRPATH=$(dirname "$SCRIPT_FILEPATH")
REPO_DIRPATH=$(realpath "$SCRIPT_DIRPATH/../")
# Help detect if we were called by get_ci_vm container
GET_CI_VM="${GET_CI_VM:-0}"
in_get_ci_vm() {
if ((GET_CI_VM==0)); then
echo "Error: $1 is not intended for use in this context"
exit 2
fi
}
# get_ci_vm APIv1 container entrypoint calls into this script
# to obtain required repo. specific configuration options.
if [[ "$1" == "--config" ]]; then
in_get_ci_vm "$1"
cat <<EOF
DESTDIR="/var/tmp/go/src/github.com/containers/skopeo"
UPSTREAM_REPO="https://github.com/containers/skopeo.git"
GCLOUD_PROJECT="skopeo"
GCLOUD_IMGPROJECT="libpod-218412"
GCLOUD_CFG="skopeo"
GCLOUD_ZONE="${GCLOUD_ZONE:-us-central1-f}"
GCLOUD_CPUS="2"
GCLOUD_MEMORY="4Gb"
GCLOUD_DISK="200"
EOF
elif [[ "$1" == "--setup" ]]; then
in_get_ci_vm "$1"
# get_ci_vm container entrypoint calls us with this option on the
# Cirrus-CI environment instance, to perform repo.-specific setup.
echo "+ Executing setup" > /dev/stderr
${GOSRC}/${SCRIPT_BASE}/runner.sh setup
else
# Create and access VM for specified Cirrus-CI task
mkdir -p $HOME/.config/gcloud/ssh
podman run -it --rm \
--tz=local \
-e NAME="$USER" \
-e SRCDIR=/src \
-e GCLOUD_ZONE="$GCLOUD_ZONE" \
-e DEBUG="${DEBUG:-0}" \
-v $REPO_DIRPATH:/src:O \
-v $HOME/.config/gcloud:/root/.config/gcloud:z \
-v $HOME/.config/gcloud/ssh:/root/.ssh:z \
quay.io/libpod/get_ci_vm:latest "$@"
fi

View File

@@ -25,12 +25,8 @@ export MAKEDIR="$SCRIPTDIR/make"
# We're a nice, sexy, little shell script, and people might try to run us;
# but really, they shouldn't. We want to be in a container!
inContainer="AssumeSoInitially"
if [ "$PWD" != "/go/src/$SKOPEO_PKG" ]; then
unset inContainer
fi
if [ -z "$inContainer" ]; then
# The magic value is defined inside our Dockerfile.
if [[ "$container_magic" != "85531765-346b-4316-bdb8-358e4cca9e5d" ]]; then
{
echo "# WARNING! I don't seem to be running in a Docker container."
echo "# The result of this command might be an incorrect build, and will not be"
@@ -39,6 +35,9 @@ if [ -z "$inContainer" ]; then
echo "# Try this instead: make all"
echo "#"
} >&2
else
echo "# I appear to be running inside my designated container image, good!"
export SKOPEO_CONTAINER_TESTS=1
fi
echo

View File

@@ -5,7 +5,7 @@ if [ -z "$VALIDATE_UPSTREAM" ]; then
# are running more than one validate bundlescript
VALIDATE_REPO='https://github.com/containers/skopeo.git'
VALIDATE_BRANCH='master'
VALIDATE_BRANCH='main'
if [ "$TRAVIS" = 'true' -a "$TRAVIS_PULL_REQUEST" != 'false' ]; then
VALIDATE_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git"

View File

@@ -8,7 +8,7 @@ bundle_test_integration() {
# subshell so that we can export PATH without breaking other things
(
make binary-local ${BUILDTAGS:+BUILDTAGS="$BUILDTAGS"}
make install
make bin/skopeo ${BUILDTAGS:+BUILDTAGS="$BUILDTAGS"}
make PREFIX=/usr install
bundle_test_integration
) 2>&1

View File

@@ -11,8 +11,8 @@ sed -i \
/etc/containers/storage.conf
# Build skopeo, install into /usr/bin
make binary-local ${BUILDTAGS:+BUILDTAGS="$BUILDTAGS"}
make install
make bin/skopeo ${BUILDTAGS:+BUILDTAGS="$BUILDTAGS"}
make PREFIX=/usr install
# Run tests
SKOPEO_BINARY=/usr/bin/skopeo bats --tap systemtest

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
set -e
export GOPATH=$(pwd)/_gopath
export PATH=$GOPATH/bin:$PATH
_containers="${GOPATH}/src/github.com/containers"
mkdir -vp ${_containers}
ln -vsf $(pwd) ${_containers}/skopeo
go version
GO111MODULE=off go get -u github.com/cpuguy83/go-md2man golang.org/x/lint/golint
cd ${_containers}/skopeo
make validate-local test-unit-local binary-local
sudo make install
skopeo -v

View File

@@ -1,70 +1,123 @@
# Installing from packages
`skopeo` may already be packaged in your distribution, for example on
RHEL/CentOS ≥ 8 or Fedora you can install it using:
## Distribution Packages
`skopeo` may already be packaged in your distribution.
### Fedora
```sh
$ sudo dnf install skopeo
sudo dnf -y install skopeo
```
on RHEL/CentOS ≤ 7.x:
### RHEL/CentOS ≥ 8 and CentOS Stream
```sh
$ sudo yum install skopeo
sudo dnf -y install skopeo
```
for openSUSE:
Newer Skopeo releases may be available on the repositories provided by the
Kubic project. Beware, these may not be suitable for production environments.
on CentOS 8:
```sh
$ sudo zypper install skopeo
sudo dnf -y module disable container-tools
sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo
sudo dnf -y install skopeo
```
on alpine:
on CentOS 8 Stream:
```sh
$ sudo apk add skopeo
sudo dnf -y module disable container-tools
sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8_Stream/devel:kubic:libcontainers:stable.repo
sudo dnf -y install skopeo
```
Debian (10 and newer including Raspbian) and Ubuntu (18.04 and newer): Packages
are available via the [Kubic][0] project repositories:
### RHEL/CentOS ≤ 7.x
[0]: https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable
```sh
sudo yum -y install skopeo
```
### openSUSE
```sh
sudo zypper install skopeo
```
### Alpine
```sh
sudo apk add skopeo
```
### macOS
```sh
brew install skopeo
```
### Nix / NixOS
```sh
$ nix-env -i skopeo
```
### Debian
The skopeo package is available in
the [Bullseye (testing) branch](https://packages.debian.org/bullseye/skopeo), which
will be the next stable release (Debian 11) as well as Debian Unstable/Sid.
```bash
# Debian Unstable/Sid:
$ echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_Unstable/Release.key -O- | sudo apt-key add -
# Debian Testing/Bullseye or Unstable/Sid
sudo apt-get update
sudo apt-get -y install skopeo
```
```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 -
```
### Raspberry Pi OS arm64 (beta)
Raspberry Pi OS uses the standard Debian's repositories,
so it is fully compatible with Debian's arm64 repository.
You can simply follow the [steps for Debian](#debian) to install Skopeo.
### Ubuntu
The skopeo package is available in the official repositories for Ubuntu 20.10
and newer.
```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 -
# Ubuntu 20.10 and newer
sudo apt-get -y update
sudo apt-get -y install skopeo
```
```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 -
```
If you would prefer newer (though not as well-tested) packages,
the [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/skopeo)
provides packages for active Ubuntu releases 20.04 and newer (it should also work with direct derivatives like Pop!\_OS).
Checkout the [Kubic project page](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/skopeo)
for a list of supported Ubuntu version and
architecture combinations. **NOTE:** The command `sudo apt-get -y upgrade`
maybe required in some cases if Skopeo cannot be installed without it.
The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/skopeo/-/tree/debian/debian).
CAUTION: On Ubuntu 20.10 and newer, we highly recommend you use Buildah, Podman and Skopeo ONLY from EITHER the Kubic repo
OR the official Ubuntu repos. Mixing and matching may lead to unpredictable situations including installation conflicts.
```bash
# 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 -
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y install skopeo
```
```bash
$ sudo apt-get update -qq
$ sudo apt-get install skopeo
```
Otherwise, read on for building and installing it from source:
@@ -73,6 +126,8 @@ 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 from Source
### Building without a container
Building without a container requires a bit more manual work and setup in your
@@ -86,49 +141,32 @@ Install the necessary dependencies:
```bash
# Fedora:
$ sudo dnf install gpgme-devel libassuan-devel btrfs-progs-devel device-mapper-devel
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
sudo apt install libgpgme-dev libassuan-dev libbtrfs-dev libdevmapper-dev
```
```bash
# macOS:
$ brew install gpgme
brew install gpgme
```
```bash
# openSUSE:
$ sudo zypper install libgpgme-devel device-mapper-devel libbtrfs-devel glib2-devel
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
git clone https://github.com/containers/skopeo $GOPATH/src/github.com/containers/skopeo
cd $GOPATH/src/github.com/containers/skopeo && make bin/skopeo
```
### 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
```
By default the `make` command (make all) will build bin/skopeo and the documentation locally.
### Building documentation
@@ -136,18 +174,31 @@ To build the manual you will need go-md2man.
```bash
# Debian:
$ sudo apt-get install go-md2man
sudo apt-get install go-md2man
```
```
# Fedora:
$ sudo dnf install go-md2man
sudo dnf install go-md2man
```
Then
```bash
$ make docs
make docs
```
### 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
```
### Installation
@@ -155,5 +206,5 @@ $ make docs
Finally, after the binary and documentation is built:
```bash
$ sudo make install
sudo make install
```

View File

@@ -30,18 +30,11 @@ type SkopeoSuite struct {
func (s *SkopeoSuite) SetUpSuite(c *check.C) {
_, err := exec.LookPath(skopeoBinary)
c.Assert(err, check.IsNil)
}
func (s *SkopeoSuite) TearDownSuite(c *check.C) {
}
func (s *SkopeoSuite) SetUpTest(c *check.C) {
s.regV2 = setupRegistryV2At(c, privateRegistryURL0, false, false)
s.regV2WithAuth = setupRegistryV2At(c, privateRegistryURL1, true, false)
}
func (s *SkopeoSuite) TearDownTest(c *check.C) {
func (s *SkopeoSuite) TearDownSuite(c *check.C) {
if s.regV2 != nil {
s.regV2.Close()
}
@@ -71,7 +64,7 @@ func (s *SkopeoSuite) TestNeedAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C
}
func (s *SkopeoSuite) TestCertDirInsteadOfCertPath(c *check.C) {
wanted := ".*flag provided but not defined: -cert-path.*"
wanted := ".*unknown flag: --cert-path.*"
assertSkopeoFails(c, wanted, "--tls-verify=false", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url), "--cert-path=/")
wanted = ".*unauthorized: authentication required.*"
assertSkopeoFails(c, wanted, "--tls-verify=false", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url), "--cert-dir=/etc/docker/certs.d/")
@@ -91,3 +84,30 @@ func (s *SkopeoSuite) TestNoNeedAuthToPrivateRegistryV2ImageNotFound(c *check.C)
func (s *SkopeoSuite) TestInspectFailsWhenReferenceIsInvalid(c *check.C) {
assertSkopeoFails(c, `.*Invalid image name.*`, "inspect", "unknown")
}
func (s *SkopeoSuite) TestLoginLogout(c *check.C) {
wanted := "^Login Succeeded!\n$"
assertSkopeoSucceeds(c, wanted, "login", "--tls-verify=false", "--username="+s.regV2WithAuth.username, "--password="+s.regV2WithAuth.password, s.regV2WithAuth.url)
// test --get-login returns username
wanted = fmt.Sprintf("^%s\n$", s.regV2WithAuth.username)
assertSkopeoSucceeds(c, wanted, "login", "--tls-verify=false", "--get-login", s.regV2WithAuth.url)
// test logout
wanted = fmt.Sprintf("^Removed login credentials for %s\n$", s.regV2WithAuth.url)
assertSkopeoSucceeds(c, wanted, "logout", s.regV2WithAuth.url)
}
func (s *SkopeoSuite) TestCopyWithLocalAuth(c *check.C) {
wanted := "^Login Succeeded!\n$"
assertSkopeoSucceeds(c, wanted, "login", "--tls-verify=false", "--username="+s.regV2WithAuth.username, "--password="+s.regV2WithAuth.password, s.regV2WithAuth.url)
// copy to private registry using local authentication
imageName := fmt.Sprintf("docker://%s/busybox:mine", s.regV2WithAuth.url)
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", testFQIN+":latest", imageName)
// inspect from private registry
assertSkopeoSucceeds(c, "", "inspect", "--tls-verify=false", imageName)
// logout from the registry
wanted = fmt.Sprintf("^Removed login credentials for %s\n$", s.regV2WithAuth.url)
assertSkopeoSucceeds(c, wanted, "logout", s.regV2WithAuth.url)
// inspect from private registry should fail after logout
wanted = ".*unauthorized: authentication required.*"
assertSkopeoFails(c, wanted, "inspect", "--tls-verify=false", imageName)
}

View File

@@ -31,6 +31,8 @@ const (
v2DockerRegistryURL = "localhost:5555" // Update also policy.json
v2s1DockerRegistryURL = "localhost:5556"
knownWindowsOnlyImage = "docker://mcr.microsoft.com/windows/nanoserver:1909"
knownListImageRepo = "docker://registry.fedoraproject.org/fedora-minimal"
knownListImage = knownListImageRepo + ":38"
)
type CopySuite struct {
@@ -99,14 +101,14 @@ func (s *CopySuite) TestCopyWithManifestList(c *check.C) {
dir, err := ioutil.TempDir("", "copy-manifest-list")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir)
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:latest", "dir:"+dir)
assertSkopeoSucceeds(c, "", "copy", knownListImage, "dir:"+dir)
}
func (s *CopySuite) TestCopyAllWithManifestList(c *check.C) {
dir, err := ioutil.TempDir("", "copy-all-manifest-list")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir)
assertSkopeoSucceeds(c, "", "copy", "--all", "docker://estesp/busybox:latest", "dir:"+dir)
assertSkopeoSucceeds(c, "", "copy", "--all", knownListImage, "dir:"+dir)
}
func (s *CopySuite) TestCopyAllWithManifestListRoundTrip(c *check.C) {
@@ -122,7 +124,7 @@ func (s *CopySuite) TestCopyAllWithManifestListRoundTrip(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-all-manifest-list-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
assertSkopeoSucceeds(c, "", "copy", "--all", "docker://estesp/busybox:latest", "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "--all", knownListImage, "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "--all", "oci:"+oci1, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "--all", "dir:"+dir1, "oci:"+oci2)
assertSkopeoSucceeds(c, "", "copy", "--all", "oci:"+oci2, "dir:"+dir2)
@@ -144,9 +146,9 @@ func (s *CopySuite) TestCopyAllWithManifestListConverge(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-all-manifest-list-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
assertSkopeoSucceeds(c, "", "copy", "--all", "docker://estesp/busybox:latest", "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "--all", knownListImage, "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "--all", "oci:"+oci1, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "--all", "--format", "oci", "docker://estesp/busybox:latest", "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", "--all", "--format", "oci", knownListImage, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", "--all", "dir:"+dir2, "oci:"+oci2)
assertDirImagesAreEqual(c, dir1, dir2)
out := combinedOutputOfCommand(c, "diff", "-urN", oci1, oci2)
@@ -166,9 +168,9 @@ func (s *CopySuite) TestCopyWithManifestListConverge(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-all-manifest-list-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:latest", "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", knownListImage, "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "--all", "oci:"+oci1, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "--format", "oci", "docker://estesp/busybox:latest", "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", "--format", "oci", knownListImage, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", "--all", "dir:"+dir2, "oci:"+oci2)
assertDirImagesAreEqual(c, dir1, dir2)
out := combinedOutputOfCommand(c, "diff", "-urN", oci1, oci2)
@@ -180,7 +182,7 @@ func (s *CopySuite) TestCopyAllWithManifestListStorageFails(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
assertSkopeoFails(c, `.*destination transport .* does not support copying multiple images as a group.*`, "copy", "--all", "docker://estesp/busybox:latest", "containers-storage:"+storage+"test")
assertSkopeoFails(c, `.*destination transport .* does not support copying multiple images as a group.*`, "copy", "--all", knownListImage, "containers-storage:"+storage+"test")
}
func (s *CopySuite) TestCopyWithManifestListStorage(c *check.C) {
@@ -194,8 +196,8 @@ func (s *CopySuite) TestCopyWithManifestListStorage(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-manifest-list-storage-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:latest", "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:latest", "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", knownListImage, "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "copy", knownListImage, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "containers-storage:"+storage+"test", "dir:"+dir2)
runDecompressDirs(c, "", dir1, dir2)
assertDirImagesAreEqual(c, dir1, dir2)
@@ -212,9 +214,9 @@ func (s *CopySuite) TestCopyWithManifestListStorageMultiple(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-manifest-list-storage-multiple-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
assertSkopeoSucceeds(c, "", "--override-arch", "amd64", "copy", "docker://estesp/busybox:latest", "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "--override-arch", "arm64", "copy", "docker://estesp/busybox:latest", "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "--override-arch", "arm64", "copy", "docker://estesp/busybox:latest", "dir:"+dir1)
assertSkopeoSucceeds(c, "", "--override-arch", "amd64", "copy", knownListImage, "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "--override-arch", "arm64", "copy", knownListImage, "containers-storage:"+storage+"test")
assertSkopeoSucceeds(c, "", "--override-arch", "arm64", "copy", knownListImage, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "containers-storage:"+storage+"test", "dir:"+dir2)
runDecompressDirs(c, "", dir1, dir2)
assertDirImagesAreEqual(c, dir1, dir2)
@@ -233,18 +235,33 @@ func (s *CopySuite) TestCopyWithManifestListDigest(c *check.C) {
oci2, err := ioutil.TempDir("", "copy-manifest-list-digest-oci")
c.Assert(err, check.IsNil)
defer os.RemoveAll(oci2)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox@"+digest, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "--all", "docker://estesp/busybox@"+digest, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", knownListImageRepo+"@"+digest, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "--all", knownListImageRepo+"@"+digest, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", "dir:"+dir1, "oci:"+oci1)
assertSkopeoSucceeds(c, "", "copy", "dir:"+dir2, "oci:"+oci2)
out := combinedOutputOfCommand(c, "diff", "-urN", oci1, oci2)
c.Assert(out, check.Equals, "")
}
func (s *CopySuite) TestCopyWithDigestfileOutput(c *check.C) {
tempdir, err := ioutil.TempDir("", "tempdir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tempdir)
dir1, err := ioutil.TempDir("", "copy-manifest-list-digest-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir1)
digestOutPath := filepath.Join(tempdir, "digest.txt")
assertSkopeoSucceeds(c, "", "copy", "--digestfile="+digestOutPath, knownListImage, "dir:"+dir1)
readDigest, err := ioutil.ReadFile(digestOutPath)
c.Assert(err, check.IsNil)
_, err = digest.Parse(string(readDigest))
c.Assert(err, check.IsNil)
}
func (s *CopySuite) TestCopyWithManifestListStorageDigest(c *check.C) {
storage, err := ioutil.TempDir("", "copy-manifest-list-storage-digest")
c.Assert(err, check.IsNil)
@@ -256,13 +273,13 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigest(c *check.C) {
dir2, err := ioutil.TempDir("", "copy-manifest-list-storage-digest-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "copy", "containers-storage:"+storage+"test@"+digest, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox@"+digest, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", knownListImageRepo+"@"+digest, "dir:"+dir2)
runDecompressDirs(c, "", dir1, dir2)
assertDirImagesAreEqual(c, dir1, dir2)
}
@@ -278,13 +295,13 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArches(c *check
dir2, err := ioutil.TempDir("", "copy-manifest-list-storage-digest-dir")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "copy", "containers-storage:"+storage+"test@"+digest, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox@"+digest, "dir:"+dir2)
assertSkopeoSucceeds(c, "", "copy", knownListImageRepo+"@"+digest, "dir:"+dir2)
runDecompressDirs(c, "", dir1, dir2)
assertDirImagesAreEqual(c, dir1, dir2)
}
@@ -294,14 +311,14 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesBothUseLi
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
_, err = manifest.ListFromBlob([]byte(m), manifest.GuessMIMEType([]byte(m)))
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoFails(c, `.*error reading manifest for image instance.*does not exist.*`, "--override-arch=amd64", "inspect", "containers-storage:"+storage+"test@"+digest)
assertSkopeoFails(c, `.*error reading manifest for image instance.*does not exist.*`, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+digest)
i2 := combinedOutputOfCommand(c, skopeoBinary, "--override-arch=arm64", "inspect", "--config", "containers-storage:"+storage+"test@"+digest)
@@ -316,7 +333,7 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesFirstUses
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
@@ -326,8 +343,8 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesFirstUses
c.Assert(err, check.IsNil)
arm64Instance, err := list.ChooseInstance(&types.SystemContext{ArchitectureChoice: "arm64"})
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", "docker://estesp/busybox@"+arm64Instance.String(), "containers-storage:"+storage+"test@"+arm64Instance.String())
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", knownListImageRepo+"@"+arm64Instance.String(), "containers-storage:"+storage+"test@"+arm64Instance.String())
i1 := combinedOutputOfCommand(c, skopeoBinary, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+digest)
var image1 imgspecv1.Image
err = json.Unmarshal([]byte(i1), &image1)
@@ -352,7 +369,7 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesSecondUse
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
@@ -362,8 +379,8 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesSecondUse
c.Assert(err, check.IsNil)
arm64Instance, err := list.ChooseInstance(&types.SystemContext{ArchitectureChoice: "arm64"})
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox@"+amd64Instance.String(), "containers-storage:"+storage+"test@"+amd64Instance.String())
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImageRepo+"@"+amd64Instance.String(), "containers-storage:"+storage+"test@"+amd64Instance.String())
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
i1 := combinedOutputOfCommand(c, skopeoBinary, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+amd64Instance.String())
var image1 imgspecv1.Image
err = json.Unmarshal([]byte(i1), &image1)
@@ -388,7 +405,7 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesThirdUses
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
@@ -398,9 +415,9 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesThirdUses
c.Assert(err, check.IsNil)
arm64Instance, err := list.ChooseInstance(&types.SystemContext{ArchitectureChoice: "arm64"})
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox@"+amd64Instance.String(), "containers-storage:"+storage+"test@"+amd64Instance.String())
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImageRepo+"@"+amd64Instance.String(), "containers-storage:"+storage+"test@"+amd64Instance.String())
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoFails(c, `.*error reading manifest for image instance.*does not exist.*`, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+digest)
i1 := combinedOutputOfCommand(c, skopeoBinary, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+amd64Instance.String())
var image1 imgspecv1.Image
@@ -424,7 +441,7 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesTagAndDig
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", "docker://estesp/busybox:latest")
m := combinedOutputOfCommand(c, skopeoBinary, "inspect", "--raw", knownListImage)
manifestDigest, err := manifest.Digest([]byte(m))
c.Assert(err, check.IsNil)
digest := manifestDigest.String()
@@ -434,8 +451,8 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesTagAndDig
c.Assert(err, check.IsNil)
arm64Instance, err := list.ChooseInstance(&types.SystemContext{ArchitectureChoice: "arm64"})
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", "docker://estesp/busybox:latest", "containers-storage:"+storage+"test:latest")
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", "docker://estesp/busybox@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoSucceeds(c, "", "--override-arch=amd64", "copy", knownListImage, "containers-storage:"+storage+"test:latest")
assertSkopeoSucceeds(c, "", "--override-arch=arm64", "copy", knownListImageRepo+"@"+digest, "containers-storage:"+storage+"test@"+digest)
assertSkopeoFails(c, `.*error reading manifest for image instance.*does not exist.*`, "--override-arch=amd64", "inspect", "--config", "containers-storage:"+storage+"test@"+digest)
i1 := combinedOutputOfCommand(c, skopeoBinary, "--override-arch=arm64", "inspect", "--config", "containers-storage:"+storage+"test:latest")
var image1 imgspecv1.Image
@@ -464,16 +481,16 @@ func (s *CopySuite) TestCopyWithManifestListStorageDigestMultipleArchesTagAndDig
c.Assert(image5.Architecture, check.Equals, "arm64")
}
func (s *CopySuite) TestCopyFailsWhenImageOSDoesntMatchRuntimeOS(c *check.C) {
storage, err := ioutil.TempDir("", "copy-fails-image-doesnt-match-runtime")
func (s *CopySuite) TestCopyFailsWhenImageOSDoesNotMatchRuntimeOS(c *check.C) {
storage, err := ioutil.TempDir("", "copy-fails-image-does-not-match-runtime")
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 .*, variant .*, OS .*`, "copy", knownWindowsOnlyImage, "containers-storage:"+storage+"test")
}
func (s *CopySuite) TestCopySucceedsWhenImageDoesntMatchRuntimeButWeOverride(c *check.C) {
storage, err := ioutil.TempDir("", "copy-succeeds-image-doesnt-match-runtime-but-override")
func (s *CopySuite) TestCopySucceedsWhenImageDoesNotMatchRuntimeButWeOverride(c *check.C) {
storage, err := ioutil.TempDir("", "copy-succeeds-image-does-not-match-runtime-but-override")
c.Assert(err, check.IsNil)
defer os.RemoveAll(storage)
storage = fmt.Sprintf("[vfs@%s/root+%s/runroot]", storage, storage)
@@ -488,14 +505,14 @@ func (s *CopySuite) TestCopySimpleAtomicRegistry(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
// "pull": docker: → dir:
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:amd64", "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", testFQIN64, "dir:"+dir1)
// "push": dir: → atomic:
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "dir:"+dir1, "atomic:localhost:5000/myns/unsigned:unsigned")
// The result of pushing and pulling is an equivalent image, except for schema1 embedded names.
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "atomic:localhost:5000/myns/unsigned:unsigned", "dir:"+dir2)
assertSchema1DirImagesAreEqualExceptNames(c, dir1, "estesp/busybox:amd64", dir2, "myns/unsigned:unsigned")
assertSchema1DirImagesAreEqualExceptNames(c, dir1, "libpod/busybox:amd64", dir2, "myns/unsigned:unsigned")
}
// The most basic (skopeo copy) use:
@@ -509,30 +526,30 @@ func (s *CopySuite) TestCopySimple(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
// "pull": docker: → dir:
assertSkopeoSucceeds(c, "", "copy", "docker://busybox", "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", "docker://registry.k8s.io/pause", "dir:"+dir1)
// "push": dir: → docker(v2s2):
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "dir:"+dir1, ourRegistry+"busybox:unsigned")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "dir:"+dir1, ourRegistry+"pause:unsigned")
// The result of pushing and pulling is an unmodified image.
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", ourRegistry+"busybox:unsigned", "dir:"+dir2)
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", ourRegistry+"pause:unsigned", "dir:"+dir2)
out := combinedOutputOfCommand(c, "diff", "-urN", dir1, dir2)
c.Assert(out, check.Equals, "")
// docker v2s2 -> OCI image layout with image name
// ociDest will be created by oci: if it doesn't exist
// so don't create it here to exercise auto-creation
ociDest := "busybox-latest-image"
ociImgName := "busybox"
ociDest := "pause-latest-image"
ociImgName := "pause"
defer os.RemoveAll(ociDest)
assertSkopeoSucceeds(c, "", "copy", "docker://busybox:latest", "oci:"+ociDest+":"+ociImgName)
assertSkopeoSucceeds(c, "", "copy", "docker://registry.k8s.io/pause:latest", "oci:"+ociDest+":"+ociImgName)
_, err = os.Stat(ociDest)
c.Assert(err, check.IsNil)
// docker v2s2 -> OCI image layout without image name
ociDest = "busybox-latest-noimage"
ociDest = "pause-latest-noimage"
defer os.RemoveAll(ociDest)
assertSkopeoSucceeds(c, "", "copy", "docker://busybox:latest", "oci:"+ociDest)
assertSkopeoSucceeds(c, "", "copy", "docker://registry.k8s.io/pause:latest", "oci:"+ociDest)
_, err = os.Stat(ociDest)
c.Assert(err, check.IsNil)
}
@@ -586,7 +603,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:1.31.1", "oci:"+originalImageDir+":latest")
assertSkopeoSucceeds(c, "", "copy", testFQIN+":1.30.1", "oci:"+originalImageDir+":latest")
// Encrypt the image
assertSkopeoSucceeds(c, "", "copy", "--encryption-key",
@@ -617,7 +634,7 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
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")
assertSkopeoSucceeds(c, "", "copy", testFQINMultiLayer, "oci:"+multiLayerImageDir+":latest")
// Partially encrypt the image
assertSkopeoSucceeds(c, "", "copy", "--encryption-key", "jwe:"+keysDir+"/public.key",
@@ -626,7 +643,7 @@ func (s *CopySuite) TestCopyEncryption(c *check.C) {
// 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
// Decrypt the partially encrypted image
assertSkopeoSucceeds(c, "", "copy", "--decryption-key", keysDir+"/private.key",
"oci:"+partiallyEncryptedImgDir+":encrypted", "oci:"+partiallyDecryptedImgDir+":decrypted")
@@ -720,13 +737,13 @@ func (s *CopySuite) TestCopyStreaming(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir2)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
// streaming: docker: → atomic:
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "docker://estesp/busybox:amd64", "atomic:localhost:5000/myns/unsigned:streaming")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", testFQIN64, "atomic:localhost:5000/myns/unsigned:streaming")
// Compare (copies of) the original and the copy:
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:amd64", "dir:"+dir1)
assertSkopeoSucceeds(c, "", "copy", testFQIN64, "dir:"+dir1)
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "atomic:localhost:5000/myns/unsigned:streaming", "dir:"+dir2)
assertSchema1DirImagesAreEqualExceptNames(c, dir1, "estesp/busybox:amd64", dir2, "myns/unsigned:streaming")
assertSchema1DirImagesAreEqualExceptNames(c, dir1, "libpod/busybox:amd64", dir2, "myns/unsigned:streaming")
// FIXME: Also check pushing to docker://
}
@@ -746,7 +763,7 @@ func (s *CopySuite) TestCopyOCIRoundTrip(c *check.C) {
defer os.RemoveAll(oci2)
// Docker -> OCI
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "docker://busybox", "oci:"+oci1+":latest")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", testFQIN, "oci:"+oci1+":latest")
// OCI -> Docker
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--debug", "copy", "oci:"+oci1+":latest", ourRegistry+"original/busybox:oci_copy")
// Docker -> OCI
@@ -797,16 +814,16 @@ func (s *CopySuite) TestCopySignatures(c *check.C) {
defer os.Remove(policy)
// type: reject
assertSkopeoFails(c, ".*Source image rejected: Running image docker://busybox:latest is rejected by policy.*",
"--policy", policy, "copy", "docker://busybox:latest", dirDest)
assertSkopeoFails(c, fmt.Sprintf(".*Source image rejected: Running image %s:latest is rejected by policy.*", testFQIN),
"--policy", policy, "copy", testFQIN+":latest", dirDest)
// type: insecureAcceptAnything
assertSkopeoSucceeds(c, "", "--policy", policy, "copy", "docker://openshift/hello-openshift", dirDest)
assertSkopeoSucceeds(c, "", "--policy", policy, "copy", "docker://quay.io/openshift/origin-hello-openshift", dirDest)
// type: signedBy
// Sign the images
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--sign-by", "personal@example.com", "docker://busybox:1.26", "atomic:localhost:5006/myns/personal:personal")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--sign-by", "official@example.com", "docker://busybox:1.26.1", "atomic:localhost:5006/myns/official:official")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--sign-by", "personal@example.com", testFQIN+":1.26", "atomic:localhost:5006/myns/personal:personal")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--sign-by", "official@example.com", testFQIN+":1.26.1", "atomic:localhost:5006/myns/official:official")
// Verify that we can pull them
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--policy", policy, "copy", "atomic:localhost:5006/myns/personal:personal", dirDest)
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--policy", policy, "copy", "atomic:localhost:5006/myns/official:official", dirDest)
@@ -860,10 +877,10 @@ func (s *CopySuite) TestCopyDirSignatures(c *check.C) {
defer os.Remove(policy)
// Get some images.
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:armfh", topDirDest+"/dir1")
assertSkopeoSucceeds(c, "", "copy", "docker://estesp/busybox:s390x", topDirDest+"/dir2")
assertSkopeoSucceeds(c, "", "copy", testFQIN+":armfh", topDirDest+"/dir1")
assertSkopeoSucceeds(c, "", "copy", testFQIN+":s390x", topDirDest+"/dir2")
// Sign the images. By coping fom a topDirDest/dirN, also test that non-/restricted paths
// Sign the images. By coping from a topDirDest/dirN, also test that non-/restricted paths
// use the dir:"" default of insecureAcceptAnything.
// (For signing, we must push to atomic: to get a Docker identity to use in the signature.)
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--policy", policy, "copy", "--sign-by", "personal@example.com", topDirDest+"/dir1", "atomic:localhost:5000/myns/personal:dirstaging")
@@ -977,7 +994,7 @@ func (s *CopySuite) TestCopyDockerSigstore(c *check.C) {
c.Assert(err, check.IsNil)
// Get an image to work with. Also verifies that we can use Docker repositories with no sigstore configured.
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--registries.d", registriesDir, "copy", "docker://busybox", ourRegistry+"original/busybox")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--registries.d", registriesDir, "copy", testFQIN, ourRegistry+"original/busybox")
// Pulling an unsigned image fails.
assertSkopeoFails(c, ".*Source image rejected: A signature was required, but no signature exists.*",
"--tls-verify=false", "--policy", policy, "--registries.d", registriesDir, "copy", ourRegistry+"original/busybox", dirDest)
@@ -1031,7 +1048,7 @@ func (s *CopySuite) TestCopyAtomicExtension(c *check.C) {
defer os.Remove(policy)
// Get an image to work with to an atomic: destination. Also verifies that we can use Docker repositories without X-Registry-Supports-Signatures
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--registries.d", registriesDir, "copy", "docker://busybox", "atomic:localhost:5000/myns/extension:unsigned")
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--registries.d", registriesDir, "copy", testFQIN, "atomic:localhost:5000/myns/extension:unsigned")
// Pulling an unsigned image using atomic: fails.
assertSkopeoFails(c, ".*Source image rejected: A signature was required, but no signature exists.*",
"--tls-verify=false", "--policy", policy,
@@ -1055,7 +1072,7 @@ func (s *CopySuite) TestCopyAtomicExtension(c *check.C) {
// Get another image (different so that they don't share signatures, and sign it using docker://)
assertSkopeoSucceeds(c, "", "--tls-verify=false", "--registries.d", registriesDir,
"copy", "--sign-by", "personal@example.com", "docker://estesp/busybox:ppc64le", "atomic:localhost:5000/myns/extension:extension")
"copy", "--sign-by", "personal@example.com", testFQIN+":ppc64le", "docker://localhost:5000/myns/extension:extension")
c.Logf("%s", combinedOutputOfCommand(c, "oc", "get", "istag", "extension:extension", "-o", "json"))
// Pulling the image using atomic: succeeds.
assertSkopeoSucceeds(c, "", "--debug", "--tls-verify=false", "--policy", policy,
@@ -1067,8 +1084,98 @@ func (s *CopySuite) TestCopyAtomicExtension(c *check.C) {
assertDirImagesAreEqual(c, filepath.Join(topDir, "dirDA"), filepath.Join(topDir, "dirDD"))
}
// copyWithSignedIdentity creates a copy of an unsigned image, adding a signature for an unrelated identity
// This should be easier than using standalone-sign.
func copyWithSignedIdentity(c *check.C, src, dest, signedIdentity, signBy, registriesDir string) {
topDir, err := ioutil.TempDir("", "copyWithSignedIdentity")
c.Assert(err, check.IsNil)
defer os.RemoveAll(topDir)
signingDir := filepath.Join(topDir, "signing-temp")
assertSkopeoSucceeds(c, "", "copy", "--src-tls-verify=false", src, "dir:"+signingDir)
// Unknown error in Travis: https://github.com/containers/skopeo/issues/1093
// c.Logf("%s", combinedOutputOfCommand(c, "ls", "-laR", signingDir))
assertSkopeoSucceeds(c, "^$", "standalone-sign", "-o", filepath.Join(signingDir, "signature-1"),
filepath.Join(signingDir, "manifest.json"), signedIdentity, signBy)
// Unknown error in Travis: https://github.com/containers/skopeo/issues/1093
// c.Logf("%s", combinedOutputOfCommand(c, "ls", "-laR", signingDir))
assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--dest-tls-verify=false", "dir:"+signingDir, dest)
}
// Both mirroring support in registries.conf, and mirrored remapIdentity support in policy.json
func (s *CopySuite) TestCopyVerifyingMirroredSignatures(c *check.C) {
const regPrefix = "docker://localhost:5006/myns/mirroring-"
mech, _, err := signature.NewEphemeralGPGSigningMechanism([]byte{})
c.Assert(err, check.IsNil)
defer mech.Close()
if err := mech.SupportsSigning(); err != nil { // FIXME? Test that verification and policy enforcement works, using signatures from fixtures
c.Skip(fmt.Sprintf("Signing not supported: %v", err))
}
topDir, err := ioutil.TempDir("", "mirrored-signatures")
c.Assert(err, check.IsNil)
defer os.RemoveAll(topDir)
registriesDir := filepath.Join(topDir, "registries.d") // An empty directory to disable sigstore use
dirDest := "dir:" + filepath.Join(topDir, "unused-dest")
policy := fileFromFixture(c, "fixtures/policy.json", map[string]string{"@keydir@": s.gpgHome})
defer os.Remove(policy)
// We use X-R-S-S for this testing to avoid having to deal with the sigstores.
// A downside is that OpenShift records signatures per image, so the error messages below
// list all signatures for other tags used for the same image as well.
// So, make sure to never create a signature that could be considered valid in a different part of the test (i.e. don't reuse tags).
// Get an image to work with.
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", testFQIN, regPrefix+"primary:unsigned")
// Verify that unsigned images are rejected
assertSkopeoFails(c, ".*Source image rejected: A signature was required, but no signature exists.*",
"--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:unsigned", dirDest)
// Sign the image for the primary location
assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--src-tls-verify=false", "--dest-tls-verify=false", "--sign-by", "personal@example.com", regPrefix+"primary:unsigned", regPrefix+"primary:direct")
// Verify that a correctly signed image in the primary location is usable.
assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:direct", dirDest)
// Sign the image for the mirror
assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--src-tls-verify=false", "--dest-tls-verify=false", "--sign-by", "personal@example.com", regPrefix+"primary:unsigned", regPrefix+"mirror:mirror-signed")
// Verify that a correctly signed image for the mirror is accessible using the mirror's reference
assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"mirror:mirror-signed", dirDest)
// … but verify that while it is accessible using the primary location redirecting to the mirror, …
assertSkopeoSucceeds(c, "" /* no --policy */, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:mirror-signed", dirDest)
// … verify it is NOT accessible when requiring a signature.
assertSkopeoFails(c, ".*Source image rejected: None of the signatures were accepted, reasons: Signature for identity localhost:5006/myns/mirroring-primary:direct is not accepted; Signature for identity localhost:5006/myns/mirroring-mirror:mirror-signed is not accepted.*",
"--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:mirror-signed", dirDest)
// Create a signature for mirroring-primary:primary-signed without pushing there.
copyWithSignedIdentity(c, regPrefix+"primary:unsigned", regPrefix+"mirror:primary-signed",
"localhost:5006/myns/mirroring-primary:primary-signed", "personal@example.com",
registriesDir)
// Verify that a correctly signed image for the primary is accessible using the primary's reference
assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:primary-signed", dirDest)
// … but verify that while it is accessible using the mirror location
assertSkopeoSucceeds(c, "" /* no --policy */, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"mirror:primary-signed", dirDest)
// … verify it is NOT accessible when requiring a signature.
assertSkopeoFails(c, ".*Source image rejected: None of the signatures were accepted, reasons: Signature for identity localhost:5006/myns/mirroring-primary:direct is not accepted; Signature for identity localhost:5006/myns/mirroring-mirror:mirror-signed is not accepted; Signature for identity localhost:5006/myns/mirroring-primary:primary-signed is not accepted.*",
"--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"mirror:primary-signed", dirDest)
assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", "--dest-tls-verify=false", regPrefix+"primary:unsigned", regPrefix+"remap:remapped")
// Verify that while a remapIdentity image is accessible using the remapped (mirror) location
assertSkopeoSucceeds(c, "" /* no --policy */, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"remap:remapped", dirDest)
// … it is NOT accessible when requiring a signature …
assertSkopeoFails(c, ".*Source image rejected: None of the signatures were accepted, reasons: Signature for identity localhost:5006/myns/mirroring-primary:direct is not accepted; Signature for identity localhost:5006/myns/mirroring-mirror:mirror-signed is not accepted; Signature for identity localhost:5006/myns/mirroring-primary:primary-signed is not accepted.*", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"remap:remapped", dirDest)
// … until signed.
copyWithSignedIdentity(c, regPrefix+"remap:remapped", regPrefix+"remap:remapped",
"localhost:5006/myns/mirroring-primary:remapped", "personal@example.com",
registriesDir)
assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"remap:remapped", dirDest)
// To be extra clear about the semantics, verify that the signedPrefix (primary) location never exists
// and only the remapped prefix (mirror) is accessed.
assertSkopeoFails(c, ".*Error initializing source docker://localhost:5006/myns/mirroring-primary:remapped:.*manifest unknown: manifest unknown.*", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:remapped", dirDest)
}
func (s *SkopeoSuite) TestCopySrcWithAuth(c *check.C) {
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", "docker://busybox", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", testFQIN, fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
dir1, err := ioutil.TempDir("", "copy-1")
c.Assert(err, check.IsNil)
defer os.RemoveAll(dir1)
@@ -1076,15 +1183,15 @@ func (s *SkopeoSuite) TestCopySrcWithAuth(c *check.C) {
}
func (s *SkopeoSuite) TestCopyDestWithAuth(c *check.C) {
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", "docker://busybox", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", testFQIN, fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
}
func (s *SkopeoSuite) TestCopySrcAndDestWithAuth(c *check.C) {
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", "docker://busybox", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--dest-creds=testuser:testpassword", testFQIN, fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
assertSkopeoSucceeds(c, "", "--tls-verify=false", "copy", "--src-creds=testuser:testpassword", "--dest-creds=testuser:testpassword", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url), fmt.Sprintf("docker://%s/test:auth", s.regV2WithAuth.url))
}
func (s *CopySuite) TestCopyNoPanicOnHTTPResponseWOTLSVerifyFalse(c *check.C) {
func (s *CopySuite) TestCopyNoPanicOnHTTPResponseWithoutTLSVerifyFalse(c *check.C) {
const ourRegistry = "docker://" + v2DockerRegistryURL + "/"
// dir:test isn't created beforehand just because we already know this could
@@ -1110,7 +1217,7 @@ func (s *CopySuite) TestCopyManifestConversion(c *check.C) {
// oci to v2s1 and vice-versa not supported yet
// get v2s2 manifest type
assertSkopeoSucceeds(c, "", "copy", "docker://busybox", "dir:"+srcDir)
assertSkopeoSucceeds(c, "", "copy", testFQIN, "dir:"+srcDir)
verifyManifestMIMEType(c, srcDir, manifest.DockerV2Schema2MediaType)
// convert from v2s2 to oci
assertSkopeoSucceeds(c, "", "copy", "--format=oci", "dir:"+srcDir, "dir:"+destDir1)
@@ -1140,7 +1247,7 @@ func (s *CopySuite) testCopySchemaConversionRegistries(c *check.C, schema1Regist
// Ensure we are working with a schema2 image.
// dir: accepts any manifest format, i.e. this makes …/input2 a schema2 source which cannot be asked to produce schema1 like ordinary docker: registries can.
assertSkopeoSucceeds(c, "", "copy", "docker://busybox", "dir:"+input2Dir)
assertSkopeoSucceeds(c, "", "copy", testFQIN, "dir:"+input2Dir)
verifyManifestMIMEType(c, input2Dir, manifest.DockerV2Schema2MediaType)
// 2→2 (the "f2t2" in tag means "from 2 to 2")
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", "dir:"+input2Dir, schema2Registry+":f2t2")
@@ -1160,14 +1267,6 @@ func (s *CopySuite) testCopySchemaConversionRegistries(c *check.C, schema1Regist
verifyManifestMIMEType(c, destDir, manifest.DockerV2Schema1SignedMediaType)
}
// Verify manifest in a dir: image at dir is expectedMIMEType.
func verifyManifestMIMEType(c *check.C, dir string, expectedMIMEType string) {
manifestBlob, err := ioutil.ReadFile(filepath.Join(dir, "manifest.json"))
c.Assert(err, check.IsNil)
mimeType := manifest.GuessMIMEType(manifestBlob)
c.Assert(mimeType, check.Equals, expectedMIMEType)
}
const regConfFixture = "./fixtures/registries.conf"
func (s *SkopeoSuite) TestSuccessCopySrcWithMirror(c *check.C) {

View File

@@ -20,10 +20,41 @@
"keyPath": "@keydir@/personal-pubkey.gpg"
}
],
"localhost:5006/myns/mirroring-primary": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "@keydir@/personal-pubkey.gpg"
}
],
"localhost:5006/myns/mirroring-mirror": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "@keydir@/personal-pubkey.gpg"
}
],
"localhost:5006/myns/mirroring-remap": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "@keydir@/personal-pubkey.gpg",
"signedIdentity": {
"type": "remapIdentity",
"prefix": "localhost:5006/myns/mirroring-remap",
"signedPrefix": "localhost:5006/myns/mirroring-primary"
}
}
],
"docker.io/openshift": [
{
"type": "insecureAcceptAnything"
}
],
"quay.io/openshift": [
{
"type": "insecureAcceptAnything"
}
]
},
"dir": {

View File

@@ -26,3 +26,9 @@ mirror = [
{ location = "wrong-mirror-0.invalid" },
{ location = "gcr.io/google-containers" },
]
[[registry]]
location = "localhost:5006/myns/mirroring-primary"
mirror = [
{ location = "localhost:5006/myns/mirroring-mirror"},
]

View File

@@ -19,8 +19,8 @@ to start a container, then within the container:
SKOPEO_CONTAINER_TESTS=1 PS1='nested> ' go test -tags openshift_shell -timeout=24h ./integration -v -check.v -check.vv -check.f='CopySuite.TestRunShell'
An example of what can be done within the container:
cd ..; make binary-local install
./skopeo --tls-verify=false copy --sign-by=personal@example.com docker://busybox:latest atomic:localhost:5000/myns/personal:personal
cd ..; make bin/skopeo PREFIX=/usr install
./skopeo --tls-verify=false copy --sign-by=personal@example.com docker://quay.io/libpod/busybox:latest atomic:localhost:5000/myns/personal:personal
oc get istag personal:personal -o json
curl -L -v 'http://localhost:5000/v2/'
cat ~/.docker/config.json

View File

@@ -11,8 +11,26 @@ import (
"strings"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/go-check/check"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
// A repository with a path with multiple components in it which
// contains multiple tags, preferably with some tags pointing to
// manifest lists, and with some tags that don't.
pullableRepo = "quay.io/libpod/testimage"
// A tagged image in the repository that we can inspect and copy.
pullableTaggedImage = "registry.k8s.io/coredns/coredns:v1.6.6"
// A tagged manifest list in the repository that we can inspect and copy.
pullableTaggedManifestList = "registry.k8s.io/coredns/coredns:v1.8.0"
// A repository containing multiple tags, some of which are for
// manifest lists, and which includes a "latest" tag. We specify the
// name here without a tag.
pullableRepoWithLatestTag = "registry.k8s.io/pause"
)
func init() {
@@ -94,8 +112,8 @@ func (s *SyncSuite) TestDocker2DirTagged(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "busybox:latest"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedImage
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
@@ -117,9 +135,37 @@ func (s *SyncSuite) TestDocker2DirTagged(c *check.C) {
c.Assert(out, check.Equals, "")
}
func (s *SyncSuite) TestDocker2DirTaggedAll(c *check.C) {
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedManifestList
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
dir1 := path.Join(tmpDir, "dir1")
dir2 := path.Join(tmpDir, "dir2")
// sync docker => dir
assertSkopeoSucceeds(c, "", "sync", "--all", "--scoped", "--src", "docker", "--dest", "dir", image, dir1)
_, err = os.Stat(path.Join(dir1, imagePath, "manifest.json"))
c.Assert(err, check.IsNil)
// copy docker => dir
assertSkopeoSucceeds(c, "", "copy", "--all", "docker://"+image, "dir:"+dir2)
_, err = os.Stat(path.Join(dir2, "manifest.json"))
c.Assert(err, check.IsNil)
out := combinedOutputOfCommand(c, "diff", "-urN", path.Join(dir1, imagePath), dir2)
c.Assert(out, check.Equals, "")
}
func (s *SyncSuite) TestScoped(c *check.C) {
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "busybox:latest"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedImage
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
@@ -127,7 +173,7 @@ func (s *SyncSuite) TestScoped(c *check.C) {
dir1, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "sync", "--src", "docker", "--dest", "dir", image, dir1)
_, err = os.Stat(path.Join(dir1, image, "manifest.json"))
_, err = os.Stat(path.Join(dir1, path.Base(imagePath), "manifest.json"))
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src", "docker", "--dest", "dir", image, dir1)
@@ -138,30 +184,30 @@ func (s *SyncSuite) TestScoped(c *check.C) {
}
func (s *SyncSuite) TestDirIsNotOverwritten(c *check.C) {
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "busybox:latest"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableRepoWithLatestTag
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
// make a copy of the image in the local registry
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", "docker://"+image, "docker://"+path.Join(v2DockerRegistryURL, image))
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", "docker://"+image, "docker://"+path.Join(v2DockerRegistryURL, reference.Path(imageRef.DockerReference())))
//sync upstream image to dir, not scoped
dir1, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
assertSkopeoSucceeds(c, "", "sync", "--src", "docker", "--dest", "dir", image, dir1)
_, err = os.Stat(path.Join(dir1, image, "manifest.json"))
_, err = os.Stat(path.Join(dir1, path.Base(imagePath), "manifest.json"))
c.Assert(err, check.IsNil)
//sync local registry image to dir, not scoped
assertSkopeoFails(c, ".*Refusing to overwrite destination directory.*", "sync", "--src-tls-verify=false", "--src", "docker", "--dest", "dir", path.Join(v2DockerRegistryURL, image), dir1)
assertSkopeoFails(c, ".*Refusing to overwrite destination directory.*", "sync", "--src-tls-verify=false", "--src", "docker", "--dest", "dir", path.Join(v2DockerRegistryURL, reference.Path(imageRef.DockerReference())), dir1)
//sync local registry image to dir, scoped
imageRef, err = docker.ParseReference(fmt.Sprintf("//%s", path.Join(v2DockerRegistryURL, image)))
imageRef, err = docker.ParseReference(fmt.Sprintf("//%s", path.Join(v2DockerRegistryURL, reference.Path(imageRef.DockerReference()))))
c.Assert(err, check.IsNil)
imagePath = imageRef.DockerReference().String()
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src-tls-verify=false", "--src", "docker", "--dest", "dir", path.Join(v2DockerRegistryURL, image), dir1)
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src-tls-verify=false", "--src", "docker", "--dest", "dir", path.Join(v2DockerRegistryURL, reference.Path(imageRef.DockerReference())), dir1)
_, err = os.Stat(path.Join(dir1, imagePath, "manifest.json"))
c.Assert(err, check.IsNil)
os.RemoveAll(dir1)
@@ -173,8 +219,8 @@ func (s *SyncSuite) TestDocker2DirUntagged(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "alpine"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableRepo
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
@@ -198,7 +244,7 @@ func (s *SyncSuite) TestYamlUntagged(c *check.C) {
defer os.RemoveAll(tmpDir)
dir1 := path.Join(tmpDir, "dir1")
image := "alpine"
image := pullableRepo
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().Name()
@@ -209,23 +255,22 @@ func (s *SyncSuite) TestYamlUntagged(c *check.C) {
c.Check(len(tags), check.Not(check.Equals), 0)
yamlConfig := fmt.Sprintf(`
docker.io:
%s:
images:
%s:
`, image)
%s: []
`, reference.Domain(imageRef.DockerReference()), reference.Path(imageRef.DockerReference()))
//sync to the local reg
// sync to the local registry
yamlFile := path.Join(tmpDir, "registries.yaml")
ioutil.WriteFile(yamlFile, []byte(yamlConfig), 0644)
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src", "yaml", "--dest", "docker", "--dest-tls-verify=false", yamlFile, v2DockerRegistryURL)
// sync back from local reg to a folder
// sync back from local registry to a folder
os.Remove(yamlFile)
yamlConfig = fmt.Sprintf(`
%s:
tls-verify: false
images:
%s:
%s: []
`, v2DockerRegistryURL, imagePath)
ioutil.WriteFile(yamlFile, []byte(yamlConfig), 0644)
@@ -234,7 +279,9 @@ docker.io:
sysCtx = types.SystemContext{
DockerInsecureSkipTLSVerify: types.NewOptionalBool(true),
}
localTags, err := docker.GetRepositoryTags(context.Background(), &sysCtx, imageRef)
localImageRef, err := docker.ParseReference(fmt.Sprintf("//%s/%s", v2DockerRegistryURL, imagePath))
c.Assert(err, check.IsNil)
localTags, err := docker.GetRepositoryTags(context.Background(), &sysCtx, localImageRef)
c.Assert(err, check.IsNil)
c.Check(len(localTags), check.Not(check.Equals), 0)
c.Assert(len(localTags), check.Equals, len(tags))
@@ -255,6 +302,71 @@ docker.io:
c.Assert(nManifests, check.Equals, len(tags))
}
func (s *SyncSuite) TestYamlRegex2Dir(c *check.C) {
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
dir1 := path.Join(tmpDir, "dir1")
yamlConfig := `
registry.k8s.io:
images-by-tag-regex:
pause: ^[12]\.0$ # regex string test
`
// the ↑ regex strings always matches only 2 images
var nTags = 2
c.Assert(nTags, check.Not(check.Equals), 0)
yamlFile := path.Join(tmpDir, "registries.yaml")
ioutil.WriteFile(yamlFile, []byte(yamlConfig), 0644)
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src", "yaml", "--dest", "dir", yamlFile, dir1)
nManifests := 0
err = filepath.Walk(dir1, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && info.Name() == "manifest.json" {
nManifests++
return filepath.SkipDir
}
return nil
})
c.Assert(err, check.IsNil)
c.Assert(nManifests, check.Equals, nTags)
}
func (s *SyncSuite) TestYamlDigest2Dir(c *check.C) {
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
dir1 := path.Join(tmpDir, "dir1")
yamlConfig := `
registry.k8s.io:
images:
pause:
- sha256:59eec8837a4d942cc19a52b8c09ea75121acc38114a2c68b98983ce9356b8610
`
yamlFile := path.Join(tmpDir, "registries.yaml")
ioutil.WriteFile(yamlFile, []byte(yamlConfig), 0644)
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--src", "yaml", "--dest", "dir", yamlFile, dir1)
nManifests := 0
err = filepath.Walk(dir1, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && info.Name() == "manifest.json" {
nManifests++
return filepath.SkipDir
}
return nil
})
c.Assert(err, check.IsNil)
c.Assert(nManifests, check.Equals, 1)
}
func (s *SyncSuite) TestYaml2Dir(c *check.C) {
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
@@ -262,22 +374,21 @@ func (s *SyncSuite) TestYaml2Dir(c *check.C) {
dir1 := path.Join(tmpDir, "dir1")
yamlConfig := `
docker.io:
registry.k8s.io:
images:
busybox:
- latest
- musl
alpine:
- edge
- 3.8
opensuse/leap:
coredns/coredns:
- v1.8.0
- v1.7.1
k8s-dns-kube-dns:
- 1.14.12
- 1.14.13
pause:
- latest
quay.io:
images:
quay/busybox:
- latest`
quay/busybox:
- latest`
// get the number of tags
re := regexp.MustCompile(`^ +- +[^:/ ]+`)
@@ -314,10 +425,10 @@ func (s *SyncSuite) TestYamlTLSVerify(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
dir1 := path.Join(tmpDir, "dir1")
image := "busybox"
image := pullableRepoWithLatestTag
tag := "latest"
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
// copy docker => docker
assertSkopeoSucceeds(c, "", "copy", "--dest-tls-verify=false", "docker://"+image+":"+tag, localRegURL+image+":"+tag)
@@ -363,6 +474,26 @@ func (s *SyncSuite) TestYamlTLSVerify(c *check.C) {
}
func (s *SyncSuite) TestSyncManifestOutput(c *check.C) {
tmpDir, err := ioutil.TempDir("", "sync-manifest-output")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
destDir1 := filepath.Join(tmpDir, "dest1")
destDir2 := filepath.Join(tmpDir, "dest2")
destDir3 := filepath.Join(tmpDir, "dest3")
//Split image:tag path from image URI for manifest comparison
imageDir := pullableTaggedImage[strings.LastIndex(pullableTaggedImage, "/")+1:]
assertSkopeoSucceeds(c, "", "sync", "--format=oci", "--all", "--src", "docker", "--dest", "dir", pullableTaggedImage, destDir1)
verifyManifestMIMEType(c, filepath.Join(destDir1, imageDir), imgspecv1.MediaTypeImageManifest)
assertSkopeoSucceeds(c, "", "sync", "--format=v2s2", "--all", "--src", "docker", "--dest", "dir", pullableTaggedImage, destDir2)
verifyManifestMIMEType(c, filepath.Join(destDir2, imageDir), manifest.DockerV2Schema2MediaType)
assertSkopeoSucceeds(c, "", "sync", "--format=v2s1", "--all", "--src", "docker", "--dest", "dir", pullableTaggedImage, destDir3)
verifyManifestMIMEType(c, filepath.Join(destDir3, imageDir), manifest.DockerV2Schema1SignedMediaType)
}
func (s *SyncSuite) TestDocker2DockerTagged(c *check.C) {
const localRegURL = "docker://" + v2DockerRegistryURL + "/"
@@ -370,8 +501,8 @@ func (s *SyncSuite) TestDocker2DockerTagged(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "busybox:latest"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedImage
imageRef, err := docker.ParseReference(fmt.Sprintf("//%s", image))
c.Assert(err, check.IsNil)
imagePath := imageRef.DockerReference().String()
@@ -403,8 +534,8 @@ func (s *SyncSuite) TestDir2DockerTagged(c *check.C) {
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of neeeding an Internet connection.
image := "busybox:latest"
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableRepoWithLatestTag
dir1 := path.Join(tmpDir, "dir1")
err = os.Mkdir(dir1, 0755)
@@ -413,6 +544,10 @@ func (s *SyncSuite) TestDir2DockerTagged(c *check.C) {
err = os.Mkdir(dir2, 0755)
c.Assert(err, check.IsNil)
// create leading dirs
err = os.MkdirAll(path.Dir(path.Join(dir1, image)), 0755)
c.Assert(err, check.IsNil)
// copy docker => dir
assertSkopeoSucceeds(c, "", "copy", "docker://"+image, "dir:"+path.Join(dir1, image))
_, err = os.Stat(path.Join(dir1, image, "manifest.json"))
@@ -421,9 +556,13 @@ func (s *SyncSuite) TestDir2DockerTagged(c *check.C) {
// sync dir => docker
assertSkopeoSucceeds(c, "", "sync", "--scoped", "--dest-tls-verify=false", "--src", "dir", "--dest", "docker", dir1, v2DockerRegistryURL)
// create leading dirs
err = os.MkdirAll(path.Dir(path.Join(dir2, image)), 0755)
c.Assert(err, check.IsNil)
// copy docker => dir
assertSkopeoSucceeds(c, "", "copy", "--src-tls-verify=false", localRegURL+image, "dir:"+path.Join(dir2, image))
_, err = os.Stat(path.Join(path.Join(dir2, image), "manifest.json"))
_, err = os.Stat(path.Join(dir2, image, "manifest.json"))
c.Assert(err, check.IsNil)
out := combinedOutputOfCommand(c, "diff", "-urN", dir1, dir2)
@@ -486,7 +625,7 @@ func (s *SyncSuite) TestFailsWithDockerSourceUnauthorized(c *check.C) {
}
func (s *SyncSuite) TestFailsWithDockerSourceNotExisting(c *check.C) {
repo := path.Join(v2DockerRegistryURL, "imagedoesdotexist")
repo := path.Join(v2DockerRegistryURL, "imagedoesnotexist")
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)

View File

@@ -10,12 +10,17 @@ import (
"strings"
"time"
"github.com/containers/image/v5/manifest"
"github.com/go-check/check"
)
const skopeoBinary = "skopeo"
const decompressDirsBinary = "./decompress-dirs.sh"
const testFQIN = "docker://quay.io/libpod/busybox" // tag left off on purpose, some tests need to add a special one
const testFQIN64 = "docker://quay.io/libpod/busybox:amd64"
const testFQINMultiLayer = "docker://quay.io/libpod/alpine_nginx:master" // multi-layer
// consumeAndLogOutputStream takes (f, err) from an exec.*Pipe(), and causes all output to it to be logged to c.
func consumeAndLogOutputStream(c *check.C, id string, f io.ReadCloser, err error) {
c.Assert(err, check.IsNil)
@@ -200,3 +205,11 @@ func runDecompressDirs(c *check.C, regexp string, args ...string) {
c.Assert(string(out), check.Matches, "(?s)"+regexp) // (?s) : '.' will also match newlines
}
}
// Verify manifest in a dir: image at dir is expectedMIMEType.
func verifyManifestMIMEType(c *check.C, dir string, expectedMIMEType string) {
manifestBlob, err := ioutil.ReadFile(filepath.Join(dir, "manifest.json"))
c.Assert(err, check.IsNil)
mimeType := manifest.GuessMIMEType(manifestBlob)
c.Assert(mimeType, check.Equals, expectedMIMEType)
}

67
nix/default-arm64.nix Normal file
View File

@@ -0,0 +1,67 @@
let
pkgs = (import ./nixpkgs.nix {
crossSystem = {
config = "aarch64-unknown-linux-gnu";
};
config = {
packageOverrides = pkg: {
gpgme = (static pkg.gpgme);
libassuan = (static pkg.libassuan);
libgpgerror = (static pkg.libgpgerror);
libseccomp = (static pkg.libseccomp);
glib = (static pkg.glib).overrideAttrs (x: {
outputs = [ "bin" "out" "dev" ];
mesonFlags = [
"-Ddefault_library=static"
"-Ddevbindir=${placeholder ''dev''}/bin"
"-Dgtk_doc=false"
"-Dnls=disabled"
];
postInstall = ''
moveToOutput "share/glib-2.0" "$dev"
substituteInPlace "$dev/bin/gdbus-codegen" --replace "$out" "$dev"
sed -i "$dev/bin/glib-gettextize" -e "s|^gettext_dir=.*|gettext_dir=$dev/share/glib-2.0/gettext|"
sed '1i#line 1 "${x.pname}-${x.version}/include/glib-2.0/gobject/gobjectnotifyqueue.c"' \
-i "$dev"/include/glib-2.0/gobject/gobjectnotifyqueue.c
'';
});
};
};
});
static = pkg: pkg.overrideAttrs (x: {
doCheck = false;
configureFlags = (x.configureFlags or [ ]) ++ [
"--without-shared"
"--disable-shared"
];
dontDisableStatic = true;
enableSharedExecutables = false;
enableStatic = true;
});
self = with pkgs; buildGoModule rec {
name = "skopeo";
src = ./..;
vendorSha256 = null;
doCheck = false;
enableParallelBuilding = true;
outputs = [ "out" ];
nativeBuildInputs = [ bash gitMinimal go-md2man installShellFiles makeWrapper pkg-config which ];
buildInputs = [ glibc glibc.static gpgme libassuan libgpgerror libseccomp ];
prePatch = ''
export CFLAGS='-static -pthread'
export LDFLAGS='-s -w -static-libgcc -static'
export EXTRA_LDFLAGS='-s -w -linkmode external -extldflags "-static -lm"'
export BUILDTAGS='static netgo osusergo exclude_graphdriver_btrfs exclude_graphdriver_devicemapper'
'';
buildPhase = ''
patchShebangs .
make bin/skopeo
'';
installPhase = ''
install -Dm755 bin/skopeo $out/bin/skopeo
'';
};
in
self

65
nix/default.nix Normal file
View File

@@ -0,0 +1,65 @@
{ system ? builtins.currentSystem }:
let
pkgs = (import ./nixpkgs.nix {
config = {
packageOverrides = pkg: {
gpgme = (static pkg.gpgme);
libassuan = (static pkg.libassuan);
libgpgerror = (static pkg.libgpgerror);
libseccomp = (static pkg.libseccomp);
glib = (static pkg.glib).overrideAttrs (x: {
outputs = [ "bin" "out" "dev" ];
mesonFlags = [
"-Ddefault_library=static"
"-Ddevbindir=${placeholder ''dev''}/bin"
"-Dgtk_doc=false"
"-Dnls=disabled"
];
postInstall = ''
moveToOutput "share/glib-2.0" "$dev"
substituteInPlace "$dev/bin/gdbus-codegen" --replace "$out" "$dev"
sed -i "$dev/bin/glib-gettextize" -e "s|^gettext_dir=.*|gettext_dir=$dev/share/glib-2.0/gettext|"
sed '1i#line 1 "${x.pname}-${x.version}/include/glib-2.0/gobject/gobjectnotifyqueue.c"' \
-i "$dev"/include/glib-2.0/gobject/gobjectnotifyqueue.c
'';
});
};
};
});
static = pkg: pkg.overrideAttrs (x: {
doCheck = false;
configureFlags = (x.configureFlags or [ ]) ++ [
"--without-shared"
"--disable-shared"
];
dontDisableStatic = true;
enableSharedExecutables = false;
enableStatic = true;
});
self = with pkgs; buildGoModule rec {
name = "skopeo";
src = ./..;
vendorSha256 = null;
doCheck = false;
enableParallelBuilding = true;
outputs = [ "out" ];
nativeBuildInputs = [ bash gitMinimal go-md2man installShellFiles makeWrapper pkg-config which ];
buildInputs = [ glibc glibc.static gpgme libassuan libgpgerror libseccomp ];
prePatch = ''
export CFLAGS='-static -pthread'
export LDFLAGS='-s -w -static-libgcc -static'
export EXTRA_LDFLAGS='-s -w -linkmode external -extldflags "-static -lm"'
export BUILDTAGS='static netgo osusergo exclude_graphdriver_btrfs exclude_graphdriver_devicemapper'
'';
buildPhase = ''
patchShebangs .
make bin/skopeo
'';
installPhase = ''
install -Dm755 bin/skopeo $out/bin/skopeo
'';
};
in
self

10
nix/nixpkgs.json Normal file
View File

@@ -0,0 +1,10 @@
{
"url": "https://github.com/nixos/nixpkgs",
"rev": "eb7e1ef185f6c990cda5f71fdc4fb02e76ab06d5",
"date": "2021-05-05T23:16:00+02:00",
"path": "/nix/store/a98lkhjlsqh32ic2kkrv5kkik6jy25wh-nixpkgs",
"sha256": "1ibz204c41g7baqga2iaj11yz9l75cfdylkiqjnk5igm81ivivxg",
"fetchSubmodules": false,
"deepClone": false,
"leaveDotGit": false
}

8
nix/nixpkgs.nix Normal file
View File

@@ -0,0 +1,8 @@
let
json = builtins.fromJSON (builtins.readFile ./nixpkgs.json);
nixpkgs = import (builtins.fetchTarball {
name = "nixos-unstable";
url = "${json.url}/archive/${json.rev}.tar.gz";
inherit (json) sha256;
});
in nixpkgs

51
release/Makefile Normal file
View File

@@ -0,0 +1,51 @@
## This Makefile is used to publish skopeo container images with Travis CI ##
## Environment variables, used in this Makefile are specified in .travis.yml
export DOCKER_CLI_EXPERIMENTAL=enabled
GOARCH ?= $(shell go env GOARCH)
# Dereference variable $(1), return value if non-empty, otherwise raise an error.
err_if_empty = $(if $(strip $($(1))),$(strip $($(1))),$(error Required $(1) variable is undefined or empty))
# Requires two arguments: Names of the username and the password env. vars.
define quay_login
@echo "$(call err_if_empty,$(2))" | \
docker login quay.io -u "$(call err_if_empty,$(1))" --password-stdin
endef
# Build container image of skopeo upstream based on host architecture
build-image/upstream:
docker build -t "${UPSTREAM_IMAGE}-${GOARCH}" contrib/skopeoimage/upstream
# Build container image of skopeo stable based on host architecture
build-image/stable:
docker build -t "${STABLE_IMAGE}-${GOARCH}" contrib/skopeoimage/stable
# Push container image of skopeo upstream (based on host architecture) to image repository
push-image/upstream:
$(call quay_login,SKOPEO_QUAY_USERNAME,SKOPEO_QUAY_PASSWORD)
docker push "${UPSTREAM_IMAGE}-${GOARCH}"
# Push container image of skopeo stable (based on host architecture) to image default and extra repositories
push-image/stable:
$(call quay_login,SKOPEO_QUAY_USERNAME,SKOPEO_QUAY_PASSWORD)
docker push "${STABLE_IMAGE}-${GOARCH}"
docker tag "${STABLE_IMAGE}-${GOARCH}" "${EXTRA_STABLE_IMAGE}-${GOARCH}"
$(call quay_login,CONTAINERS_QUAY_USERNAME,CONTAINERS_QUAY_PASSWORD)
docker push "${EXTRA_STABLE_IMAGE}-${GOARCH}"
# Create and push multiarch image manifest of skopeo upstream
push-manifest-multiarch/upstream:
docker manifest create "${UPSTREAM_IMAGE}" $(foreach arch,${MULTIARCH_MANIFEST_ARCHITECTURES}, ${UPSTREAM_IMAGE}-${arch})
$(call quay_login,SKOPEO_QUAY_USERNAME,SKOPEO_QUAY_PASSWORD)
docker manifest push --purge "${UPSTREAM_IMAGE}"
# Create and push multiarch image manifest of skopeo stable
push-manifest-multiarch/stable:
docker manifest create "${STABLE_IMAGE}" $(foreach arch,${MULTIARCH_MANIFEST_ARCHITECTURES}, ${STABLE_IMAGE}-${arch})
$(call quay_login,SKOPEO_QUAY_USERNAME,SKOPEO_QUAY_PASSWORD)
docker manifest push --purge "${STABLE_IMAGE}"
# Push to extra repository
docker manifest create "${EXTRA_STABLE_IMAGE}" $(foreach arch,${MULTIARCH_MANIFEST_ARCHITECTURES}, ${EXTRA_STABLE_IMAGE}-${arch})
$(call quay_login,CONTAINERS_QUAY_USERNAME,CONTAINERS_QUAY_PASSWORD)
docker manifest push --purge "${EXTRA_STABLE_IMAGE}"

40
release/README.md Normal file
View File

@@ -0,0 +1,40 @@
# skopeo container image build with Travis
This document describes the details and requirements to build and publish skopeo container images. The images are published as several architecture specific images and multiarch images on top for upstream and stable versions.
The Travis configuration is available at `.travis.yml`.
The code to build and publish images is available at `release/Makefile` and should be used only via Travis.
Travis workflow has 3 major pieces:
- `local-build` - build and test source code locally on osx and linux/amd64 environments, 2 jobs are running in parallel
- `image-build-push` - build and push container images with several Travis jobs running in parallel to build images for several architectures (linux/amd64, linux/s390x, linux/ppc64le). Build part is done for each PR, push part is executed only in case of cron job or master branch update.
- `manifest-multiarch-push` - create and push image manifests, which consists of architecture specific images from previous step. Executed only in case of cron job or master branch update.
## Ways to have full workflow run
- [cron job](https://docs.travis-ci.com/user/cron-jobs/#adding-cron-jobs)
- Trigger build from Travis CI
- Update code in master branch
## Environment variables
Several environment variables are used to customize image names and keep private credentials to push to quay.io repositories.
**Image tags** are specified in environment variable and should be manually updated in case of new release.
- `SKOPEO_QUAY_USERNAME` and `SKOPEO_QUAY_PASSWORD` are credentials to push images to `quay.io/skopeo/stable` and `quay.io/skopeo/upstream` repos, and require the credentials to have write permissions. These variables should be specified in [Travis](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings).
- `CONTAINERS_QUAY_USERNAME` and `CONTAINERS_QUAY_PASSWORD` are credentials to push images to `quay.io/containers/skopeo` repos, and require the credentials to have write permissions. These variables should be specified in [Travis](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings).
Variables in .travis.yml
- `MULTIARCH_MANIFEST_ARCHITECTURES` is a list with architecture shortnames, to appear in final multiarch manifest. The values should fit to architectures used in the `image-build-push` Travis step.
- `STABLE_IMAGE`, `EXTRA_STABLE_IMAGE` are image names to publish stable Skopeo.
- `UPSTREAM_IMAGE` is an image name to publish upstream Skopeo.
### Values for environment variables
| Env variable | Value |
| -------------------------------- |----------------------------------|
| MULTIARCH_MANIFEST_ARCHITECTURES | "amd64 s390x ppc64le" |
| STABLE_IMAGE | quay.io/skopeo/stable:v1.2.0 |
| EXTRA_STABLE_IMAGE | quay.io/containers/skopeo:v1.2.0 |
| UPSTREAM_IMAGE | quay.io/skopeo/upstream:master |

View File

@@ -27,11 +27,20 @@ load helpers
# Now run inspect locally
run_skopeo inspect dir:$workdir
inspect_local=$output
run_skopeo inspect --raw dir:$workdir
inspect_local_raw=$output
config_digest=$(jq -r '.config.digest' <<<"$inspect_local_raw")
# Each SHA-named file must be listed in the output of 'inspect'
# Each SHA-named layer file (but not the config) must be listed in the output of 'inspect'.
# In all existing versions of Skopeo (with 1.6 being the current as of this comment),
# the output of 'inspect' lists layer digests,
# but not the digest of the config blob ($config_digest), if any.
layers=$(jq -r '.Layers' <<<"$inspect_local")
for sha in $(find $workdir -type f | xargs -l1 basename | egrep '^[0-9a-f]{64}$'); do
expect_output --from="$inspect_local" --substring "sha256:$sha" \
"Locally-extracted SHA file is present in 'inspect'"
if [ "sha256:$sha" != "$config_digest" ]; then
expect_output --from="$layers" --substring "sha256:$sha" \
"Locally-extracted SHA file is present in 'inspect'"
fi
done
# Simple sanity check on 'inspect' output.
@@ -65,59 +74,47 @@ END_EXPECT
}
@test "inspect: env" {
remote_image=docker://docker.io/fedora:latest
remote_image=docker://quay.io/libpod/fedora:31
run_skopeo inspect $remote_image
inspect_remote=$output
# Simple check on 'inspect' output with environment variables.
# 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=.* )
check_array=(FGC=f31 DISTTAG=f31container)
remote=$(jq '.Env[]' <<<"$inspect_remote")
for substr in ${check_array[@]}; do
expect_output --from="$remote" --substring "$substr"
done
}
# Tests https://github.com/containers/skopeo/pull/708
@test "inspect: image manifest list w/ diff platform" {
# When --raw is provided, can inspect show the raw manifest list, w/o
# requiring any particular platform to be present
# To test whether container image can be inspected successfully w/o
# platform dependency.
# 1) Get current platform arch
# 2) Inspect container image is different from current platform arch
# 3) Compare output w/ expected result
# This image's manifest is for an os + arch that is... um, unlikely
# to support skopeo in the foreseeable future. Or past. The image
# is created by the make-noarch-manifest script in this directory.
img=docker://quay.io/libpod/notmyarch:20210121
# 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
# Get our host arch (what we're running on). This assumes that skopeo
# arch matches podman; it also assumes running podman >= April 2020
# (prior to that, the format keys were lower-case).
arch=$(podman info --format '{{.Host.Arch}}')
case $arch in
"amd64")
diff_arch_list="s390x ppc64le"
;;
"s390x")
diff_arch_list="amd64 ppc64le"
;;
"ppc64le")
diff_arch_list="amd64 s390x"
;;
"*")
diff_arch_list="amd64 s390x ppc64le"
;;
esac
# By default, 'inspect' tries to match our host os+arch. This should fail.
run_skopeo 1 inspect $img
expect_output --substring "Error parsing manifest for image: Error choosing image instance: no image found in manifest list for architecture $arch, variant " \
"skopeo inspect, without --raw, fails"
for arch in $diff_arch_list; do
remote_image=docker://docker.io/$arch/golang
run_skopeo inspect --tls-verify=false --raw $remote_image
remote_arch=$(jq -r '.manifests[0]["platform"]["architecture"]' <<< "$output")
expect_output --from="$remote_arch" "$arch" "platform arch of $remote_image"
done
# With --raw, we can inspect
run_skopeo inspect --raw $img
expect_output --substring "manifests.*platform.*architecture" \
"skopeo inspect --raw returns reasonable output"
# ...and what we get should be consistent with what our script created.
archinfo=$(jq -r '.manifests[0].platform | {os,variant,architecture} | join("-")' <<<"$output")
expect_output --from="$archinfo" "amigaos-1000-mc68000" \
"os - variant - architecture of $img"
}
# vim: filetype=sh

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://docker.io/library/busybox:latest
local remote_image=docker://quay.io/libpod/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://docker.io/library/busybox:latest
local remote_image=docker://quay.io/libpod/busybox:latest
local localimg=docker://localhost:5000/busybox:unsigned
local dir1=$TESTDIR/oci1
@@ -45,8 +45,8 @@ function setup() {
}
# Compression zstd
@test "copy: oci, round trip, zstd" {
local remote_image=docker://docker.io/library/busybox:latest
@test "copy: oci, zstd" {
local remote_image=docker://quay.io/libpod/busybox:latest
local dir=$TESTDIR/dir
@@ -57,11 +57,17 @@ function setup() {
# Check there is at least one file that has the zstd magic number as the first 4 bytes
(for i in $dir/blobs/sha256/*; do test "$(head -c 4 $i)" = $magic && exit 0; done; exit 1)
# Check that the manifest's description of the image's first layer is the zstd layer type
instance=$(jq -r '.manifests[0].digest' $dir/index.json)
[[ "$instance" != null ]]
mediatype=$(jq -r '.layers[0].mediaType' < $dir/blobs/${instance/://})
[[ "$mediatype" == "application/vnd.oci.image.layer.v1.tar+zstd" ]]
}
# Same image, extracted once with :tag and once without
@test "copy: oci w/ and w/o tags" {
local remote_image=docker://docker.io/library/busybox:latest
local remote_image=docker://quay.io/libpod/busybox:latest
local dir1=$TESTDIR/dir1
local dir2=$TESTDIR/dir2
@@ -78,7 +84,7 @@ function setup() {
# Registry -> storage -> oci-archive
@test "copy: registry -> storage -> oci-archive" {
local alpine=docker.io/library/alpine:latest
local alpine=quay.io/libpod/alpine:latest
local tmp=$TESTDIR/oci
run_skopeo copy docker://$alpine containers-storage:$alpine
@@ -94,6 +100,50 @@ function setup() {
docker://localhost:5000/foo
}
# manifest format
@test "copy: manifest format" {
local remote_image=docker://quay.io/libpod/busybox:latest
local dir1=$TESTDIR/dir1
local dir2=$TESTDIR/dir2
run_skopeo copy --format v2s2 $remote_image dir:$dir1
run_skopeo copy --format oci $remote_image dir:$dir2
grep 'application/vnd.docker.distribution.manifest.v2' $dir1/manifest.json
grep 'application/vnd.oci.image' $dir2/manifest.json
}
# additional tag
@test "copy: additional tag" {
local remote_image=docker://quay.io/libpod/busybox:latest
# additional-tag is supported only for docker-archive
run_skopeo copy --additional-tag busybox:mine $remote_image \
docker-archive:$TESTDIR/mybusybox.tar:busybox:latest
mkdir -p $TESTDIR/podmanroot
run podman --root $TESTDIR/podmanroot load -i $TESTDIR/mybusybox.tar
run podman --root $TESTDIR/podmanroot images
expect_output --substring "mine"
}
# shared blob directory
@test "copy: shared blob directory" {
local remote_image=docker://quay.io/libpod/busybox:latest
local shareddir=$TESTDIR/shareddir
local dir1=$TESTDIR/dir1
local dir2=$TESTDIR/dir2
run_skopeo copy --dest-shared-blob-dir $shareddir \
$remote_image oci:$dir1
[ -n "$(ls $shareddir)" ]
[ -z "$(ls $dir1/blobs)" ]
run_skopeo copy --src-shared-blob-dir $shareddir \
oci:$dir1 oci:$dir2
diff -urN $shareddir $dir2/blobs
}
teardown() {
podman rm -f reg

View File

@@ -8,19 +8,28 @@ load helpers
function setup() {
standard_setup
start_registry --with-cert reg
start_registry --with-cert --enable-delete=true reg
}
@test "local registry, with cert" {
# Push to local registry...
run_skopeo copy --dest-cert-dir=$TESTDIR/client-auth \
docker://docker.io/library/busybox:latest \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:unsigned
# ...and pull it back out
run_skopeo copy --src-cert-dir=$TESTDIR/client-auth \
docker://localhost:5000/busybox:unsigned \
dir:$TESTDIR/extracted
# inspect with cert
run_skopeo inspect --cert-dir=$TESTDIR/client-auth \
docker://localhost:5000/busybox:unsigned
expect_output --substring "localhost:5000/busybox"
# delete with cert
run_skopeo delete --cert-dir=$TESTDIR/client-auth \
docker://localhost:5000/busybox:unsigned
}
teardown() {

View File

@@ -18,7 +18,7 @@ function setup() {
testuser=testuser
testpassword=$(random_string 15)
start_registry --testuser=$testuser --testpassword=$testpassword reg
start_registry --testuser=$testuser --testpassword=$testpassword --enable-delete=true reg
}
@test "auth: credentials on command line" {
@@ -43,7 +43,7 @@ function setup() {
# These should pass
run_skopeo copy --dest-tls-verify=false --dcreds=$testuser:$testpassword \
docker://docker.io/library/busybox:latest \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:mine
run_skopeo inspect --tls-verify=false --creds=$testuser:$testpassword \
docker://localhost:5000/busybox:mine
@@ -55,7 +55,7 @@ function setup() {
podman login --tls-verify=false -u $testuser -p $testpassword localhost:5000
run_skopeo copy --dest-tls-verify=false \
docker://docker.io/library/busybox:latest \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:mine
run_skopeo inspect --tls-verify=false docker://localhost:5000/busybox:mine
expect_output --substring "localhost:5000/busybox"
@@ -67,6 +67,47 @@ function setup() {
expect_output --substring "unauthorized: authentication required"
}
@test "auth: copy with --src-creds and --dest-creds" {
run_skopeo copy --dest-tls-verify=false --dest-creds=$testuser:$testpassword \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:mine
run_skopeo copy --src-tls-verify=false --src-creds=$testuser:$testpassword \
docker://localhost:5000/busybox:mine \
dir:$TESTDIR/dir1
run ls $TESTDIR/dir1
expect_output --substring "manifest.json"
}
@test "auth: credentials via authfile" {
podman login --tls-verify=false --authfile $TESTDIR/test.auth -u $testuser -p $testpassword localhost:5000
# copy without authfile: should fail
run_skopeo 1 copy --dest-tls-verify=false \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:mine
# copy with authfile: should work
run_skopeo copy --dest-tls-verify=false \
--authfile $TESTDIR/test.auth \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:mine
# inspect without authfile: should fail
run_skopeo 1 inspect --tls-verify=false docker://localhost:5000/busybox:mine
expect_output --substring "unauthorized: authentication required"
# inspect with authfile: should work
run_skopeo inspect --tls-verify=false --authfile $TESTDIR/test.auth docker://localhost:5000/busybox:mine
expect_output --substring "localhost:5000/busybox"
# delete without authfile: should fail
run_skopeo 1 delete --tls-verify=false docker://localhost:5000/busybox:mine
expect_output --substring "authentication required"
# delete with authfile: should work
run_skopeo delete --tls-verify=false --authfile $TESTDIR/test.auth docker://localhost:5000/busybox:mine
}
teardown() {
podman rm -f reg

View File

@@ -92,7 +92,7 @@ END_POLICY_JSON
fi
# Cache local copy
run_skopeo copy docker://docker.io/library/busybox:latest \
run_skopeo copy docker://quay.io/libpod/busybox:latest \
dir:$TESTDIR/busybox
# Push a bunch of images. Do so *without* --policy flag; this lets us
@@ -143,6 +143,75 @@ END_PUSH
END_TESTS
}
@test "signing: remove signature" {
run_skopeo '?' standalone-sign /dev/null busybox alice@test.redhat.com -o /dev/null
if [[ "$output" =~ 'signing is not supported' ]]; then
skip "skopeo built without support for creating signatures"
return 1
fi
if [ "$status" -ne 0 ]; then
die "exit code is $status; expected 0"
fi
# Cache local copy
run_skopeo copy docker://quay.io/libpod/busybox:latest \
dir:$TESTDIR/busybox
# Push a signed image
run_skopeo --registries.d $REGISTRIES_D \
copy --dest-tls-verify=false \
--sign-by=alice@test.redhat.com \
dir:$TESTDIR/busybox \
docker://localhost:5000/myns/alice:signed
# Fetch the image with signature
run_skopeo --registries.d $REGISTRIES_D \
--policy $POLICY_JSON \
copy --src-tls-verify=false \
docker://localhost:5000/myns/alice:signed \
dir:$TESTDIR/busybox-signed
# Fetch the image with removing signature
run_skopeo --registries.d $REGISTRIES_D \
--policy $POLICY_JSON \
copy --src-tls-verify=false \
--remove-signatures \
docker://localhost:5000/myns/alice:signed \
dir:$TESTDIR/busybox-unsigned
ls $TESTDIR/busybox-signed | grep "signature"
[ -z "$(ls $TESTDIR/busybox-unsigned | grep "signature")" ]
}
@test "signing: standalone" {
run_skopeo '?' standalone-sign /dev/null busybox alice@test.redhat.com -o /dev/null
if [[ "$output" =~ 'signing is not supported' ]]; then
skip "skopeo built without support for creating signatures"
return 1
fi
if [ "$status" -ne 0 ]; then
die "exit code is $status; expected 0"
fi
run_skopeo copy --dest-tls-verify=false \
docker://quay.io/libpod/busybox:latest \
docker://localhost:5000/busybox:latest
run_skopeo copy --src-tls-verify=false \
docker://localhost:5000/busybox:latest \
dir:$TESTDIR/busybox
# Standalone sign
run_skopeo standalone-sign -o $TESTDIR/busybox.signature \
$TESTDIR/busybox/manifest.json \
localhost:5000/busybox:latest \
alice@test.redhat.com
# Standalone verify
fingerprint=$(gpg --list-keys | grep -B1 alice.test.redhat.com | head -n 1)
run_skopeo standalone-verify $TESTDIR/busybox/manifest.json \
localhost:5000/busybox:latest \
$fingerprint \
$TESTDIR/busybox.signature
# manifest digest
digest=$(echo "$output" | awk '{print $4;}')
run_skopeo manifest-digest $TESTDIR/busybox/manifest.json
expect_output $digest
}
teardown() {
podman rm -f reg

View File

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

View File

@@ -6,7 +6,7 @@ SKOPEO_BINARY=${SKOPEO_BINARY:-$(dirname ${BASH_SOURCE})/../skopeo}
SKOPEO_TIMEOUT=${SKOPEO_TIMEOUT:-300}
# Default image to run as a local registry
REGISTRY_FQIN=${SKOPEO_TEST_REGISTRY_FQIN:-docker.io/library/registry:2}
REGISTRY_FQIN=${SKOPEO_TEST_REGISTRY_FQIN:-quay.io/libpod/registry:2}
###############################################################################
# BEGIN setup/teardown
@@ -194,7 +194,7 @@ function expect_output() {
fi
# This is a multi-line message, which may in turn contain multi-line
# output, so let's format it ourself, readably
# output, so let's format it ourselves, readably
local -a actual_split
readarray -t actual_split <<<"$actual"
printf "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" >&2
@@ -314,8 +314,7 @@ start_registry() {
fi
if ! egrep -q "^$testuser:" $AUTHDIR/htpasswd; then
log_and_run $PODMAN run --rm --entrypoint htpasswd $REGISTRY_FQIN \
-Bbn $testuser $testpassword >> $AUTHDIR/htpasswd
htpasswd -Bbn $testuser $testpassword >> $AUTHDIR/htpasswd
fi
reg_args+=(
@@ -332,7 +331,8 @@ start_registry() {
log_and_run openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout $AUTHDIR/domain.key -x509 -days 2 \
-out $CERT \
-subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost"
-subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \
-addext subjectAltName=DNS:localhost
fi
reg_args+=(
@@ -356,7 +356,7 @@ start_registry() {
return
fi
timeout=$(expr $timeout - 1)
timeout=$(( timeout - 1 ))
sleep 1
done
die "Timed out waiting for registry container to respond on :$port"

70
systemtest/make-noarch-manifest Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/sh
#
# Tool for creating an image whose OS and arch will (probably) never
# match a system on which skopeo will run. This image will be used
# in the 'inspect' test.
#
set -ex
# Name and tag of the image we create
imgname=notmyarch
imgtag=$(date +%Y%m%d)
# (In case older image exists from a prior run)
buildah rmi $imgname:$imgtag &>/dev/null || true
#
# Step 1: create an image containing only a README and a copy of this script
#
id=$(buildah from scratch)
now=$(date --rfc-3339=seconds)
readme=$(mktemp -t README.XXXXXXXX)
ME=$(basename $0)
cat >| $readme <<EOF
This is a dummy image intended solely for skopeo testing.
This image was created $now
The script used to create this image is available as $ME
EOF
buildah copy $id $readme /README
buildah copy $id $0 /$ME
buildah commit $id my_tmp_image
buildah rm $id
#
# Step 2: create a manifest list, then add the above image but with
# an os+arch override.
#
buildah manifest create $imgname:$imgtag
buildah manifest add \
--os amigaos \
--arch mc68000 \
--variant 1000 \
$imgname:$imgtag my_tmp_image
# Done. Show instructions.
cat <<EOF
DONE!
You can inspect the created image with:
skopeo inspect --raw containers-storage:localhost/$imgname:$imgtag | jq .
(FIXME: is there a way to, like, mount the image and verify the files?)
If you're happy with this image, you can now:
buildah manifest push --all $imgname:$imgtag docker://quay.io/libpod/$imgname:$imgtag
Once done, you urgently need to:
buildah rmi $imgname:$imgtag my_tmp_image
If you don't do this, 'podman images' will barf catastrophically!
EOF

1
vendor/github.com/Microsoft/go-winio/CODEOWNERS generated vendored Normal file
View File

@@ -0,0 +1 @@
* @microsoft/containerplat

View File

@@ -1,4 +1,4 @@
# go-winio
# go-winio [![Build Status](https://github.com/microsoft/go-winio/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/go-winio/actions/workflows/ci.yml)
This repository contains utilities for efficiently performing Win32 IO operations in
Go. Currently, this is focused on accessing named pipes and other file handles, and

View File

@@ -1,344 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tar implements access to tar archives.
// It aims to cover most of the variations, including those produced
// by GNU and BSD tars.
//
// References:
// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
package tar
import (
"bytes"
"errors"
"fmt"
"os"
"path"
"time"
)
const (
blockSize = 512
// Types
TypeReg = '0' // regular file
TypeRegA = '\x00' // regular file
TypeLink = '1' // hard link
TypeSymlink = '2' // symbolic link
TypeChar = '3' // character device node
TypeBlock = '4' // block device node
TypeDir = '5' // directory
TypeFifo = '6' // fifo node
TypeCont = '7' // reserved
TypeXHeader = 'x' // extended header
TypeXGlobalHeader = 'g' // global extended header
TypeGNULongName = 'L' // Next file has a long name
TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
TypeGNUSparse = 'S' // sparse file
)
// A Header represents a single header in a tar archive.
// Some fields may not be populated.
type Header struct {
Name string // name of header file entry
Mode int64 // permission and mode bits
Uid int // user id of owner
Gid int // group id of owner
Size int64 // length in bytes
ModTime time.Time // modified time
Typeflag byte // type of header entry
Linkname string // target name of link
Uname string // user name of owner
Gname string // group name of owner
Devmajor int64 // major number of character or block device
Devminor int64 // minor number of character or block device
AccessTime time.Time // access time
ChangeTime time.Time // status change time
CreationTime time.Time // creation time
Xattrs map[string]string
Winheaders map[string]string
}
// File name constants from the tar spec.
const (
fileNameSize = 100 // Maximum number of bytes in a standard tar name.
fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
)
// FileInfo returns an os.FileInfo for the Header.
func (h *Header) FileInfo() os.FileInfo {
return headerFileInfo{h}
}
// headerFileInfo implements os.FileInfo.
type headerFileInfo struct {
h *Header
}
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
func (fi headerFileInfo) Sys() interface{} { return fi.h }
// Name returns the base name of the file.
func (fi headerFileInfo) Name() string {
if fi.IsDir() {
return path.Base(path.Clean(fi.h.Name))
}
return path.Base(fi.h.Name)
}
// Mode returns the permission and mode bits for the headerFileInfo.
func (fi headerFileInfo) Mode() (mode os.FileMode) {
// Set file permission bits.
mode = os.FileMode(fi.h.Mode).Perm()
// Set setuid, setgid and sticky bits.
if fi.h.Mode&c_ISUID != 0 {
// setuid
mode |= os.ModeSetuid
}
if fi.h.Mode&c_ISGID != 0 {
// setgid
mode |= os.ModeSetgid
}
if fi.h.Mode&c_ISVTX != 0 {
// sticky
mode |= os.ModeSticky
}
// Set file mode bits.
// clear perm, setuid, setgid and sticky bits.
m := os.FileMode(fi.h.Mode) &^ 07777
if m == c_ISDIR {
// directory
mode |= os.ModeDir
}
if m == c_ISFIFO {
// named pipe (FIFO)
mode |= os.ModeNamedPipe
}
if m == c_ISLNK {
// symbolic link
mode |= os.ModeSymlink
}
if m == c_ISBLK {
// device file
mode |= os.ModeDevice
}
if m == c_ISCHR {
// Unix character device
mode |= os.ModeDevice
mode |= os.ModeCharDevice
}
if m == c_ISSOCK {
// Unix domain socket
mode |= os.ModeSocket
}
switch fi.h.Typeflag {
case TypeSymlink:
// symbolic link
mode |= os.ModeSymlink
case TypeChar:
// character device node
mode |= os.ModeDevice
mode |= os.ModeCharDevice
case TypeBlock:
// block device node
mode |= os.ModeDevice
case TypeDir:
// directory
mode |= os.ModeDir
case TypeFifo:
// fifo node
mode |= os.ModeNamedPipe
}
return mode
}
// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error
// Mode constants from the tar spec.
const (
c_ISUID = 04000 // Set uid
c_ISGID = 02000 // Set gid
c_ISVTX = 01000 // Save text (sticky bit)
c_ISDIR = 040000 // Directory
c_ISFIFO = 010000 // FIFO
c_ISREG = 0100000 // Regular file
c_ISLNK = 0120000 // Symbolic link
c_ISBLK = 060000 // Block special file
c_ISCHR = 020000 // Character special file
c_ISSOCK = 0140000 // Socket
)
// Keywords for the PAX Extended Header
const (
paxAtime = "atime"
paxCharset = "charset"
paxComment = "comment"
paxCtime = "ctime" // please note that ctime is not a valid pax header.
paxCreationTime = "LIBARCHIVE.creationtime"
paxGid = "gid"
paxGname = "gname"
paxLinkpath = "linkpath"
paxMtime = "mtime"
paxPath = "path"
paxSize = "size"
paxUid = "uid"
paxUname = "uname"
paxXattr = "SCHILY.xattr."
paxWindows = "MSWINDOWS."
paxNone = ""
)
// FileInfoHeader creates a partially-populated Header from fi.
// If fi describes a symlink, FileInfoHeader records link as the link target.
// If fi describes a directory, a slash is appended to the name.
// Because os.FileInfo's Name method returns only the base name of
// the file it describes, it may be necessary to modify the Name field
// of the returned header to provide the full path name of the file.
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
if fi == nil {
return nil, errors.New("tar: FileInfo is nil")
}
fm := fi.Mode()
h := &Header{
Name: fi.Name(),
ModTime: fi.ModTime(),
Mode: int64(fm.Perm()), // or'd with c_IS* constants later
}
switch {
case fm.IsRegular():
h.Mode |= c_ISREG
h.Typeflag = TypeReg
h.Size = fi.Size()
case fi.IsDir():
h.Typeflag = TypeDir
h.Mode |= c_ISDIR
h.Name += "/"
case fm&os.ModeSymlink != 0:
h.Typeflag = TypeSymlink
h.Mode |= c_ISLNK
h.Linkname = link
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
h.Mode |= c_ISCHR
h.Typeflag = TypeChar
} else {
h.Mode |= c_ISBLK
h.Typeflag = TypeBlock
}
case fm&os.ModeNamedPipe != 0:
h.Typeflag = TypeFifo
h.Mode |= c_ISFIFO
case fm&os.ModeSocket != 0:
h.Mode |= c_ISSOCK
default:
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
}
if fm&os.ModeSetuid != 0 {
h.Mode |= c_ISUID
}
if fm&os.ModeSetgid != 0 {
h.Mode |= c_ISGID
}
if fm&os.ModeSticky != 0 {
h.Mode |= c_ISVTX
}
// If possible, populate additional fields from OS-specific
// FileInfo fields.
if sys, ok := fi.Sys().(*Header); ok {
// This FileInfo came from a Header (not the OS). Use the
// original Header to populate all remaining fields.
h.Uid = sys.Uid
h.Gid = sys.Gid
h.Uname = sys.Uname
h.Gname = sys.Gname
h.AccessTime = sys.AccessTime
h.ChangeTime = sys.ChangeTime
if sys.Xattrs != nil {
h.Xattrs = make(map[string]string)
for k, v := range sys.Xattrs {
h.Xattrs[k] = v
}
}
if sys.Typeflag == TypeLink {
// hard link
h.Typeflag = TypeLink
h.Size = 0
h.Linkname = sys.Linkname
}
}
if sysStat != nil {
return h, sysStat(fi, h)
}
return h, nil
}
var zeroBlock = make([]byte, blockSize)
// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
// We compute and return both.
func checksum(header []byte) (unsigned int64, signed int64) {
for i := 0; i < len(header); i++ {
if i == 148 {
// The chksum field (header[148:156]) is special: it should be treated as space bytes.
unsigned += ' ' * 8
signed += ' ' * 8
i += 7
continue
}
unsigned += int64(header[i])
signed += int64(int8(header[i]))
}
return
}
type slicer []byte
func (sp *slicer) next(n int) (b []byte) {
s := *sp
b, *sp = s[0:n], s[n:]
return
}
func isASCII(s string) bool {
for _, c := range s {
if c >= 0x80 {
return false
}
}
return true
}
func toASCII(s string) string {
if isASCII(s) {
return s
}
var buf bytes.Buffer
for _, c := range s {
if c < 0x80 {
buf.WriteByte(byte(c))
}
}
return buf.String()
}
// isHeaderOnlyType checks if the given type flag is of the type that has no
// data section even if a size is specified.
func isHeaderOnlyType(flag byte) bool {
switch flag {
case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
return true
default:
return false
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux dragonfly openbsd solaris
package tar
import (
"syscall"
"time"
)
func statAtime(st *syscall.Stat_t) time.Time {
return time.Unix(st.Atim.Unix())
}
func statCtime(st *syscall.Stat_t) time.Time {
return time.Unix(st.Ctim.Unix())
}

View File

@@ -1,20 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd netbsd
package tar
import (
"syscall"
"time"
)
func statAtime(st *syscall.Stat_t) time.Time {
return time.Unix(st.Atimespec.Unix())
}
func statCtime(st *syscall.Stat_t) time.Time {
return time.Unix(st.Ctimespec.Unix())
}

View File

@@ -1,32 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux darwin dragonfly freebsd openbsd netbsd solaris
package tar
import (
"os"
"syscall"
)
func init() {
sysStat = statUnix
}
func statUnix(fi os.FileInfo, h *Header) error {
sys, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return nil
}
h.Uid = int(sys.Uid)
h.Gid = int(sys.Gid)
// TODO(bradfitz): populate username & group. os/user
// doesn't cache LookupId lookups, and lacks group
// lookup functions.
h.AccessTime = statAtime(sys)
h.ChangeTime = statCtime(sys)
// TODO(bradfitz): major/minor device numbers?
return nil
}

View File

@@ -1,444 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tar
// TODO(dsymonds):
// - catch more errors (no first header, etc.)
import (
"bytes"
"errors"
"fmt"
"io"
"path"
"sort"
"strconv"
"strings"
"time"
)
var (
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
errInvalidHeader = errors.New("archive/tar: header field too long or contains invalid values")
)
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
// A tar archive consists of a sequence of files.
// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
// writing at most hdr.Size bytes in total.
type Writer struct {
w io.Writer
err error
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
closed bool
usedBinary bool // whether the binary numeric field extension was used
preferPax bool // use pax header instead of binary numeric header
hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
}
type formatter struct {
err error // Last error seen
}
// NewWriter creates a new Writer writing to w.
func NewWriter(w io.Writer) *Writer { return &Writer{w: w, preferPax: true} }
// Flush finishes writing the current file (optional).
func (tw *Writer) Flush() error {
if tw.nb > 0 {
tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
return tw.err
}
n := tw.nb + tw.pad
for n > 0 && tw.err == nil {
nr := n
if nr > blockSize {
nr = blockSize
}
var nw int
nw, tw.err = tw.w.Write(zeroBlock[0:nr])
n -= int64(nw)
}
tw.nb = 0
tw.pad = 0
return tw.err
}
// Write s into b, terminating it with a NUL if there is room.
func (f *formatter) formatString(b []byte, s string) {
if len(s) > len(b) {
f.err = ErrFieldTooLong
return
}
ascii := toASCII(s)
copy(b, ascii)
if len(ascii) < len(b) {
b[len(ascii)] = 0
}
}
// Encode x as an octal ASCII string and write it into b with leading zeros.
func (f *formatter) formatOctal(b []byte, x int64) {
s := strconv.FormatInt(x, 8)
// leading zeros, but leave room for a NUL.
for len(s)+1 < len(b) {
s = "0" + s
}
f.formatString(b, s)
}
// fitsInBase256 reports whether x can be encoded into n bytes using base-256
// encoding. Unlike octal encoding, base-256 encoding does not require that the
// string ends with a NUL character. Thus, all n bytes are available for output.
//
// If operating in binary mode, this assumes strict GNU binary mode; which means
// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
// equivalent to the sign bit in two's complement form.
func fitsInBase256(n int, x int64) bool {
var binBits = uint(n-1) * 8
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
}
// Write x into b, as binary (GNUtar/star extension).
func (f *formatter) formatNumeric(b []byte, x int64) {
if fitsInBase256(len(b), x) {
for i := len(b) - 1; i >= 0; i-- {
b[i] = byte(x)
x >>= 8
}
b[0] |= 0x80 // Highest bit indicates binary format
return
}
f.formatOctal(b, 0) // Last resort, just write zero
f.err = ErrFieldTooLong
}
var (
minTime = time.Unix(0, 0)
// There is room for 11 octal digits (33 bits) of mtime.
maxTime = minTime.Add((1<<33 - 1) * time.Second)
)
// WriteHeader writes hdr and prepares to accept the file's contents.
// WriteHeader calls Flush if it is not the first header.
// Calling after a Close will return ErrWriteAfterClose.
func (tw *Writer) WriteHeader(hdr *Header) error {
return tw.writeHeader(hdr, true)
}
// WriteHeader writes hdr and prepares to accept the file's contents.
// WriteHeader calls Flush if it is not the first header.
// Calling after a Close will return ErrWriteAfterClose.
// As this method is called internally by writePax header to allow it to
// suppress writing the pax header.
func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
if tw.closed {
return ErrWriteAfterClose
}
if tw.err == nil {
tw.Flush()
}
if tw.err != nil {
return tw.err
}
// a map to hold pax header records, if any are needed
paxHeaders := make(map[string]string)
// TODO(shanemhansen): we might want to use PAX headers for
// subsecond time resolution, but for now let's just capture
// too long fields or non ascii characters
var f formatter
var header []byte
// We need to select which scratch buffer to use carefully,
// since this method is called recursively to write PAX headers.
// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
// already being used by the non-recursive call, so we must use paxHdrBuff.
header = tw.hdrBuff[:]
if !allowPax {
header = tw.paxHdrBuff[:]
}
copy(header, zeroBlock)
s := slicer(header)
// Wrappers around formatter that automatically sets paxHeaders if the
// argument extends beyond the capacity of the input byte slice.
var formatString = func(b []byte, s string, paxKeyword string) {
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
if needsPaxHeader {
paxHeaders[paxKeyword] = s
return
}
f.formatString(b, s)
}
var formatNumeric = func(b []byte, x int64, paxKeyword string) {
// Try octal first.
s := strconv.FormatInt(x, 8)
if len(s) < len(b) {
f.formatOctal(b, x)
return
}
// If it is too long for octal, and PAX is preferred, use a PAX header.
if paxKeyword != paxNone && tw.preferPax {
f.formatOctal(b, 0)
s := strconv.FormatInt(x, 10)
paxHeaders[paxKeyword] = s
return
}
tw.usedBinary = true
f.formatNumeric(b, x)
}
var formatTime = func(b []byte, t time.Time, paxKeyword string) {
var unixTime int64
if !t.Before(minTime) && !t.After(maxTime) {
unixTime = t.Unix()
}
formatNumeric(b, unixTime, paxNone)
// Write a PAX header if the time didn't fit precisely.
if paxKeyword != "" && tw.preferPax && allowPax && (t.Nanosecond() != 0 || !t.Before(minTime) || !t.After(maxTime)) {
paxHeaders[paxKeyword] = formatPAXTime(t)
}
}
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
pathHeaderBytes := s.next(fileNameSize)
formatString(pathHeaderBytes, hdr.Name, paxPath)
f.formatOctal(s.next(8), hdr.Mode) // 100:108
formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
formatTime(s.next(12), hdr.ModTime, paxMtime) // 136:148
s.next(8) // chksum (148:156)
s.next(1)[0] = hdr.Typeflag // 156:157
formatString(s.next(100), hdr.Linkname, paxLinkpath)
copy(s.next(8), []byte("ustar\x0000")) // 257:265
formatString(s.next(32), hdr.Uname, paxUname) // 265:297
formatString(s.next(32), hdr.Gname, paxGname) // 297:329
formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
prefixHeaderBytes := s.next(155)
formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
copy(header[257:265], []byte("ustar \x00"))
}
_, paxPathUsed := paxHeaders[paxPath]
// try to use a ustar header when only the name is too long
if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
prefix, suffix, ok := splitUSTARPath(hdr.Name)
if ok {
// Since we can encode in USTAR format, disable PAX header.
delete(paxHeaders, paxPath)
// Update the path fields
formatString(pathHeaderBytes, suffix, paxNone)
formatString(prefixHeaderBytes, prefix, paxNone)
}
}
// The chksum field is terminated by a NUL and a space.
// This is different from the other octal fields.
chksum, _ := checksum(header)
f.formatOctal(header[148:155], chksum) // Never fails
header[155] = ' '
// Check if there were any formatting errors.
if f.err != nil {
tw.err = f.err
return tw.err
}
if allowPax {
if !hdr.AccessTime.IsZero() {
paxHeaders[paxAtime] = formatPAXTime(hdr.AccessTime)
}
if !hdr.ChangeTime.IsZero() {
paxHeaders[paxCtime] = formatPAXTime(hdr.ChangeTime)
}
if !hdr.CreationTime.IsZero() {
paxHeaders[paxCreationTime] = formatPAXTime(hdr.CreationTime)
}
for k, v := range hdr.Xattrs {
paxHeaders[paxXattr+k] = v
}
for k, v := range hdr.Winheaders {
paxHeaders[paxWindows+k] = v
}
}
if len(paxHeaders) > 0 {
if !allowPax {
return errInvalidHeader
}
if err := tw.writePAXHeader(hdr, paxHeaders); err != nil {
return err
}
}
tw.nb = int64(hdr.Size)
tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
_, tw.err = tw.w.Write(header)
return tw.err
}
func formatPAXTime(t time.Time) string {
sec := t.Unix()
usec := t.Nanosecond()
s := strconv.FormatInt(sec, 10)
if usec != 0 {
s = fmt.Sprintf("%s.%09d", s, usec)
}
return s
}
// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
// If the path is not splittable, then it will return ("", "", false).
func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
length := len(name)
if length <= fileNameSize || !isASCII(name) {
return "", "", false
} else if length > fileNamePrefixSize+1 {
length = fileNamePrefixSize + 1
} else if name[length-1] == '/' {
length--
}
i := strings.LastIndex(name[:length], "/")
nlen := len(name) - i - 1 // nlen is length of suffix
plen := i // plen is length of prefix
if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
return "", "", false
}
return name[:i], name[i+1:], true
}
// writePaxHeader writes an extended pax header to the
// archive.
func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error {
// Prepare extended header
ext := new(Header)
ext.Typeflag = TypeXHeader
// Setting ModTime is required for reader parsing to
// succeed, and seems harmless enough.
ext.ModTime = hdr.ModTime
// The spec asks that we namespace our pseudo files
// with the current pid. However, this results in differing outputs
// for identical inputs. As such, the constant 0 is now used instead.
// golang.org/issue/12358
dir, file := path.Split(hdr.Name)
fullName := path.Join(dir, "PaxHeaders.0", file)
ascii := toASCII(fullName)
if len(ascii) > 100 {
ascii = ascii[:100]
}
ext.Name = ascii
// Construct the body
var buf bytes.Buffer
// Keys are sorted before writing to body to allow deterministic output.
var keys []string
for k := range paxHeaders {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
}
ext.Size = int64(len(buf.Bytes()))
if err := tw.writeHeader(ext, false); err != nil {
return err
}
if _, err := tw.Write(buf.Bytes()); err != nil {
return err
}
if err := tw.Flush(); err != nil {
return err
}
return nil
}
// formatPAXRecord formats a single PAX record, prefixing it with the
// appropriate length.
func formatPAXRecord(k, v string) string {
const padding = 3 // Extra padding for ' ', '=', and '\n'
size := len(k) + len(v) + padding
size += len(strconv.Itoa(size))
record := fmt.Sprintf("%d %s=%s\n", size, k, v)
// Final adjustment if adding size field increased the record size.
if len(record) != size {
size = len(record)
record = fmt.Sprintf("%d %s=%s\n", size, k, v)
}
return record
}
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.
func (tw *Writer) Write(b []byte) (n int, err error) {
if tw.closed {
err = ErrWriteAfterClose
return
}
overwrite := false
if int64(len(b)) > tw.nb {
b = b[0:tw.nb]
overwrite = true
}
n, err = tw.w.Write(b)
tw.nb -= int64(n)
if err == nil && overwrite {
err = ErrWriteTooLong
return
}
tw.err = err
return
}
// Close closes the tar archive, flushing any unwritten
// data to the underlying writer.
func (tw *Writer) Close() error {
if tw.err != nil || tw.closed {
return tw.err
}
tw.Flush()
tw.closed = true
if tw.err != nil {
return tw.err
}
// trailer: two zero blocks
for i := 0; i < 2; i++ {
_, tw.err = tw.w.Write(zeroBlock)
if tw.err != nil {
break
}
}
return tw.err
}

View File

@@ -0,0 +1,68 @@
package backuptar
import (
"archive/tar"
"fmt"
"strconv"
"strings"
"time"
)
// Functions copied from https://github.com/golang/go/blob/master/src/archive/tar/strconv.go
// as we need to manage the LIBARCHIVE.creationtime PAXRecord manually.
// Idea taken from containerd which did the same thing.
// parsePAXTime takes a string of the form %d.%d as described in the PAX
// specification. Note that this implementation allows for negative timestamps,
// which is allowed for by the PAX specification, but not always portable.
func parsePAXTime(s string) (time.Time, error) {
const maxNanoSecondDigits = 9
// Split string into seconds and sub-seconds parts.
ss, sn := s, ""
if pos := strings.IndexByte(s, '.'); pos >= 0 {
ss, sn = s[:pos], s[pos+1:]
}
// Parse the seconds.
secs, err := strconv.ParseInt(ss, 10, 64)
if err != nil {
return time.Time{}, tar.ErrHeader
}
if len(sn) == 0 {
return time.Unix(secs, 0), nil // No sub-second values
}
// Parse the nanoseconds.
if strings.Trim(sn, "0123456789") != "" {
return time.Time{}, tar.ErrHeader
}
if len(sn) < maxNanoSecondDigits {
sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
} else {
sn = sn[:maxNanoSecondDigits] // Right truncate
}
nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
if len(ss) > 0 && ss[0] == '-' {
return time.Unix(secs, -1*nsecs), nil // Negative correction
}
return time.Unix(secs, nsecs), nil
}
// formatPAXTime converts ts into a time of the form %d.%d as described in the
// PAX specification. This function is capable of negative timestamps.
func formatPAXTime(ts time.Time) (s string) {
secs, nsecs := ts.Unix(), ts.Nanosecond()
if nsecs == 0 {
return strconv.FormatInt(secs, 10)
}
// If seconds is negative, then perform correction.
sign := ""
if secs < 0 {
sign = "-" // Remember sign
secs = -(secs + 1) // Add a second to secs
nsecs = -(nsecs - 1e9) // Take that second away from nsecs
}
return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0")
}

View File

@@ -3,6 +3,7 @@
package backuptar
import (
"archive/tar"
"encoding/base64"
"errors"
"fmt"
@@ -15,7 +16,7 @@ import (
"time"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/archive/tar" // until archive/tar supports pax extensions in its interface
"golang.org/x/sys/windows"
)
const (
@@ -32,11 +33,13 @@ const (
)
const (
hdrFileAttributes = "fileattr"
hdrSecurityDescriptor = "sd"
hdrRawSecurityDescriptor = "rawsd"
hdrMountPoint = "mountpoint"
hdrEaPrefix = "xattr."
hdrFileAttributes = "MSWINDOWS.fileattr"
hdrSecurityDescriptor = "MSWINDOWS.sd"
hdrRawSecurityDescriptor = "MSWINDOWS.rawsd"
hdrMountPoint = "MSWINDOWS.mountpoint"
hdrEaPrefix = "MSWINDOWS.xattr."
hdrCreationTime = "LIBARCHIVE.creationtime"
)
func writeZeroes(w io.Writer, count int64) error {
@@ -86,16 +89,17 @@ func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error {
// BasicInfoHeader creates a tar header from basic file information.
func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *tar.Header {
hdr := &tar.Header{
Name: filepath.ToSlash(name),
Size: size,
Typeflag: tar.TypeReg,
ModTime: time.Unix(0, fileInfo.LastWriteTime.Nanoseconds()),
ChangeTime: time.Unix(0, fileInfo.ChangeTime.Nanoseconds()),
AccessTime: time.Unix(0, fileInfo.LastAccessTime.Nanoseconds()),
CreationTime: time.Unix(0, fileInfo.CreationTime.Nanoseconds()),
Winheaders: make(map[string]string),
Format: tar.FormatPAX,
Name: filepath.ToSlash(name),
Size: size,
Typeflag: tar.TypeReg,
ModTime: time.Unix(0, fileInfo.LastWriteTime.Nanoseconds()),
ChangeTime: time.Unix(0, fileInfo.ChangeTime.Nanoseconds()),
AccessTime: time.Unix(0, fileInfo.LastAccessTime.Nanoseconds()),
PAXRecords: make(map[string]string),
}
hdr.Winheaders[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes)
hdr.PAXRecords[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes)
hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds()))
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
hdr.Mode |= c_ISDIR
@@ -155,7 +159,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
if err != nil {
return err
}
hdr.Winheaders[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
hdr.PAXRecords[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
case winio.BackupReparseData:
hdr.Mode |= c_ISLNK
@@ -166,7 +170,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
return err
}
if rp.IsMountPoint {
hdr.Winheaders[hdrMountPoint] = "1"
hdr.PAXRecords[hdrMountPoint] = "1"
}
hdr.Linkname = rp.Target
@@ -183,7 +187,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
// Use base64 encoding for the binary value. Note that there
// is no way to encode the EA's flags, since their use doesn't
// make any sense for persisted EAs.
hdr.Winheaders[hdrEaPrefix+ea.Name] = base64.StdEncoding.EncodeToString(ea.Value)
hdr.PAXRecords[hdrEaPrefix+ea.Name] = base64.StdEncoding.EncodeToString(ea.Value)
}
case winio.BackupAlternateData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData:
@@ -254,6 +258,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
}
if (bhdr.Attributes & winio.StreamSparseAttributes) == 0 {
hdr = &tar.Header{
Format: hdr.Format,
Name: name + altName,
Mode: hdr.Mode,
Typeflag: tar.TypeReg,
@@ -293,12 +298,13 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
size = hdr.Size
}
fileInfo = &winio.FileBasicInfo{
LastAccessTime: syscall.NsecToFiletime(hdr.AccessTime.UnixNano()),
LastWriteTime: syscall.NsecToFiletime(hdr.ModTime.UnixNano()),
ChangeTime: syscall.NsecToFiletime(hdr.ChangeTime.UnixNano()),
CreationTime: syscall.NsecToFiletime(hdr.CreationTime.UnixNano()),
LastAccessTime: windows.NsecToFiletime(hdr.AccessTime.UnixNano()),
LastWriteTime: windows.NsecToFiletime(hdr.ModTime.UnixNano()),
ChangeTime: windows.NsecToFiletime(hdr.ChangeTime.UnixNano()),
// Default to ModTime, we'll pull hdrCreationTime below if present
CreationTime: windows.NsecToFiletime(hdr.ModTime.UnixNano()),
}
if attrStr, ok := hdr.Winheaders[hdrFileAttributes]; ok {
if attrStr, ok := hdr.PAXRecords[hdrFileAttributes]; ok {
attr, err := strconv.ParseUint(attrStr, 10, 32)
if err != nil {
return "", 0, nil, err
@@ -309,6 +315,13 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY
}
}
if creationTimeStr, ok := hdr.PAXRecords[hdrCreationTime]; ok {
creationTime, err := parsePAXTime(creationTimeStr)
if err != nil {
return "", 0, nil, err
}
fileInfo.CreationTime = windows.NsecToFiletime(creationTime.UnixNano())
}
return
}
@@ -321,13 +334,13 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
var err error
// Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written
// by this library will have raw binary for the security descriptor.
if sddl, ok := hdr.Winheaders[hdrSecurityDescriptor]; ok {
if sddl, ok := hdr.PAXRecords[hdrSecurityDescriptor]; ok {
sd, err = winio.SddlToSecurityDescriptor(sddl)
if err != nil {
return nil, err
}
}
if sdraw, ok := hdr.Winheaders[hdrRawSecurityDescriptor]; ok {
if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok {
sd, err = base64.StdEncoding.DecodeString(sdraw)
if err != nil {
return nil, err
@@ -348,7 +361,7 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
}
}
var eas []winio.ExtendedAttribute
for k, v := range hdr.Winheaders {
for k, v := range hdr.PAXRecords {
if !strings.HasPrefix(k, hdrEaPrefix) {
continue
}
@@ -380,7 +393,7 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
}
}
if hdr.Typeflag == tar.TypeSymlink {
_, isMountPoint := hdr.Winheaders[hdrMountPoint]
_, isMountPoint := hdr.PAXRecords[hdrMountPoint]
rp := winio.ReparsePoint{
Target: filepath.FromSlash(hdr.Linkname),
IsMountPoint: isMountPoint,

View File

@@ -5,21 +5,14 @@ package winio
import (
"os"
"runtime"
"syscall"
"unsafe"
)
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
const (
fileBasicInfo = 0
fileIDInfo = 0x12
"golang.org/x/sys/windows"
)
// FileBasicInfo contains file access time and file attributes information.
type FileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
FileAttributes uint32
pad uint32 // padding
}
@@ -27,7 +20,7 @@ type FileBasicInfo struct {
// GetFileBasicInfo retrieves times and attributes for a file.
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
bi := &FileBasicInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
@@ -36,13 +29,32 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
// SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return nil
}
// FileStandardInfo contains extended information for the file.
// FILE_STANDARD_INFO in WinBase.h
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info
type FileStandardInfo struct {
AllocationSize, EndOfFile int64
NumberOfLinks uint32
DeletePending, Directory bool
}
// GetFileStandardInfo retrieves ended information for the file.
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
si := &FileStandardInfo{}
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return si, nil
}
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
// unique on a system.
type FileIDInfo struct {
@@ -53,7 +65,7 @@ type FileIDInfo struct {
// GetFileID retrieves the unique (volume, file ID) pair for a file.
func GetFileID(f *os.File) (*FileIDInfo, error) {
fileID := &FileIDInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)

View File

@@ -3,7 +3,7 @@ module github.com/Microsoft/go-winio
go 1.12
require (
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.1
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.7.0
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
)

View File

@@ -1,18 +1,14 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -1,3 +1,5 @@
// +build windows
package winio
import (

View File

@@ -182,13 +182,14 @@ func (s pipeAddress) String() string {
}
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
for {
select {
case <-ctx.Done():
return syscall.Handle(0), ctx.Err()
default:
h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err == nil {
return h, nil
}
@@ -197,7 +198,7 @@ func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
}
// Wait 10 msec and try again. This is a rather simplistic
// view, as we always try each 10 milliseconds.
time.Sleep(time.Millisecond * 10)
time.Sleep(10 * time.Millisecond)
}
}
}
@@ -210,7 +211,7 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
if timeout != nil {
absTimeout = time.Now().Add(*timeout)
} else {
absTimeout = time.Now().Add(time.Second * 2)
absTimeout = time.Now().Add(2 * time.Second)
}
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
conn, err := DialPipeContext(ctx, path)
@@ -223,9 +224,15 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
// cancellation or timeout.
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE)
}
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
// cancellation or timeout.
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error
var h syscall.Handle
h, err = tryDialPipe(ctx, &path)
h, err = tryDialPipe(ctx, &path, access)
if err != nil {
return nil, err
}
@@ -422,10 +429,10 @@ type PipeConfig struct {
// when the pipe is in message mode.
MessageMode bool
// InputBufferSize specifies the size the input buffer, in bytes.
// InputBufferSize specifies the size of the input buffer, in bytes.
InputBufferSize int32
// OutputBufferSize specifies the size the input buffer, in bytes.
// OutputBufferSize specifies the size of the output buffer, in bytes.
OutputBufferSize int32
}

View File

@@ -1,3 +1,5 @@
// +build windows
// Package guid provides a GUID type. The backing structure for a GUID is
// identical to that used by the golang.org/x/sys/windows GUID type.
// There are two main binary encodings used for a GUID, the big-endian encoding,

View File

@@ -0,0 +1,161 @@
// +build windows
package security
import (
"os"
"syscall"
"unsafe"
"github.com/pkg/errors"
)
type (
accessMask uint32
accessMode uint32
desiredAccess uint32
inheritMode uint32
objectType uint32
shareMode uint32
securityInformation uint32
trusteeForm uint32
trusteeType uint32
explicitAccess struct {
accessPermissions accessMask
accessMode accessMode
inheritance inheritMode
trustee trustee
}
trustee struct {
multipleTrustee *trustee
multipleTrusteeOperation int32
trusteeForm trusteeForm
trusteeType trusteeType
name uintptr
}
)
const (
accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
accessModeGrant accessMode = 1
desiredAccessReadControl desiredAccess = 0x20000
desiredAccessWriteDac desiredAccess = 0x40000
gvmga = "GrantVmGroupAccess:"
inheritModeNoInheritance inheritMode = 0x0
inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
objectTypeFileObject objectType = 0x1
securityInformationDACL securityInformation = 0x4
shareModeRead shareMode = 0x1
shareModeWrite shareMode = 0x2
sidVmGroup = "S-1-5-83-0"
trusteeFormIsSid trusteeForm = 0
trusteeTypeWellKnownGroup trusteeType = 5
)
// GrantVMGroupAccess sets the DACL for a specified file or directory to
// include Grant ACE entries for the VM Group SID. This is a golang re-
// implementation of the same function in vmcompute, just not exported in
// RS5. Which kind of sucks. Sucks a lot :/
func GrantVmGroupAccess(name string) error {
// Stat (to determine if `name` is a directory).
s, err := os.Stat(name)
if err != nil {
return errors.Wrapf(err, "%s os.Stat %s", gvmga, name)
}
// Get a handle to the file/directory. Must defer Close on success.
fd, err := createFile(name, s.IsDir())
if err != nil {
return err // Already wrapped
}
defer syscall.CloseHandle(fd)
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
ot := objectTypeFileObject
si := securityInformationDACL
sd := uintptr(0)
origDACL := uintptr(0)
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
return errors.Wrapf(err, "%s GetSecurityInfo %s", gvmga, name)
}
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
// Generate a new DACL which is the current DACL with the required ACEs added.
// Must defer LocalFree on success.
newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), origDACL)
if err != nil {
return err // Already wrapped
}
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
// And finally use SetSecurityInfo to apply the updated DACL.
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
return errors.Wrapf(err, "%s SetSecurityInfo %s", gvmga, name)
}
return nil
}
// createFile is a helper function to call [Nt]CreateFile to get a handle to
// the file or directory.
func createFile(name string, isDir bool) (syscall.Handle, error) {
namep := syscall.StringToUTF16(name)
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
sm := uint32(shareModeRead | shareModeWrite)
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
if isDir {
fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
}
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
if err != nil {
return 0, errors.Wrapf(err, "%s syscall.CreateFile %s", gvmga, name)
}
return fd, nil
}
// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
// The caller is responsible for LocalFree of the returned DACL on success.
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
// Generate pointers to the SIDs based on the string SIDs
sid, err := syscall.StringToSid(sidVmGroup)
if err != nil {
return 0, errors.Wrapf(err, "%s syscall.StringToSid %s %s", gvmga, name, sidVmGroup)
}
inheritance := inheritModeNoInheritance
if isDir {
inheritance = inheritModeSubContainersAndObjectsInherit
}
eaArray := []explicitAccess{
explicitAccess{
accessPermissions: accessMaskDesiredPermission,
accessMode: accessModeGrant,
inheritance: inheritance,
trustee: trustee{
trusteeForm: trusteeFormIsSid,
trusteeType: trusteeTypeWellKnownGroup,
name: uintptr(unsafe.Pointer(sid)),
},
},
}
modifiedDACL := uintptr(0)
if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
return 0, errors.Wrapf(err, "%s SetEntriesInAcl %s", gvmga, name)
}
return modifiedDACL, nil
}

View File

@@ -0,0 +1,7 @@
package security
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) [failretval!=0] = advapi32.SetSecurityInfo
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) [failretval!=0] = advapi32.SetEntriesInAclW

View File

@@ -0,0 +1,70 @@
// Code generated by 'go generate'; DO NOT EDIT.
package security
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
procSetSecurityInfo = modadvapi32.NewProc("SetSecurityInfo")
)
func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) {
r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
if r1 != 0 {
err = errnoErr(e1)
}
return
}
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
if r1 != 0 {
err = errnoErr(e1)
}
return
}
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) {
r1, _, e1 := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
if r1 != 0 {
err = errnoErr(e1)
}
return
}

View File

@@ -28,8 +28,9 @@ const (
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
SeSecurityPrivilege = "SeSecurityPrivilege"
)
const (

View File

@@ -1,3 +1,3 @@
package winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go

323
vendor/github.com/Microsoft/go-winio/vhd/vhd.go generated vendored Normal file
View File

@@ -0,0 +1,323 @@
// +build windows
package vhd
import (
"fmt"
"syscall"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
//go:generate go run mksyscall_windows.go -output zvhd_windows.go vhd.go
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath
type (
CreateVirtualDiskFlag uint32
VirtualDiskFlag uint32
AttachVirtualDiskFlag uint32
DetachVirtualDiskFlag uint32
VirtualDiskAccessMask uint32
)
type VirtualStorageType struct {
DeviceID uint32
VendorID guid.GUID
}
type CreateVersion2 struct {
UniqueID guid.GUID
MaximumSize uint64
BlockSizeInBytes uint32
SectorSizeInBytes uint32
PhysicalSectorSizeInByte uint32
ParentPath *uint16 // string
SourcePath *uint16 // string
OpenFlags uint32
ParentVirtualStorageType VirtualStorageType
SourceVirtualStorageType VirtualStorageType
ResiliencyGUID guid.GUID
}
type CreateVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 CreateVersion2
}
type OpenVersion2 struct {
GetInfoOnly bool
ReadOnly bool
ResiliencyGUID guid.GUID
}
type OpenVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 OpenVersion2
}
type AttachVersion2 struct {
RestrictedOffset uint64
RestrictedLength uint64
}
type AttachVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 AttachVersion2
}
const (
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
// Access Mask for opening a VHD
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
VirtualDiskAccessDetach VirtualDiskAccessMask = 0x00040000
VirtualDiskAccessGetInfo VirtualDiskAccessMask = 0x00080000
VirtualDiskAccessCreate VirtualDiskAccessMask = 0x00100000
VirtualDiskAccessMetaOps VirtualDiskAccessMask = 0x00200000
VirtualDiskAccessRead VirtualDiskAccessMask = 0x000d0000
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
// Flags for creating a VHD
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
CreateVirtualDiskFlagDoNotCopyMetadataFromParent CreateVirtualDiskFlag = 0x4
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
// Flags for opening a VHD
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x00000004
OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x00000008
OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x00000010
OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x00000020
OpenVirtualDiskFlagVhdsetFileOnly VirtualDiskFlag = 0x00000040
OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
// Flags for attaching a VHD
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
AttachVirtualDiskFlagPermanentLifetime AttachVirtualDiskFlag = 0x00000004
AttachVirtualDiskFlagNoLocalHost AttachVirtualDiskFlag = 0x00000008
AttachVirtualDiskFlagNoSecurityDescriptor AttachVirtualDiskFlag = 0x00000010
AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
AttachVirtualDiskFlagNonPnp AttachVirtualDiskFlag = 0x00000040
AttachVirtualDiskFlagRestrictedRange AttachVirtualDiskFlag = 0x00000080
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
// Flags for detaching a VHD
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
)
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
// default values.
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
params := CreateVirtualDiskParameters{
Version: 2,
Version2: CreateVersion2{
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
},
}
handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, &params)
if err != nil {
return err
}
if err := syscall.CloseHandle(handle); err != nil {
return err
}
return nil
}
// DetachVirtualDisk detaches a virtual hard disk by handle.
func DetachVirtualDisk(handle syscall.Handle) (err error) {
if err := detachVirtualDisk(handle, 0, 0); err != nil {
return errors.Wrap(err, "failed to detach virtual disk")
}
return nil
}
// DetachVhd detaches a vhd found at `path`.
func DetachVhd(path string) error {
handle, err := OpenVirtualDisk(
path,
VirtualDiskAccessNone,
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
)
if err != nil {
return err
}
defer syscall.CloseHandle(handle)
return DetachVirtualDisk(handle)
}
// AttachVirtualDisk attaches a virtual hard disk for use.
func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
if err := attachVirtualDisk(
handle,
nil,
uint32(attachVirtualDiskFlag),
0,
parameters,
nil,
); err != nil {
return errors.Wrap(err, "failed to attach virtual disk")
}
return nil
}
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
func AttachVhd(path string) (err error) {
handle, err := OpenVirtualDisk(
path,
VirtualDiskAccessNone,
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
)
if err != nil {
return err
}
defer syscall.CloseHandle(handle)
params := AttachVirtualDiskParameters{Version: 2}
if err := AttachVirtualDisk(
handle,
AttachVirtualDiskFlagNone,
&params,
); err != nil {
return errors.Wrap(err, "failed to attach virtual disk")
}
return nil
}
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
parameters := OpenVirtualDiskParameters{Version: 2}
handle, err := OpenVirtualDiskWithParameters(
vhdPath,
virtualDiskAccessMask,
openVirtualDiskFlags,
&parameters,
)
if err != nil {
return 0, err
}
return handle, nil
}
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
var (
handle syscall.Handle
defaultType VirtualStorageType
)
if parameters.Version != 2 {
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
}
if err := openVirtualDisk(
&defaultType,
vhdPath,
uint32(virtualDiskAccessMask),
uint32(openVirtualDiskFlags),
parameters,
&handle,
); err != nil {
return 0, errors.Wrap(err, "failed to open virtual disk")
}
return handle, nil
}
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
var (
handle syscall.Handle
defaultType VirtualStorageType
)
if parameters.Version != 2 {
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
}
if err := createVirtualDisk(
&defaultType,
path,
uint32(virtualDiskAccessMask),
nil,
uint32(createVirtualDiskFlags),
0,
parameters,
nil,
&handle,
); err != nil {
return handle, errors.Wrap(err, "failed to create virtual disk")
}
return handle, nil
}
// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
// that represents the particular enumeration of the physical disk on the caller's system.
func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
var (
diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
diskPhysicalPathBuf [256]uint16
)
if err := getVirtualDiskPhysicalPath(
handle,
&diskPathSizeInBytes,
&diskPhysicalPathBuf[0],
); err != nil {
return "", errors.Wrap(err, "failed to get disk physical path")
}
return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
}
// CreateDiffVhd is a helper function to create a differencing virtual disk.
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
// Setting `ParentPath` is how to signal to create a differencing disk.
createParams := &CreateVirtualDiskParameters{
Version: 2,
Version2: CreateVersion2{
ParentPath: windows.StringToUTF16Ptr(baseVhdPath),
BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
OpenFlags: uint32(OpenVirtualDiskFlagCachedIO),
},
}
vhdHandle, err := CreateVirtualDisk(
diffVhdPath,
VirtualDiskAccessNone,
CreateVirtualDiskFlagNone,
createParams,
)
if err != nil {
return fmt.Errorf("failed to create differencing vhd: %s", err)
}
if err := syscall.CloseHandle(vhdHandle); err != nil {
return fmt.Errorf("failed to close differencing vhd handle: %s", err)
}
return nil
}

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