mirror of
https://github.com/containers/podman
synced 2024-10-19 16:54:07 +00:00
Add --accept-repositories
integration tests
This adds the integration tests for the repository or namespaced registry feature introduced in c/common. Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
This commit is contained in:
parent
a5de831418
commit
732ece6ae2
|
@ -52,6 +52,7 @@ func init() {
|
|||
loginOptions.Stdin = os.Stdin
|
||||
loginOptions.Stdout = os.Stdout
|
||||
loginOptions.AcceptUnspecifiedRegistry = true
|
||||
loginOptions.AcceptRepositories = true
|
||||
}
|
||||
|
||||
// Implementation of podman-login.
|
||||
|
|
|
@ -43,6 +43,7 @@ func init() {
|
|||
|
||||
logoutOptions.Stdout = os.Stdout
|
||||
logoutOptions.AcceptUnspecifiedRegistry = true
|
||||
logoutOptions.AcceptRepositories = true
|
||||
}
|
||||
|
||||
// Implementation of podman-logout.
|
||||
|
|
2
go.mod
2
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/containernetworking/cni v0.8.1
|
||||
github.com/containernetworking/plugins v0.9.1
|
||||
github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933
|
||||
github.com/containers/common v0.41.1-0.20210721172332-291287e9d060
|
||||
github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/image/v5 v5.14.0
|
||||
github.com/containers/ocicrypt v1.1.2
|
||||
|
|
4
go.sum
4
go.sum
|
@ -242,8 +242,8 @@ github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRD
|
|||
github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933 h1:jqO3hDypBoKM5be+fVcqGHOpX2fOiQy2DFEeb/VKpsk=
|
||||
github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933/go.mod h1:9gspFNeUJxIK72n1IMIKIHmtcePEZQsv0tjo+1LqkCo=
|
||||
github.com/containers/common v0.41.1-0.20210721112610-c95d2f794edf/go.mod h1:Ba5YVNCnyX6xDtg1JqEHa2EMVMW5UbHmIyEqsEwpeGE=
|
||||
github.com/containers/common v0.41.1-0.20210721172332-291287e9d060 h1:HgGff2MeEKfYoKp2WQFl9xdsgP7KV8rr/1JZRIuPXmg=
|
||||
github.com/containers/common v0.41.1-0.20210721172332-291287e9d060/go.mod h1:Ba5YVNCnyX6xDtg1JqEHa2EMVMW5UbHmIyEqsEwpeGE=
|
||||
github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3 h1:lHOZ+G5B7aP2YPsbDo4DtALFAuFG5PWH3Pv5zL2bC08=
|
||||
github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3/go.mod h1:UzAAjDsxwd4qkN1mgsk6aspduBY5bspxvKgwQElaBwk=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/image/v5 v5.13.2/go.mod h1:GkWursKDlDcUIT7L7vZf70tADvZCk/Ga0wgS0MuF0ag=
|
||||
|
|
|
@ -97,6 +97,24 @@ var _ = Describe("Podman login and logout", func() {
|
|||
os.RemoveAll(certDirPath)
|
||||
})
|
||||
|
||||
readAuthInfo := func(filePath string) map[string]interface{} {
|
||||
authBytes, err := ioutil.ReadFile(filePath)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
var authInfo map[string]interface{}
|
||||
err = json.Unmarshal(authBytes, &authInfo)
|
||||
Expect(err).To(BeNil())
|
||||
fmt.Println(authInfo)
|
||||
|
||||
const authsKey = "auths"
|
||||
Expect(authInfo).To(HaveKey(authsKey))
|
||||
|
||||
auths, ok := authInfo[authsKey].(map[string]interface{})
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
return auths
|
||||
}
|
||||
|
||||
It("podman login and logout", func() {
|
||||
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test", server})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
@ -151,10 +169,7 @@ var _ = Describe("Podman login and logout", func() {
|
|||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
authInfo, _ := ioutil.ReadFile(authFile)
|
||||
var info map[string]interface{}
|
||||
json.Unmarshal(authInfo, &info)
|
||||
fmt.Println(info)
|
||||
readAuthInfo(authFile)
|
||||
|
||||
// push should fail with nonexistent authfile
|
||||
session = podmanTest.Podman([]string{"push", "--authfile", "/tmp/nonexistent", ALPINE, testImg})
|
||||
|
@ -284,4 +299,204 @@ var _ = Describe("Podman login and logout", func() {
|
|||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).To(ExitWithError())
|
||||
})
|
||||
|
||||
It("podman login and logout with repository", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
|
||||
testRepository := server + "/podmantest"
|
||||
session := podmanTest.Podman([]string{
|
||||
"login",
|
||||
"-u", "podmantest",
|
||||
"-p", "test",
|
||||
"--authfile", authFile,
|
||||
testRepository,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
authInfo := readAuthInfo(authFile)
|
||||
Expect(authInfo).To(HaveKey(testRepository))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"logout",
|
||||
"--authfile", authFile,
|
||||
testRepository,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
authInfo = readAuthInfo(authFile)
|
||||
Expect(authInfo).NotTo(HaveKey(testRepository))
|
||||
})
|
||||
|
||||
It("podman login and logout with repository and specified image", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
|
||||
testTarget := server + "/podmantest/test-alpine"
|
||||
session := podmanTest.Podman([]string{
|
||||
"login",
|
||||
"-u", "podmantest",
|
||||
"-p", "test",
|
||||
"--authfile", authFile,
|
||||
testTarget,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
authInfo := readAuthInfo(authFile)
|
||||
Expect(authInfo).To(HaveKey(testTarget))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, testTarget,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
})
|
||||
|
||||
It("podman login and logout with repository with fallback", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
|
||||
testRepos := []string{
|
||||
server + "/podmantest",
|
||||
server,
|
||||
}
|
||||
for _, testRepo := range testRepos {
|
||||
session := podmanTest.Podman([]string{
|
||||
"login",
|
||||
"-u", "podmantest",
|
||||
"-p", "test",
|
||||
"--authfile", authFile,
|
||||
testRepo,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
}
|
||||
|
||||
authInfo := readAuthInfo(authFile)
|
||||
Expect(authInfo).To(HaveKey(testRepos[0]))
|
||||
Expect(authInfo).To(HaveKey(testRepos[1]))
|
||||
|
||||
session := podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, testRepos[0] + "/test-image-alpine",
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"logout",
|
||||
"--authfile", authFile,
|
||||
testRepos[0],
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, testRepos[0] + "/test-image-alpine",
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"logout",
|
||||
"--authfile", authFile,
|
||||
testRepos[1],
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
authInfo = readAuthInfo(authFile)
|
||||
Expect(authInfo).NotTo(HaveKey(testRepos[0]))
|
||||
Expect(authInfo).NotTo(HaveKey(testRepos[1]))
|
||||
})
|
||||
|
||||
It("podman login with repository invalid arguments", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
|
||||
for _, invalidArg := range []string{
|
||||
"https://" + server + "/podmantest",
|
||||
server + "/podmantest/image:latest",
|
||||
} {
|
||||
session := podmanTest.Podman([]string{
|
||||
"login",
|
||||
"-u", "podmantest",
|
||||
"-p", "test",
|
||||
"--authfile", authFile,
|
||||
invalidArg,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitWithError())
|
||||
}
|
||||
})
|
||||
|
||||
It("podman login and logout with repository push with invalid auth.json credentials", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
// only `server` contains the correct login data
|
||||
err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
|
||||
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
|
||||
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
|
||||
}}`, server, server)), 0644)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
session := podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, server + "/podmantest/test-image",
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).To(ExitWithError())
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, server + "/test-image",
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).To(Exit(0))
|
||||
})
|
||||
|
||||
It("podman login and logout with repository pull with wrong auth.json credentials", func() {
|
||||
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
|
||||
|
||||
testTarget := server + "/podmantest/test-alpine"
|
||||
session := podmanTest.Podman([]string{
|
||||
"login",
|
||||
"-u", "podmantest",
|
||||
"-p", "test",
|
||||
"--authfile", authFile,
|
||||
testTarget,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"push",
|
||||
"--authfile", authFile,
|
||||
ALPINE, testTarget,
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
// only `server + /podmantest` and `server` have the correct login data
|
||||
err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
|
||||
"%s/podmantest/test-alpine": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
|
||||
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp0ZXN0" },
|
||||
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
|
||||
}}`, server, server, server)), 0644)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
session = podmanTest.Podman([]string{
|
||||
"pull",
|
||||
"--authfile", authFile,
|
||||
server + "/podmantest/test-alpine",
|
||||
})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).To(ExitWithError())
|
||||
})
|
||||
})
|
||||
|
|
12
vendor/github.com/containers/common/libimage/copier.go
generated
vendored
12
vendor/github.com/containers/common/libimage/copier.go
generated
vendored
|
@ -342,7 +342,7 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
|
|||
}
|
||||
}
|
||||
|
||||
var copiedManifest []byte
|
||||
var returnManifest []byte
|
||||
f := func() error {
|
||||
opts := c.imageCopyOptions
|
||||
if sourceInsecure != nil {
|
||||
|
@ -354,11 +354,13 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
|
|||
opts.DestinationCtx.DockerInsecureSkipTLSVerify = value
|
||||
}
|
||||
|
||||
var err error
|
||||
copiedManifest, err = copy.Image(ctx, c.policyContext, destination, source, &opts)
|
||||
copiedManifest, err := copy.Image(ctx, c.policyContext, destination, source, &opts)
|
||||
if err == nil {
|
||||
returnManifest = copiedManifest
|
||||
}
|
||||
return err
|
||||
}
|
||||
return copiedManifest, retry.RetryIfNecessary(ctx, f, &c.retryOptions)
|
||||
return returnManifest, retry.RetryIfNecessary(ctx, f, &c.retryOptions)
|
||||
}
|
||||
|
||||
// checkRegistrySourcesAllows checks the $BUILD_REGISTRY_SOURCES environment
|
||||
|
@ -369,7 +371,7 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
|
|||
// If set, the insecure return value indicates whether the registry is set to
|
||||
// be insecure.
|
||||
//
|
||||
// NOTE: this functionality is required by Buildah.
|
||||
// NOTE: this functionality is required by Buildah for OpenShift.
|
||||
func checkRegistrySourcesAllows(dest types.ImageReference) (insecure *bool, err error) {
|
||||
registrySources, ok := os.LookupEnv("BUILD_REGISTRY_SOURCES")
|
||||
if !ok || registrySources == "" {
|
||||
|
|
8
vendor/github.com/containers/common/libimage/image.go
generated
vendored
8
vendor/github.com/containers/common/libimage/image.go
generated
vendored
|
@ -836,9 +836,9 @@ func (i *Image) Manifest(ctx context.Context) (rawManifest []byte, mimeType stri
|
|||
return src.GetManifest(ctx, nil)
|
||||
}
|
||||
|
||||
// getImageDigest creates an image object and uses the hex value of the digest as the image ID
|
||||
// for parsing the store reference
|
||||
func getImageDigest(ctx context.Context, src types.ImageReference, sys *types.SystemContext) (string, error) {
|
||||
// getImageID creates an image object and uses the hex value of the config
|
||||
// blob's digest (if it has one) as the image ID for parsing the store reference
|
||||
func getImageID(ctx context.Context, src types.ImageReference, sys *types.SystemContext) (string, error) {
|
||||
newImg, err := src.NewImage(ctx, sys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -852,5 +852,5 @@ func getImageDigest(ctx context.Context, src types.ImageReference, sys *types.Sy
|
|||
if err = imageDigest.Validate(); err != nil {
|
||||
return "", errors.Wrapf(err, "error getting config info")
|
||||
}
|
||||
return "@" + imageDigest.Hex(), nil
|
||||
return "@" + imageDigest.Encoded(), nil
|
||||
}
|
||||
|
|
2
vendor/github.com/containers/common/libimage/import.go
generated
vendored
2
vendor/github.com/containers/common/libimage/import.go
generated
vendored
|
@ -86,7 +86,7 @@ func (r *Runtime) Import(ctx context.Context, path string, options *ImportOption
|
|||
return "", err
|
||||
}
|
||||
|
||||
id, err := getImageDigest(ctx, srcRef, r.systemContextCopy())
|
||||
id, err := getImageID(ctx, srcRef, r.systemContextCopy())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
18
vendor/github.com/containers/common/libimage/manifests/manifests.go
generated
vendored
18
vendor/github.com/containers/common/libimage/manifests/manifests.go
generated
vendored
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/lockfile"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -395,3 +396,20 @@ func (l *list) Remove(instanceDigest digest.Digest) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// LockerForImage returns a Locker for a given image record. It's recommended
|
||||
// that processes which use LoadFromImage() to load a list from an image and
|
||||
// then use that list's SaveToImage() method to save a modified version of the
|
||||
// list to that image record use this lock to avoid accidentally wiping out
|
||||
// changes that another process is also attempting to make.
|
||||
func LockerForImage(store storage.Store, image string) (lockfile.Locker, error) {
|
||||
img, err := store.Image(image)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "locating image %q for locating lock", image)
|
||||
}
|
||||
d := digest.NewDigestFromEncoded(digest.Canonical, img.ID)
|
||||
if err := d.Validate(); err != nil {
|
||||
return nil, errors.Wrapf(err, "coercing image ID for %q into a digest", image)
|
||||
}
|
||||
return store.GetDigestLock(d)
|
||||
}
|
||||
|
|
80
vendor/github.com/containers/common/libimage/pull.go
generated
vendored
80
vendor/github.com/containers/common/libimage/pull.go
generated
vendored
|
@ -12,6 +12,7 @@ import (
|
|||
dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
|
||||
dockerDaemonTransport "github.com/containers/image/v5/docker/daemon"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
ociArchiveTransport "github.com/containers/image/v5/oci/archive"
|
||||
ociTransport "github.com/containers/image/v5/oci/layout"
|
||||
"github.com/containers/image/v5/pkg/shortnames"
|
||||
|
@ -19,6 +20,7 @@ import (
|
|||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/storage"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -192,19 +194,19 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
imageName = storageName
|
||||
|
||||
case ociArchiveTransport.Transport.Name():
|
||||
manifest, err := ociArchiveTransport.LoadManifestDescriptor(ref)
|
||||
manifestDescriptor, err := ociArchiveTransport.LoadManifestDescriptor(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if index.json has no reference name, compute the image digest instead
|
||||
if manifest.Annotations == nil || manifest.Annotations["org.opencontainers.image.ref.name"] == "" {
|
||||
storageName, err = getImageDigest(ctx, ref, nil)
|
||||
// if index.json has no reference name, compute the image ID instead
|
||||
if manifestDescriptor.Annotations == nil || manifestDescriptor.Annotations["org.opencontainers.image.ref.name"] == "" {
|
||||
storageName, err = getImageID(ctx, ref, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageName = "sha256:" + storageName[1:]
|
||||
} else {
|
||||
storageName = manifest.Annotations["org.opencontainers.image.ref.name"]
|
||||
storageName = manifestDescriptor.Annotations["org.opencontainers.image.ref.name"]
|
||||
named, err := NormalizeName(storageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -248,7 +250,7 @@ func (r *Runtime) storageReferencesReferencesFromArchiveReader(ctx context.Conte
|
|||
|
||||
var imageNames []string
|
||||
if len(destNames) == 0 {
|
||||
destName, err := getImageDigest(ctx, readerRef, &r.systemContext)
|
||||
destName, err := getImageID(ctx, readerRef, &r.systemContext)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -316,8 +318,8 @@ func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, read
|
|||
}
|
||||
|
||||
// copyFromRegistry pulls the specified, possibly unqualified, name from a
|
||||
// registry. On successful pull it returns the used fully-qualified name that
|
||||
// can later be used to look up the image in the local containers storage.
|
||||
// registry. On successful pull it returns the ID of the image in local
|
||||
// storage.
|
||||
//
|
||||
// If options.All is set, all tags from the specified registry will be pulled.
|
||||
func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) {
|
||||
|
@ -337,7 +339,7 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pulledTags := []string{}
|
||||
pulledIDs := []string{}
|
||||
for _, tag := range tags {
|
||||
select { // Let's be gentle with Podman remote.
|
||||
case <-ctx.Done():
|
||||
|
@ -353,15 +355,54 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pulledTags = append(pulledTags, pulled...)
|
||||
pulledIDs = append(pulledIDs, pulled...)
|
||||
}
|
||||
|
||||
return pulledTags, nil
|
||||
return pulledIDs, nil
|
||||
}
|
||||
|
||||
// imageIDsForManifest() parses the manifest of the copied image and then looks
|
||||
// up the IDs of the matching image. There's a small slice of time, between
|
||||
// when we copy the image into local storage and when we go to look for it
|
||||
// using the name that we gave it when we copied it, when the name we wanted to
|
||||
// assign to the image could have been moved, but the image's ID will remain
|
||||
// the same until it is deleted.
|
||||
func (r *Runtime) imagesIDsForManifest(manifestBytes []byte, sys *types.SystemContext) ([]string, error) {
|
||||
var imageDigest digest.Digest
|
||||
manifestType := manifest.GuessMIMEType(manifestBytes)
|
||||
if manifest.MIMETypeIsMultiImage(manifestType) {
|
||||
list, err := manifest.ListFromBlob(manifestBytes, manifestType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing manifest list")
|
||||
}
|
||||
d, err := list.ChooseInstance(sys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "choosing instance from manifest list")
|
||||
}
|
||||
imageDigest = d
|
||||
} else {
|
||||
d, err := manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "digesting manifest")
|
||||
}
|
||||
imageDigest = d
|
||||
}
|
||||
var results []string
|
||||
images, err := r.store.ImagesByDigest(imageDigest)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "listing images by manifest digest")
|
||||
}
|
||||
for _, image := range images {
|
||||
results = append(results, image.ID)
|
||||
}
|
||||
if len(results) == 0 {
|
||||
return nil, errors.Wrapf(storage.ErrImageUnknown, "identifying new image by manifest digest")
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// copySingleImageFromRegistry pulls the specified, possibly unqualified, name
|
||||
// from a registry. On successful pull it returns the used fully-qualified
|
||||
// name that can later be used to look up the image in the local containers
|
||||
// from a registry. On successful pull it returns the ID of the image in local
|
||||
// storage.
|
||||
func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) { //nolint:gocyclo
|
||||
// Sanity check.
|
||||
|
@ -375,7 +416,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
err error
|
||||
)
|
||||
|
||||
// Always check if there's a local image. If, we should use it's
|
||||
// Always check if there's a local image. If so, we should use its
|
||||
// resolved name for pulling. Assume we're doing a `pull foo`.
|
||||
// If there's already a local image "localhost/foo", then we should
|
||||
// attempt pulling that instead of doing the full short-name dance.
|
||||
|
@ -454,7 +495,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
}
|
||||
}
|
||||
|
||||
// If we found a local image, we should use it's locally resolved name
|
||||
// If we found a local image, we should use its locally resolved name
|
||||
// (see containers/buildah/issues/2904). An exception is if a custom
|
||||
// platform is specified (e.g., `--arch=arm64`). In that case, we need
|
||||
// to pessimistically pull the image since some images declare wrong
|
||||
|
@ -462,7 +503,8 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
// containers/podman/issues/10682).
|
||||
//
|
||||
// In other words: multi-arch support can only be as good as the images
|
||||
// in the wild.
|
||||
// in the wild, so we shouldn't break things for our users by trying to
|
||||
// insist that they make sense.
|
||||
if localImage != nil && !customPlatform {
|
||||
if imageName != resolvedImageName {
|
||||
logrus.Debugf("Image %s resolved to local image %s which will be used for pulling", imageName, resolvedImageName)
|
||||
|
@ -541,7 +583,8 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
if _, err := c.copy(ctx, srcRef, destRef); err != nil {
|
||||
var manifestBytes []byte
|
||||
if manifestBytes, err = c.copy(ctx, srcRef, destRef); err != nil {
|
||||
logrus.Debugf("Error pulling candidate %s: %v", candidateString, err)
|
||||
pullErrors = append(pullErrors, err)
|
||||
continue
|
||||
|
@ -554,6 +597,9 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
}
|
||||
|
||||
logrus.Debugf("Pulled candidate %s successfully", candidateString)
|
||||
if ids, err := r.imagesIDsForManifest(manifestBytes, sys); err == nil {
|
||||
return ids, nil
|
||||
}
|
||||
return []string{candidate.Value.String()}, nil
|
||||
}
|
||||
|
||||
|
|
4
vendor/github.com/containers/common/libimage/search.go
generated
vendored
4
vendor/github.com/containers/common/libimage/search.go
generated
vendored
|
@ -185,6 +185,10 @@ func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry stri
|
|||
sys.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
|
||||
}
|
||||
|
||||
if options.Authfile != "" {
|
||||
sys.AuthFilePath = options.Authfile
|
||||
}
|
||||
|
||||
if options.ListTags {
|
||||
results, err := searchRepositoryTags(ctx, sys, registry, term, options)
|
||||
if err != nil {
|
||||
|
|
153
vendor/github.com/containers/common/pkg/auth/auth.go
generated
vendored
153
vendor/github.com/containers/common/pkg/auth/auth.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/pkg/docker/config"
|
||||
"github.com/containers/image/v5/pkg/sysregistriesv2"
|
||||
"github.com/containers/image/v5/types"
|
||||
|
@ -69,30 +70,50 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
|
|||
systemContext = systemContextWithOptions(systemContext, opts.AuthFile, opts.CertDir)
|
||||
|
||||
var (
|
||||
server string
|
||||
err error
|
||||
authConfig types.DockerAuthConfig
|
||||
key, registry string
|
||||
ref reference.Named
|
||||
err error
|
||||
)
|
||||
if len(args) > 1 {
|
||||
return errors.New("login accepts only one registry to login to")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
l := len(args)
|
||||
switch l {
|
||||
case 0:
|
||||
if !opts.AcceptUnspecifiedRegistry {
|
||||
return errors.New("please provide a registry to login to")
|
||||
}
|
||||
if server, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
|
||||
if key, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server)
|
||||
registry = key
|
||||
logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", key)
|
||||
|
||||
case 1:
|
||||
key, registry, ref, err = parseRegistryArgument(args[0], opts.AcceptRepositories)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.New("login accepts only one registry to login to")
|
||||
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
authConfig, err = config.GetCredentialsForRef(systemContext, ref)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get credentials for repository")
|
||||
}
|
||||
} else {
|
||||
server = getRegistryName(args[0])
|
||||
}
|
||||
authConfig, err := config.GetCredentials(systemContext, server)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "reading auth file")
|
||||
// nolint: staticcheck
|
||||
authConfig, err = config.GetCredentials(systemContext, registry)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get credentials")
|
||||
}
|
||||
}
|
||||
|
||||
if opts.GetLoginSet {
|
||||
if authConfig.Username == "" {
|
||||
return errors.Errorf("not logged into %s", server)
|
||||
return errors.Errorf("not logged into %s", key)
|
||||
}
|
||||
fmt.Fprintf(opts.Stdout, "%s\n", authConfig.Username)
|
||||
return nil
|
||||
|
@ -119,9 +140,9 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
|
|||
|
||||
// If no username and no password is specified, try to use existing ones.
|
||||
if opts.Username == "" && password == "" && authConfig.Username != "" && authConfig.Password != "" {
|
||||
fmt.Println("Authenticating with existing credentials...")
|
||||
if err := docker.CheckAuth(ctx, systemContext, authConfig.Username, authConfig.Password, server); err == nil {
|
||||
fmt.Fprintln(opts.Stdout, "Existing credentials are valid. Already logged in to", server)
|
||||
fmt.Fprintf(opts.Stdout, "Authenticating with existing credentials for %s\n", key)
|
||||
if err := docker.CheckAuth(ctx, systemContext, authConfig.Username, authConfig.Password, registry); err == nil {
|
||||
fmt.Fprintf(opts.Stdout, "Existing credentials are valid. Already logged in to %s\n", registry)
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintln(opts.Stdout, "Existing credentials are invalid, please enter valid username and password")
|
||||
|
@ -132,9 +153,9 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
|
|||
return errors.Wrap(err, "getting username and password")
|
||||
}
|
||||
|
||||
if err = docker.CheckAuth(ctx, systemContext, username, password, server); err == nil {
|
||||
if err = docker.CheckAuth(ctx, systemContext, username, password, registry); err == nil {
|
||||
// Write the new credentials to the authfile
|
||||
desc, err := config.SetCredentials(systemContext, server, username, password)
|
||||
desc, err := config.SetCredentials(systemContext, key, username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -147,10 +168,45 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
|
|||
return nil
|
||||
}
|
||||
if unauthorized, ok := err.(docker.ErrUnauthorizedForCredentials); ok {
|
||||
logrus.Debugf("error logging into %q: %v", server, unauthorized)
|
||||
return errors.Errorf("error logging into %q: invalid username/password", server)
|
||||
logrus.Debugf("error logging into %q: %v", key, unauthorized)
|
||||
return errors.Errorf("error logging into %q: invalid username/password", key)
|
||||
}
|
||||
return errors.Wrapf(err, "authenticating creds for %q", server)
|
||||
return errors.Wrapf(err, "authenticating creds for %q", key)
|
||||
}
|
||||
|
||||
// parseRegistryArgument verifies the provided arg depending if we accept
|
||||
// repositories or not.
|
||||
func parseRegistryArgument(arg string, acceptRepositories bool) (key, registry string, maybeRef reference.Named, err error) {
|
||||
if !acceptRepositories {
|
||||
registry = getRegistryName(arg)
|
||||
key = registry
|
||||
return key, registry, maybeRef, nil
|
||||
}
|
||||
|
||||
key = trimScheme(arg)
|
||||
if key != arg {
|
||||
return key, registry, nil, errors.New("credentials key has https[s]:// prefix")
|
||||
}
|
||||
|
||||
registry = getRegistryName(key)
|
||||
if registry == key {
|
||||
// We cannot parse a reference from a registry, so we stop here
|
||||
return key, registry, nil, nil
|
||||
}
|
||||
|
||||
ref, parseErr := reference.ParseNamed(key)
|
||||
if parseErr != nil {
|
||||
return key, registry, nil, errors.Wrapf(parseErr, "parse reference from %q", key)
|
||||
}
|
||||
|
||||
if !reference.IsNameOnly(ref) {
|
||||
return key, registry, nil, errors.Errorf("reference %q contains tag or digest", ref.String())
|
||||
}
|
||||
|
||||
maybeRef = ref
|
||||
registry = reference.Domain(ref)
|
||||
|
||||
return key, registry, maybeRef, nil
|
||||
}
|
||||
|
||||
// getRegistryName scrubs and parses the input to get the server name
|
||||
|
@ -158,13 +214,21 @@ func getRegistryName(server string) string {
|
|||
// removes 'http://' or 'https://' from the front of the
|
||||
// server/registry string if either is there. This will be mostly used
|
||||
// for user input from 'Buildah login' and 'Buildah logout'.
|
||||
server = strings.TrimPrefix(strings.TrimPrefix(server, "https://"), "http://")
|
||||
server = trimScheme(server)
|
||||
// gets the registry from the input. If the input is of the form
|
||||
// quay.io/myuser/myimage, it will parse it and just return quay.io
|
||||
split := strings.Split(server, "/")
|
||||
return split[0]
|
||||
}
|
||||
|
||||
// trimScheme removes the HTTP(s) scheme from the provided repository.
|
||||
func trimScheme(repository string) string {
|
||||
// removes 'http://' or 'https://' from the front of the
|
||||
// server/registry string if either is there. This will be mostly used
|
||||
// for user input from 'Buildah login' and 'Buildah logout'.
|
||||
return strings.TrimPrefix(strings.TrimPrefix(repository, "https://"), "http://")
|
||||
}
|
||||
|
||||
// getUserAndPass gets the username and password from STDIN if not given
|
||||
// using the -u and -p flags. If the username prompt is left empty, the
|
||||
// displayed userFromAuthFile will be used instead.
|
||||
|
@ -209,8 +273,9 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
|
|||
systemContext = systemContextWithOptions(systemContext, opts.AuthFile, "")
|
||||
|
||||
var (
|
||||
server string
|
||||
err error
|
||||
key, registry string
|
||||
ref reference.Named
|
||||
err error
|
||||
)
|
||||
if len(args) > 1 {
|
||||
return errors.New("logout accepts only one registry to logout from")
|
||||
|
@ -219,16 +284,20 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
|
|||
if !opts.AcceptUnspecifiedRegistry {
|
||||
return errors.New("please provide a registry to logout from")
|
||||
}
|
||||
if server, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
|
||||
if key, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server)
|
||||
registry = key
|
||||
logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", key)
|
||||
}
|
||||
if len(args) != 0 {
|
||||
if opts.All {
|
||||
return errors.New("--all takes no arguments")
|
||||
}
|
||||
server = getRegistryName(args[0])
|
||||
key, registry, ref, err = parseRegistryArgument(args[0], opts.AcceptRepositories)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if opts.All {
|
||||
|
@ -239,24 +308,34 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
|
|||
return nil
|
||||
}
|
||||
|
||||
err = config.RemoveAuthentication(systemContext, server)
|
||||
err = config.RemoveAuthentication(systemContext, key)
|
||||
switch errors.Cause(err) {
|
||||
case nil:
|
||||
fmt.Fprintf(opts.Stdout, "Removed login credentials for %s\n", server)
|
||||
fmt.Fprintf(opts.Stdout, "Removed login credentials for %s\n", key)
|
||||
return nil
|
||||
case config.ErrNotLoggedIn:
|
||||
authConfig, err := config.GetCredentials(systemContext, server)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "reading auth file")
|
||||
var authConfig types.DockerAuthConfig
|
||||
if ref != nil {
|
||||
authConfig, err = config.GetCredentialsForRef(systemContext, ref)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get credentials for repository")
|
||||
}
|
||||
} else {
|
||||
// nolint: staticcheck
|
||||
authConfig, err = config.GetCredentials(systemContext, registry)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get credentials")
|
||||
}
|
||||
}
|
||||
authInvalid := docker.CheckAuth(context.Background(), systemContext, authConfig.Username, authConfig.Password, server)
|
||||
|
||||
authInvalid := docker.CheckAuth(context.Background(), systemContext, authConfig.Username, authConfig.Password, registry)
|
||||
if authConfig.Username != "" && authConfig.Password != "" && authInvalid == nil {
|
||||
fmt.Printf("Not logged into %s with current tool. Existing credentials were established via docker login. Please use docker logout instead.\n", server)
|
||||
fmt.Printf("Not logged into %s with current tool. Existing credentials were established via docker login. Please use docker logout instead.\n", key)
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("Not logged into %s\n", server)
|
||||
return errors.Errorf("Not logged into %s\n", key)
|
||||
default:
|
||||
return errors.Wrapf(err, "logging out of %q", server)
|
||||
return errors.Wrapf(err, "logging out of %q", key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
20
vendor/github.com/containers/common/pkg/auth/cli.go
generated
vendored
20
vendor/github.com/containers/common/pkg/auth/cli.go
generated
vendored
|
@ -14,13 +14,14 @@ type LoginOptions struct {
|
|||
// CLI flags managed by the FlagSet returned by GetLoginFlags
|
||||
// Callers that use GetLoginFlags should not need to touch these values at all; callers that use
|
||||
// other CLI frameworks should set them based on user input.
|
||||
AuthFile string
|
||||
CertDir string
|
||||
Password string
|
||||
Username string
|
||||
StdinPassword bool
|
||||
GetLoginSet bool
|
||||
Verbose bool // set to true for verbose output
|
||||
AuthFile string
|
||||
CertDir string
|
||||
Password string
|
||||
Username string
|
||||
StdinPassword bool
|
||||
GetLoginSet bool
|
||||
Verbose bool // set to true for verbose output
|
||||
AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries
|
||||
// Options caller can set
|
||||
Stdin io.Reader // set to os.Stdin
|
||||
Stdout io.Writer // set to os.Stdout
|
||||
|
@ -32,8 +33,9 @@ type LogoutOptions struct {
|
|||
// CLI flags managed by the FlagSet returned by GetLogoutFlags
|
||||
// Callers that use GetLogoutFlags should not need to touch these values at all; callers that use
|
||||
// other CLI frameworks should set them based on user input.
|
||||
AuthFile string
|
||||
All bool
|
||||
AuthFile string
|
||||
All bool
|
||||
AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries
|
||||
// Options caller can set
|
||||
Stdout io.Writer // set to os.Stdout
|
||||
AcceptUnspecifiedRegistry bool // set to true if allows logout with unspecified registry
|
||||
|
|
11
vendor/github.com/containers/common/pkg/config/config.go
generated
vendored
11
vendor/github.com/containers/common/pkg/config/config.go
generated
vendored
|
@ -637,9 +637,14 @@ func (c *Config) CheckCgroupsAndAdjustConfig() {
|
|||
|
||||
session := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
|
||||
hasSession := session != ""
|
||||
if hasSession && strings.HasPrefix(session, "unix:path=") {
|
||||
_, err := os.Stat(strings.TrimPrefix(session, "unix:path="))
|
||||
hasSession = err == nil
|
||||
if hasSession {
|
||||
for _, part := range strings.Split(session, ",") {
|
||||
if strings.HasPrefix(part, "unix:path=") {
|
||||
_, err := os.Stat(strings.TrimPrefix(part, "unix:path="))
|
||||
hasSession = err == nil
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hasSession && unshare.GetRootlessUID() != 0 {
|
||||
|
|
8
vendor/github.com/containers/common/pkg/config/pull_policy.go
generated
vendored
8
vendor/github.com/containers/common/pkg/config/pull_policy.go
generated
vendored
|
@ -76,13 +76,13 @@ func (p PullPolicy) Validate() error {
|
|||
// * "never" <-> PullPolicyNever
|
||||
func ParsePullPolicy(s string) (PullPolicy, error) {
|
||||
switch s {
|
||||
case "always":
|
||||
case "always", "Always":
|
||||
return PullPolicyAlways, nil
|
||||
case "missing", "ifnotpresent", "":
|
||||
case "missing", "Missing", "ifnotpresent", "IfNotPresent", "":
|
||||
return PullPolicyMissing, nil
|
||||
case "newer", "ifnewer":
|
||||
case "newer", "Newer", "ifnewer", "IfNewer":
|
||||
return PullPolicyNewer, nil
|
||||
case "never":
|
||||
case "never", "Never":
|
||||
return PullPolicyNever, nil
|
||||
default:
|
||||
return PullPolicyUnsupported, errors.Errorf("unsupported pull policy %q", s)
|
||||
|
|
2
vendor/github.com/containers/common/pkg/seccomp/types.go
generated
vendored
2
vendor/github.com/containers/common/pkg/seccomp/types.go
generated
vendored
|
@ -7,7 +7,7 @@ package seccomp
|
|||
// Seccomp represents the config for a seccomp profile for syscall restriction.
|
||||
type Seccomp struct {
|
||||
DefaultAction Action `json:"defaultAction"`
|
||||
DefaultErrnoRet *uint `json:"defaultErrnoRet"`
|
||||
DefaultErrnoRet *uint `json:"defaultErrnoRet,omitempty"`
|
||||
// Architectures is kept to maintain backward compatibility with the old
|
||||
// seccomp profile.
|
||||
Architectures []Arch `json:"architectures,omitempty"`
|
||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -93,7 +93,7 @@ github.com/containers/buildah/pkg/overlay
|
|||
github.com/containers/buildah/pkg/parse
|
||||
github.com/containers/buildah/pkg/rusage
|
||||
github.com/containers/buildah/util
|
||||
# github.com/containers/common v0.41.1-0.20210721172332-291287e9d060
|
||||
# github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3
|
||||
github.com/containers/common/libimage
|
||||
github.com/containers/common/libimage/manifests
|
||||
github.com/containers/common/pkg/apparmor
|
||||
|
|
Loading…
Reference in a new issue