package server import ( "context" "fmt" "net/http" "net/http/httptest" "strings" "time" "github.com/distribution/distribution/v3/configuration" "github.com/distribution/distribution/v3/registry" "github.com/distribution/distribution/v3/registry/handlers" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) func NewRegistry(ctx context.Context, cfg *configuration.Configuration) (*registry.Registry, error) { r, err := registry.NewRegistry(ctx, cfg) if err != nil { return nil, err } return r, nil } type tmpRegistryServer struct { *httptest.Server } func NewTempRegistry(ctx context.Context, root string) *tmpRegistryServer { cfg := &configuration.Configuration{ Version: "0.1", Storage: configuration.Storage{ "cache": configuration.Parameters{"blobdescriptor": "inmemory"}, "filesystem": configuration.Parameters{"rootdirectory": root}, }, } cfg.Validation.Manifests.URLs.Allow = []string{".+"} cfg.Log.Level = "error" cfg.HTTP.Headers = http.Header{ "X-Content-Type-Options": []string{"nosniff"}, } l, err := logrus.ParseLevel("panic") if err != nil { l = logrus.ErrorLevel } logrus.SetLevel(l) app := handlers.NewApp(ctx, cfg) app.RegisterHealthChecks() handler := alive("/", app) s := httptest.NewUnstartedServer(handler) return &tmpRegistryServer{ Server: s, } } // Registry returns the URL of the server without the protocol, suitable for content references func (t *tmpRegistryServer) Registry() string { return strings.Replace(t.Server.URL, "http://", "", 1) } func (t *tmpRegistryServer) Start() error { t.Server.Start() err := retry(5, 1*time.Second, func() (err error) { resp, err := http.Get(t.Server.URL + "/v2") if err != nil { return err } resp.Body.Close() if resp.StatusCode == http.StatusOK { return nil } return errors.New("to start temporary registry") }) return err } func (t *tmpRegistryServer) Stop() { t.Server.Close() } func alive(path string, handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == path { w.Header().Set("Cache-Control", "no-cache") w.WriteHeader(http.StatusOK) return } handler.ServeHTTP(w, r) }) } func retry(attempts int, sleep time.Duration, f func() error) (err error) { for i := 0; i < attempts; i++ { if i > 0 { time.Sleep(sleep) sleep *= 2 } err = f() if err == nil { return nil } } return fmt.Errorf("after %d attempts, last error: %s", attempts, err) }