Add a small helper to create the error directly from the http response
without having to set the struct fields at each caller.
Signed-off-by: Paul Holzinger <pholzing@redhat.com>
Some callers might like to make decisions based on the http server error
that was returned.
In particular we would like c/common/pkg/retry to match this error so it
can retry image pulls/pushes on 5XX errors as they seems to be a quite
common problem[1].
[1] https://github.com/containers/common/issues/2299
Signed-off-by: Paul Holzinger <pholzing@redhat.com>
in distribution v3, the registry/client package became internal. this
change drops usage of dockerChallenge.ResponseChallenges in favor of
parseAuthHeader directly, merging some of ResponseChallenges
functionality into handleErrorResponse (where it was being called).
Signed-off-by: Flavian Missi <fmissi@redhat.com>
If some code creates a slice with extra capacity, and
provides it to more than one user which calls append(),
those two users will write conflicting data to the same
backing array.
So, use append(slices.Clone(...), ...) whenever the origin
of the array backing a slice is unclear (or even in cases
where it can be traced but the code is a bit remote, making it
hard to maintain).
A demonstration of the problem:
> package main
>
> import (
> "fmt"
> "sync"
> "time"
> )
>
> func goroutine(wg *sync.WaitGroup, sharedSlice []int, i int) {
> defer wg.Done()
>
> privateSlice := append(sharedSlice, i)
> oldValue := privateSlice[len(privateSlice)-1]
> // This is already slow enough that the "full" value is frequently overwritten by another goroutine
> fmt.Printf("goroutine %d: immediate %d; full %#v@%v\n", i, oldValue, privateSlice, cap(privateSlice))
>
> time.Sleep(100 * time.Millisecond) // Give ample time for other goroutines to run
>
> newValue := privateSlice[len(privateSlice)-1]
> if newValue != i {
> panic(fmt.Sprintf("goroutine %d: immediate %d, after sleep %d; full %#v@%v", i, oldValue, newValue, privateSlice, cap(privateSlice)))
> }
> }
>
> func main() {
> sharedSlice := []int{0, 0, 0, 0}
> // Creates a backing array with extra capacity. (Alternatively, this could use the 3-argument version of make(),
> // but this demonstrates that this happens completely naturally just using append().)
> sharedSlice = append(sharedSlice, 0, 0)
> fmt.Printf("shared: %#v@%d\n", sharedSlice, cap(sharedSlice))
>
> wg := sync.WaitGroup{}
> for i := 0; i < 10; i++ {
> wg.Add(1)
> go goroutine(&wg, sharedSlice, i)
> }
> wg.Wait()
> }
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Using the github.com/docker/distribution/registry/client package will
import many huge prometheus dependencies, e.g.
* github.com/prometheus/client_golang/prometheus/promhttp
* github.com/prometheus/client_golang/prometheus
* github.com/prometheus/procfs
and even more...
All of these dependencies are completely unused AFAICT but will still end
up in a binary because they are imported transitive.
github.com/docker/distribution/registry/client is only used to check
http errors so I think it makes sense to copy only the required code
into the docker package.
I vendored this commit into podman and it saves over 700KB in binary
size.
Signed-off-by: Paul Holzinger <pholzing@redhat.com>