diff --git a/health/api/api.go b/health/api/api.go index d7d62a28..f70fec29 100644 --- a/health/api/api.go +++ b/health/api/api.go @@ -9,6 +9,13 @@ import ( var updater = health.NewStatusUpdater() +// init sets up the two endpoints to bring the service up and down +func init() { + health.Register("manual_http_status", updater) + http.HandleFunc("/debug/health/down", DownHandler) + http.HandleFunc("/debug/health/up", UpHandler) +} + // DownHandler registers a manual_http_status that always returns an Error func DownHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { @@ -26,10 +33,3 @@ func UpHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) } } - -// init sets up the two endpoints to bring the service up and down -func init() { - health.Register("manual_http_status", updater) - http.HandleFunc("/debug/health/down", DownHandler) - http.HandleFunc("/debug/health/up", UpHandler) -} diff --git a/health/health.go b/health/health.go index fff87323..aefd8655 100644 --- a/health/health.go +++ b/health/health.go @@ -13,6 +13,12 @@ import ( "github.com/distribution/distribution/v3/registry/api/errcode" ) +// Registers global /debug/health api endpoint, creates default registry +func init() { + DefaultRegistry = NewRegistry() + http.HandleFunc("/debug/health", StatusHandler) +} + // A Registry is a collection of checks. Most applications will use the global // registry defined in DefaultRegistry. However, unit tests may need to create // separate registries to isolate themselves from other tests. @@ -278,9 +284,3 @@ func statusResponse(w http.ResponseWriter, r *http.Request, status int, checks m dcontext.GetLogger(r.Context()).Errorf("error writing health status response body: %v", err) } } - -// Registers global /debug/health api endpoint, creates default registry -func init() { - DefaultRegistry = NewRegistry() - http.HandleFunc("/debug/health", StatusHandler) -} diff --git a/internal/client/auth/challenge/authchallenge.go b/internal/client/auth/challenge/authchallenge.go index 3dae9538..34684dd5 100644 --- a/internal/client/auth/challenge/authchallenge.go +++ b/internal/client/auth/challenge/authchallenge.go @@ -8,6 +8,48 @@ import ( "sync" ) +// Octet types from RFC 2616. +type octetType byte + +var octetTypes [256]octetType + +const ( + isToken octetType = 1 << iota + isSpace +) + +func init() { + // OCTET = + // CHAR = + // CTL = + // CR = + // LF = + // SP = + // HT = + // <"> = + // CRLF = CR LF + // LWS = [CRLF] 1*( SP | HT ) + // TEXT = + // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> + // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT + // token = 1* + // qdtext = > + + for c := 0; c < 256; c++ { + var t octetType + isCtl := c <= 31 || c == 127 + isChar := 0 <= c && c <= 127 + isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) + if strings.ContainsRune(" \t\r\n", rune(c)) { + t |= isSpace + } + if isChar && !isCtl && !isSeparator { + t |= isToken + } + octetTypes[c] = t + } +} + // Challenge carries information from a WWW-Authenticate response header. // See RFC 2617. type Challenge struct { @@ -86,48 +128,6 @@ func (m *simpleManager) AddResponse(resp *http.Response) error { return nil } -// Octet types from RFC 2616. -type octetType byte - -var octetTypes [256]octetType - -const ( - isToken octetType = 1 << iota - isSpace -) - -func init() { - // OCTET = - // CHAR = - // CTL = - // CR = - // LF = - // SP = - // HT = - // <"> = - // CRLF = CR LF - // LWS = [CRLF] 1*( SP | HT ) - // TEXT = - // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> - // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT - // token = 1* - // qdtext = > - - for c := 0; c < 256; c++ { - var t octetType - isCtl := c <= 31 || c == 127 - isChar := 0 <= c && c <= 127 - isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) - if strings.ContainsRune(" \t\r\n", rune(c)) { - t |= isSpace - } - if isChar && !isCtl && !isSeparator { - t |= isToken - } - octetTypes[c] = t - } -} - // ResponseChallenges returns a list of authorization challenges // for the given http Response. Challenges are only checked if // the response status code was a 401. diff --git a/notifications/metrics.go b/notifications/metrics.go index c520f332..238fdb00 100644 --- a/notifications/metrics.go +++ b/notifications/metrics.go @@ -20,6 +20,57 @@ var ( statusCounter = prometheus.NotificationsNamespace.NewLabeledCounter("status", "The number of status code", "code", "endpoint") ) +// endpoints is global registry of endpoints used to report metrics to expvar +var endpoints struct { + registered []*Endpoint + mu sync.Mutex +} + +func init() { + // NOTE(stevvooe): Setup registry metrics structure to report to expvar. + // Ideally, we do more metrics through logging but we need some nice + // realtime metrics for queue state for now. + + registry := expvar.Get("registry") + + if registry == nil { + registry = expvar.NewMap("registry") + } + + var notifications expvar.Map + notifications.Init() + notifications.Set("endpoints", expvar.Func(func() interface{} { + endpoints.mu.Lock() + defer endpoints.mu.Unlock() + + var names []interface{} + for _, v := range endpoints.registered { + var epjson struct { + Name string `json:"name"` + URL string `json:"url"` + EndpointConfig + + Metrics EndpointMetrics + } + + epjson.Name = v.Name() + epjson.URL = v.URL() + epjson.EndpointConfig = v.EndpointConfig + + v.ReadMetrics(&epjson.Metrics) + + names = append(names, epjson) + } + + return names + })) + + registry.(*expvar.Map).Set("notifications", ¬ifications) + + // register prometheus metrics + metrics.Register(prometheus.NotificationsNamespace) +} + // EndpointMetrics track various actions taken by the endpoint, typically by // number of events. The goal of this to export it via expvar but we may find // some other future solution to be better. @@ -123,12 +174,6 @@ func (eqc *endpointMetricsEventQueueListener) egress(event events.Event) { pendingGauge.WithValues(eqc.EndpointName).Dec(1) } -// endpoints is global registry of endpoints used to report metrics to expvar -var endpoints struct { - registered []*Endpoint - mu sync.Mutex -} - // register places the endpoint into expvar so that stats are tracked. func register(e *Endpoint) { endpoints.mu.Lock() @@ -136,48 +181,3 @@ func register(e *Endpoint) { endpoints.registered = append(endpoints.registered, e) } - -func init() { - // NOTE(stevvooe): Setup registry metrics structure to report to expvar. - // Ideally, we do more metrics through logging but we need some nice - // realtime metrics for queue state for now. - - registry := expvar.Get("registry") - - if registry == nil { - registry = expvar.NewMap("registry") - } - - var notifications expvar.Map - notifications.Init() - notifications.Set("endpoints", expvar.Func(func() interface{} { - endpoints.mu.Lock() - defer endpoints.mu.Unlock() - - var names []interface{} - for _, v := range endpoints.registered { - var epjson struct { - Name string `json:"name"` - URL string `json:"url"` - EndpointConfig - - Metrics EndpointMetrics - } - - epjson.Name = v.Name() - epjson.URL = v.URL() - epjson.EndpointConfig = v.EndpointConfig - - v.ReadMetrics(&epjson.Metrics) - - names = append(names, epjson) - } - - return names - })) - - registry.(*expvar.Map).Set("notifications", ¬ifications) - - // register prometheus metrics - metrics.Register(prometheus.NotificationsNamespace) -} diff --git a/registry/api/v2/descriptors.go b/registry/api/v2/descriptors.go index 63f51cab..7f9135fa 100644 --- a/registry/api/v2/descriptors.go +++ b/registry/api/v2/descriptors.go @@ -9,6 +9,16 @@ import ( "github.com/opencontainers/go-digest" ) +var routeDescriptorsMap map[string]RouteDescriptor + +func init() { + routeDescriptorsMap = make(map[string]RouteDescriptor, len(routeDescriptors)) + + for _, descriptor := range routeDescriptors { + routeDescriptorsMap[descriptor.Name] = descriptor + } +} + var ( nameParameterDescriptor = ParameterDescriptor{ Name: "name", @@ -1600,13 +1610,3 @@ var routeDescriptors = []RouteDescriptor{ }, }, } - -var routeDescriptorsMap map[string]RouteDescriptor - -func init() { - routeDescriptorsMap = make(map[string]RouteDescriptor, len(routeDescriptors)) - - for _, descriptor := range routeDescriptors { - routeDescriptorsMap[descriptor.Name] = descriptor - } -} diff --git a/registry/auth/auth.go b/registry/auth/auth.go index 6266d1e5..b9c3b01d 100644 --- a/registry/auth/auth.go +++ b/registry/auth/auth.go @@ -45,6 +45,16 @@ var ( ErrAuthenticationFailure = errors.New("authentication failure") ) +// InitFunc is the type of an AccessController factory function and is used +// to register the constructor for different AccesController backends. +type InitFunc func(options map[string]interface{}) (AccessController, error) + +var accessControllers map[string]InitFunc + +func init() { + accessControllers = make(map[string]InitFunc) +} + // UserInfo carries information about // an autenticated/authorized client. type UserInfo struct { @@ -104,16 +114,6 @@ type CredentialAuthenticator interface { AuthenticateUser(username, password string) error } -// InitFunc is the type of an AccessController factory function and is used -// to register the constructor for different AccesController backends. -type InitFunc func(options map[string]interface{}) (AccessController, error) - -var accessControllers map[string]InitFunc - -func init() { - accessControllers = make(map[string]InitFunc) -} - // Register is used to register an InitFunc for // an AccessController backend with the given name. func Register(name string, initFunc InitFunc) error { diff --git a/registry/auth/htpasswd/access.go b/registry/auth/htpasswd/access.go index c3f7f302..d8b33de8 100644 --- a/registry/auth/htpasswd/access.go +++ b/registry/auth/htpasswd/access.go @@ -23,6 +23,12 @@ import ( "github.com/sirupsen/logrus" ) +func init() { + if err := auth.Register("htpasswd", auth.InitFunc(newAccessController)); err != nil { + logrus.Errorf("failed to register htpasswd auth: %v", err) + } +} + type accessController struct { realm string path string @@ -150,9 +156,3 @@ func createHtpasswdFile(path string) error { }).Warnf("htpasswd is missing, provisioning with default user") return nil } - -func init() { - if err := auth.Register("htpasswd", auth.InitFunc(newAccessController)); err != nil { - logrus.Errorf("failed to register htpasswd auth: %v", err) - } -} diff --git a/registry/auth/silly/access.go b/registry/auth/silly/access.go index 8de17bb9..171251d5 100644 --- a/registry/auth/silly/access.go +++ b/registry/auth/silly/access.go @@ -16,6 +16,13 @@ import ( "github.com/sirupsen/logrus" ) +// init registers the silly auth backend. +func init() { + if err := auth.Register("silly", auth.InitFunc(newAccessController)); err != nil { + logrus.Errorf("failed to register silly auth: %v", err) + } +} + // accessController provides a simple implementation of auth.AccessController // that simply checks for a non-empty Authorization header. It is useful for // demonstration and testing. @@ -85,10 +92,3 @@ func (ch challenge) SetHeaders(r *http.Request, w http.ResponseWriter) { func (ch challenge) Error() string { return fmt.Sprintf("silly authentication challenge: %#v", ch) } - -// init registers the silly auth backend. -func init() { - if err := auth.Register("silly", auth.InitFunc(newAccessController)); err != nil { - logrus.Errorf("failed to register silly auth: %v", err) - } -} diff --git a/registry/auth/token/accesscontroller.go b/registry/auth/token/accesscontroller.go index ffae9928..8f610c46 100644 --- a/registry/auth/token/accesscontroller.go +++ b/registry/auth/token/accesscontroller.go @@ -17,6 +17,13 @@ import ( "github.com/sirupsen/logrus" ) +// init handles registering the token auth backend. +func init() { + if err := auth.Register("token", auth.InitFunc(newAccessController)); err != nil { + logrus.Errorf("tailed to register token auth: %v", err) + } +} + // accessSet maps a typed, named resource to // a set of actions requested or authorized. type accessSet map[auth.Resource]actionSet @@ -337,10 +344,3 @@ func (ac *accessController) Authorized(req *http.Request, accessItems ...auth.Ac Resources: claims.resources(), }, nil } - -// init handles registering the token auth backend. -func init() { - if err := auth.Register("token", auth.InitFunc(newAccessController)); err != nil { - logrus.Errorf("tailed to register token auth: %v", err) - } -} diff --git a/registry/proxy/proxyblobstore_test.go b/registry/proxy/proxyblobstore_test.go index dfcbfaa3..e7dccc09 100644 --- a/registry/proxy/proxyblobstore_test.go +++ b/registry/proxy/proxyblobstore_test.go @@ -20,14 +20,20 @@ import ( "github.com/opencontainers/go-digest" ) -var sbsMu sync.Mutex -var randSource rand.Rand +var ( + sbsMu sync.Mutex + randSource rand.Rand +) type statsBlobStore struct { stats map[string]int blobs distribution.BlobStore } +func init() { + randSource = *rand.New(rand.NewSource(42)) +} + func (sbs statsBlobStore) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) { sbsMu.Lock() sbs.stats["put"]++ @@ -195,10 +201,6 @@ func makeBlob(size int) []byte { return blob } -func init() { - randSource = *rand.New(rand.NewSource(42)) -} - func populate(t *testing.T, te *testEnv, blobCount, size, numUnique int) { var inRemote []distribution.Descriptor diff --git a/registry/proxy/proxymetrics.go b/registry/proxy/proxymetrics.go index 4eb89569..e2c5d242 100644 --- a/registry/proxy/proxymetrics.go +++ b/registry/proxy/proxymetrics.go @@ -36,6 +36,34 @@ type proxyMetricsCollector struct { manifestMetrics Metrics } +// proxyMetrics tracks metrics about the proxy cache. This is +// kept globally and made available via expvar. +var proxyMetrics = &proxyMetricsCollector{} + +func init() { + registry := expvar.Get("registry") + if registry == nil { + registry = expvar.NewMap("registry") + } + + pm := registry.(*expvar.Map).Get("proxy") + if pm == nil { + pm = &expvar.Map{} + pm.(*expvar.Map).Init() + registry.(*expvar.Map).Set("proxy", pm) + } + + pm.(*expvar.Map).Set("blobs", expvar.Func(func() interface{} { + return proxyMetrics.blobMetrics + })) + + pm.(*expvar.Map).Set("manifests", expvar.Func(func() interface{} { + return proxyMetrics.manifestMetrics + })) + + metrics.Register(prometheus.ProxyNamespace) +} + // BlobPull tracks metrics about blobs pulled into the cache func (pmc *proxyMetricsCollector) BlobPull(bytesPulled uint64) { atomic.AddUint64(&pmc.blobMetrics.Misses, 1) @@ -83,31 +111,3 @@ func (pmc *proxyMetricsCollector) ManifestPush(bytesPushed uint64, isHit bool) { hits.WithValues("manifest").Inc(1) } } - -// proxyMetrics tracks metrics about the proxy cache. This is -// kept globally and made available via expvar. -var proxyMetrics = &proxyMetricsCollector{} - -func init() { - registry := expvar.Get("registry") - if registry == nil { - registry = expvar.NewMap("registry") - } - - pm := registry.(*expvar.Map).Get("proxy") - if pm == nil { - pm = &expvar.Map{} - pm.(*expvar.Map).Init() - registry.(*expvar.Map).Set("proxy", pm) - } - - pm.(*expvar.Map).Set("blobs", expvar.Func(func() interface{} { - return proxyMetrics.blobMetrics - })) - - pm.(*expvar.Map).Set("manifests", expvar.Func(func() interface{} { - return proxyMetrics.manifestMetrics - })) - - metrics.Register(prometheus.ProxyNamespace) -} diff --git a/registry/storage/driver/middleware/cloudfront/middleware.go b/registry/storage/driver/middleware/cloudfront/middleware.go index 3d07f2fd..4e5f32d7 100644 --- a/registry/storage/driver/middleware/cloudfront/middleware.go +++ b/registry/storage/driver/middleware/cloudfront/middleware.go @@ -20,6 +20,13 @@ import ( "github.com/sirupsen/logrus" ) +// init registers the cloudfront layerHandler backend. +func init() { + if err := storagemiddleware.Register("cloudfront", newCloudFrontStorageMiddleware); err != nil { + logrus.Errorf("failed to register cloudfront middleware: %v", err) + } +} + // cloudFrontStorageMiddleware provides a simple implementation of layerHandler that // constructs temporary signed CloudFront URLs from the storagedriver layer URL, // then issues HTTP Temporary Redirects to this CloudFront content URL. @@ -224,10 +231,3 @@ func (lh *cloudFrontStorageMiddleware) RedirectURL(r *http.Request, path string) } return cfURL, nil } - -// init registers the cloudfront layerHandler backend. -func init() { - if err := storagemiddleware.Register("cloudfront", newCloudFrontStorageMiddleware); err != nil { - logrus.Errorf("failed to register cloudfront middleware: %v", err) - } -} diff --git a/registry/storage/driver/middleware/redirect/middleware.go b/registry/storage/driver/middleware/redirect/middleware.go index e6b9b692..08f37e6e 100644 --- a/registry/storage/driver/middleware/redirect/middleware.go +++ b/registry/storage/driver/middleware/redirect/middleware.go @@ -12,6 +12,12 @@ import ( "github.com/sirupsen/logrus" ) +func init() { + if err := storagemiddleware.Register("redirect", newRedirectStorageMiddleware); err != nil { + logrus.Errorf("tailed to register redirect storage middleware: %v", err) + } +} + type redirectStorageMiddleware struct { storagedriver.StorageDriver scheme string @@ -51,9 +57,3 @@ func (r *redirectStorageMiddleware) RedirectURL(_ *http.Request, urlPath string) u := &url.URL{Scheme: r.scheme, Host: r.host, Path: urlPath} return u.String(), nil } - -func init() { - if err := storagemiddleware.Register("redirect", newRedirectStorageMiddleware); err != nil { - logrus.Errorf("tailed to register redirect storage middleware: %v", err) - } -} diff --git a/registry/storage/driver/testsuites/testsuites.go b/registry/storage/driver/testsuites/testsuites.go index 99dd24b6..c27ff115 100644 --- a/registry/storage/driver/testsuites/testsuites.go +++ b/registry/storage/driver/testsuites/testsuites.go @@ -24,6 +24,14 @@ import ( // Test hooks up gocheck into the "go test" runner. func Test(t *testing.T) { check.TestingT(t) } +// randomBytes pre-allocates all of the memory sizes needed for the test. If +// anything panics while accessing randomBytes, just make this number bigger. +var randomBytes = make([]byte, 128<<20) + +func init() { + _, _ = crand.Read(randomBytes) // always returns len(randomBytes) and nil error +} + // RegisterSuite registers an in-process storage driver test suite with // the go test runner. func RegisterSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) { @@ -1343,14 +1351,6 @@ func randomFilename(length int64) string { return string(b) } -// randomBytes pre-allocates all of the memory sizes needed for the test. If -// anything panics while accessing randomBytes, just make this number bigger. -var randomBytes = make([]byte, 128<<20) - -func init() { - _, _ = crand.Read(randomBytes) // always returns len(randomBytes) and nil error -} - func randomContents(length int64) []byte { return randomBytes[:length] }