forked from TrueCloudLab/distribution
c40c4b289a
Enable configuration options that can selectively disable validation that dependencies exist within the registry before the image index is uploaded. This enables sparse indexes, where a registry holds a manifest index that could be signed (so the digest must not change) but does not hold every referenced image in the index. The use case for this is when a registry mirror does not need to mirror all platforms, but does need to maintain the digests of all manifests either because they are signed or because they are pulled by digest. The registry administrator can also select specific image architectures that must exist in the registry, enabling a registry operator to select only the platforms they care about and ensure all image indexes uploaded to the registry are valid for those platforms. Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
752 lines
25 KiB
Go
752 lines
25 KiB
Go
package configuration
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Configuration is a versioned registry configuration, intended to be provided by a yaml file, and
|
|
// optionally modified by environment variables.
|
|
//
|
|
// Note that yaml field names should never include _ characters, since this is the separator used
|
|
// in environment variable names.
|
|
type Configuration struct {
|
|
// Version is the version which defines the format of the rest of the configuration
|
|
Version Version `yaml:"version"`
|
|
|
|
// Log supports setting various parameters related to the logging
|
|
// subsystem.
|
|
Log struct {
|
|
// AccessLog configures access logging.
|
|
AccessLog struct {
|
|
// Disabled disables access logging.
|
|
Disabled bool `yaml:"disabled,omitempty"`
|
|
} `yaml:"accesslog,omitempty"`
|
|
|
|
// Level is the granularity at which registry operations are logged.
|
|
Level Loglevel `yaml:"level,omitempty"`
|
|
|
|
// Formatter overrides the default formatter with another. Options
|
|
// include "text", "json" and "logstash".
|
|
Formatter string `yaml:"formatter,omitempty"`
|
|
|
|
// Fields allows users to specify static string fields to include in
|
|
// the logger context.
|
|
Fields map[string]interface{} `yaml:"fields,omitempty"`
|
|
|
|
// Hooks allows users to configure the log hooks, to enabling the
|
|
// sequent handling behavior, when defined levels of log message emit.
|
|
Hooks []LogHook `yaml:"hooks,omitempty"`
|
|
|
|
// ReportCaller allows user to configure the log to report the caller
|
|
ReportCaller bool `yaml:"reportcaller,omitempty"`
|
|
}
|
|
|
|
// Loglevel is the level at which registry operations are logged.
|
|
//
|
|
// Deprecated: Use Log.Level instead.
|
|
Loglevel Loglevel `yaml:"loglevel,omitempty"`
|
|
|
|
// Storage is the configuration for the registry's storage driver
|
|
Storage Storage `yaml:"storage"`
|
|
|
|
// Auth allows configuration of various authorization methods that may be
|
|
// used to gate requests.
|
|
Auth Auth `yaml:"auth,omitempty"`
|
|
|
|
// Middleware lists all middlewares to be used by the registry.
|
|
Middleware map[string][]Middleware `yaml:"middleware,omitempty"`
|
|
|
|
// HTTP contains configuration parameters for the registry's http
|
|
// interface.
|
|
HTTP struct {
|
|
// Addr specifies the bind address for the registry instance.
|
|
Addr string `yaml:"addr,omitempty"`
|
|
|
|
// Net specifies the net portion of the bind address. A default empty value means tcp.
|
|
Net string `yaml:"net,omitempty"`
|
|
|
|
// Host specifies an externally-reachable address for the registry, as a fully
|
|
// qualified URL.
|
|
Host string `yaml:"host,omitempty"`
|
|
|
|
Prefix string `yaml:"prefix,omitempty"`
|
|
|
|
// Secret specifies the secret key which HMAC tokens are created with.
|
|
Secret string `yaml:"secret,omitempty"`
|
|
|
|
// RelativeURLs specifies that relative URLs should be returned in
|
|
// Location headers
|
|
RelativeURLs bool `yaml:"relativeurls,omitempty"`
|
|
|
|
// Amount of time to wait for connection to drain before shutting down when registry
|
|
// receives a stop signal
|
|
DrainTimeout time.Duration `yaml:"draintimeout,omitempty"`
|
|
|
|
// TLS instructs the http server to listen with a TLS configuration.
|
|
// This only support simple tls configuration with a cert and key.
|
|
// Mostly, this is useful for testing situations or simple deployments
|
|
// that require tls. If more complex configurations are required, use
|
|
// a proxy or make a proposal to add support here.
|
|
TLS struct {
|
|
// Certificate specifies the path to an x509 certificate file to
|
|
// be used for TLS.
|
|
Certificate string `yaml:"certificate,omitempty"`
|
|
|
|
// Key specifies the path to the x509 key file, which should
|
|
// contain the private portion for the file specified in
|
|
// Certificate.
|
|
Key string `yaml:"key,omitempty"`
|
|
|
|
// Specifies the CA certs for client authentication
|
|
// A file may contain multiple CA certificates encoded as PEM
|
|
ClientCAs []string `yaml:"clientcas,omitempty"`
|
|
|
|
// Specifies the lowest TLS version allowed
|
|
MinimumTLS string `yaml:"minimumtls,omitempty"`
|
|
|
|
// Specifies a list of cipher suites allowed
|
|
CipherSuites []string `yaml:"ciphersuites,omitempty"`
|
|
|
|
// LetsEncrypt is used to configuration setting up TLS through
|
|
// Let's Encrypt instead of manually specifying certificate and
|
|
// key. If a TLS certificate is specified, the Let's Encrypt
|
|
// section will not be used.
|
|
LetsEncrypt struct {
|
|
// CacheFile specifies cache file to use for lets encrypt
|
|
// certificates and keys.
|
|
CacheFile string `yaml:"cachefile,omitempty"`
|
|
|
|
// Email is the email to use during Let's Encrypt registration
|
|
Email string `yaml:"email,omitempty"`
|
|
|
|
// Hosts specifies the hosts which are allowed to obtain Let's
|
|
// Encrypt certificates.
|
|
Hosts []string `yaml:"hosts,omitempty"`
|
|
|
|
// DirectoryURL points to the CA directory endpoint.
|
|
// If empty, LetsEncrypt is used.
|
|
DirectoryURL string `yaml:"directoryurl,omitempty"`
|
|
} `yaml:"letsencrypt,omitempty"`
|
|
} `yaml:"tls,omitempty"`
|
|
|
|
// Headers is a set of headers to include in HTTP responses. A common
|
|
// use case for this would be security headers such as
|
|
// Strict-Transport-Security. The map keys are the header names, and
|
|
// the values are the associated header payloads.
|
|
Headers http.Header `yaml:"headers,omitempty"`
|
|
|
|
// Debug configures the http debug interface, if specified. This can
|
|
// include services such as pprof, expvar and other data that should
|
|
// not be exposed externally. Left disabled by default.
|
|
Debug struct {
|
|
// Addr specifies the bind address for the debug server.
|
|
Addr string `yaml:"addr,omitempty"`
|
|
// Prometheus configures the Prometheus telemetry endpoint.
|
|
Prometheus struct {
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
Path string `yaml:"path,omitempty"`
|
|
} `yaml:"prometheus,omitempty"`
|
|
} `yaml:"debug,omitempty"`
|
|
|
|
// HTTP2 configuration options
|
|
HTTP2 struct {
|
|
// Specifies whether the registry should disallow clients attempting
|
|
// to connect via HTTP/2. If set to true, only HTTP/1.1 is supported.
|
|
Disabled bool `yaml:"disabled,omitempty"`
|
|
} `yaml:"http2,omitempty"`
|
|
|
|
H2C struct {
|
|
// Enables H2C (HTTP/2 Cleartext). Enable to support HTTP/2 without needing to configure TLS
|
|
// Useful when deploying the registry behind a load balancer (e.g. Cloud Run)
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
} `yaml:"h2c,omitempty"`
|
|
} `yaml:"http,omitempty"`
|
|
|
|
// Notifications specifies configuration about various endpoint to which
|
|
// registry events are dispatched.
|
|
Notifications Notifications `yaml:"notifications,omitempty"`
|
|
|
|
// Redis configures the redis pool available to the registry webapp.
|
|
Redis Redis `yaml:"redis,omitempty"`
|
|
|
|
Health Health `yaml:"health,omitempty"`
|
|
Catalog Catalog `yaml:"catalog,omitempty"`
|
|
|
|
Proxy Proxy `yaml:"proxy,omitempty"`
|
|
|
|
// Validation configures validation options for the registry.
|
|
Validation Validation `yaml:"validation,omitempty"`
|
|
|
|
// Policy configures registry policy options.
|
|
Policy struct {
|
|
// Repository configures policies for repositories
|
|
Repository struct {
|
|
// Classes is a list of repository classes which the
|
|
// registry allows content for. This class is matched
|
|
// against the configuration media type inside uploaded
|
|
// manifests. When non-empty, the registry will enforce
|
|
// the class in authorized resources.
|
|
Classes []string `yaml:"classes"`
|
|
} `yaml:"repository,omitempty"`
|
|
} `yaml:"policy,omitempty"`
|
|
}
|
|
|
|
// Catalog is composed of MaxEntries.
|
|
// Catalog endpoint (/v2/_catalog) configuration, it provides the configuration
|
|
// options to control the maximum number of entries returned by the catalog endpoint.
|
|
type Catalog struct {
|
|
// Max number of entries returned by the catalog endpoint. Requesting n entries
|
|
// to the catalog endpoint will return at most MaxEntries entries.
|
|
// An empty or a negative value will set a default of 1000 maximum entries by default.
|
|
MaxEntries int `yaml:"maxentries,omitempty"`
|
|
}
|
|
|
|
// LogHook is composed of hook Level and Type.
|
|
// After hooks configuration, it can execute the next handling automatically,
|
|
// when defined levels of log message emitted.
|
|
// Example: hook can sending an email notification when error log happens in app.
|
|
type LogHook struct {
|
|
// Disable lets user select to enable hook or not.
|
|
Disabled bool `yaml:"disabled,omitempty"`
|
|
|
|
// Type allows user to select which type of hook handler they want.
|
|
Type string `yaml:"type,omitempty"`
|
|
|
|
// Levels set which levels of log message will let hook executed.
|
|
Levels []string `yaml:"levels,omitempty"`
|
|
|
|
// MailOptions allows user to configure email parameters.
|
|
MailOptions MailOptions `yaml:"options,omitempty"`
|
|
}
|
|
|
|
// MailOptions provides the configuration sections to user, for specific handler.
|
|
type MailOptions struct {
|
|
SMTP struct {
|
|
// Addr defines smtp host address
|
|
Addr string `yaml:"addr,omitempty"`
|
|
|
|
// Username defines user name to smtp host
|
|
Username string `yaml:"username,omitempty"`
|
|
|
|
// Password defines password of login user
|
|
Password string `yaml:"password,omitempty"`
|
|
|
|
// Insecure defines if smtp login skips the secure certification.
|
|
Insecure bool `yaml:"insecure,omitempty"`
|
|
} `yaml:"smtp,omitempty"`
|
|
|
|
// From defines mail sending address
|
|
From string `yaml:"from,omitempty"`
|
|
|
|
// To defines mail receiving address
|
|
To []string `yaml:"to,omitempty"`
|
|
}
|
|
|
|
// FileChecker is a type of entry in the health section for checking files.
|
|
type FileChecker struct {
|
|
// Interval is the duration in between checks
|
|
Interval time.Duration `yaml:"interval,omitempty"`
|
|
// File is the path to check
|
|
File string `yaml:"file,omitempty"`
|
|
// Threshold is the number of times a check must fail to trigger an
|
|
// unhealthy state
|
|
Threshold int `yaml:"threshold,omitempty"`
|
|
}
|
|
|
|
// Redis configures the redis pool available to the registry webapp.
|
|
type Redis struct {
|
|
// Addr specifies the redis instance available to the application.
|
|
Addr string `yaml:"addr,omitempty"`
|
|
|
|
// Usernames can be used as a finer-grained permission control since the introduction of the redis 6.0.
|
|
Username string `yaml:"username,omitempty"`
|
|
|
|
// Password string to use when making a connection.
|
|
Password string `yaml:"password,omitempty"`
|
|
|
|
// DB specifies the database to connect to on the redis instance.
|
|
DB int `yaml:"db,omitempty"`
|
|
|
|
// TLS configures settings for redis in-transit encryption
|
|
TLS struct {
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
} `yaml:"tls,omitempty"`
|
|
|
|
DialTimeout time.Duration `yaml:"dialtimeout,omitempty"` // timeout for connect
|
|
ReadTimeout time.Duration `yaml:"readtimeout,omitempty"` // timeout for reads of data
|
|
WriteTimeout time.Duration `yaml:"writetimeout,omitempty"` // timeout for writes of data
|
|
|
|
// Pool configures the behavior of the redis connection pool.
|
|
Pool struct {
|
|
// MaxIdle sets the maximum number of idle connections.
|
|
MaxIdle int `yaml:"maxidle,omitempty"`
|
|
|
|
// MaxActive sets the maximum number of connections that should be
|
|
// opened before blocking a connection request.
|
|
MaxActive int `yaml:"maxactive,omitempty"`
|
|
|
|
// IdleTimeout sets the amount time to wait before closing
|
|
// inactive connections.
|
|
IdleTimeout time.Duration `yaml:"idletimeout,omitempty"`
|
|
} `yaml:"pool,omitempty"`
|
|
}
|
|
|
|
// HTTPChecker is a type of entry in the health section for checking HTTP URIs.
|
|
type HTTPChecker struct {
|
|
// Timeout is the duration to wait before timing out the HTTP request
|
|
Timeout time.Duration `yaml:"timeout,omitempty"`
|
|
// StatusCode is the expected status code
|
|
StatusCode int
|
|
// Interval is the duration in between checks
|
|
Interval time.Duration `yaml:"interval,omitempty"`
|
|
// URI is the HTTP URI to check
|
|
URI string `yaml:"uri,omitempty"`
|
|
// Headers lists static headers that should be added to all requests
|
|
Headers http.Header `yaml:"headers"`
|
|
// Threshold is the number of times a check must fail to trigger an
|
|
// unhealthy state
|
|
Threshold int `yaml:"threshold,omitempty"`
|
|
}
|
|
|
|
// TCPChecker is a type of entry in the health section for checking TCP servers.
|
|
type TCPChecker struct {
|
|
// Timeout is the duration to wait before timing out the TCP connection
|
|
Timeout time.Duration `yaml:"timeout,omitempty"`
|
|
// Interval is the duration in between checks
|
|
Interval time.Duration `yaml:"interval,omitempty"`
|
|
// Addr is the TCP address to check
|
|
Addr string `yaml:"addr,omitempty"`
|
|
// Threshold is the number of times a check must fail to trigger an
|
|
// unhealthy state
|
|
Threshold int `yaml:"threshold,omitempty"`
|
|
}
|
|
|
|
// Health provides the configuration section for health checks.
|
|
type Health struct {
|
|
// FileCheckers is a list of paths to check
|
|
FileCheckers []FileChecker `yaml:"file,omitempty"`
|
|
// HTTPCheckers is a list of URIs to check
|
|
HTTPCheckers []HTTPChecker `yaml:"http,omitempty"`
|
|
// TCPCheckers is a list of URIs to check
|
|
TCPCheckers []TCPChecker `yaml:"tcp,omitempty"`
|
|
// StorageDriver configures a health check on the configured storage
|
|
// driver
|
|
StorageDriver struct {
|
|
// Enabled turns on the health check for the storage driver
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
// Interval is the duration in between checks
|
|
Interval time.Duration `yaml:"interval,omitempty"`
|
|
// Threshold is the number of times a check must fail to trigger an
|
|
// unhealthy state
|
|
Threshold int `yaml:"threshold,omitempty"`
|
|
} `yaml:"storagedriver,omitempty"`
|
|
}
|
|
|
|
type Platform struct {
|
|
// Architecture is the architecture for this platform
|
|
Architecture string `yaml:"architecture,omitempty"`
|
|
// OS is the operating system for this platform
|
|
OS string `yaml:"os,omitempty"`
|
|
}
|
|
|
|
// v0_1Configuration is a Version 0.1 Configuration struct
|
|
// This is currently aliased to Configuration, as it is the current version
|
|
type v0_1Configuration Configuration
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface
|
|
// Unmarshals a string of the form X.Y into a Version, validating that X and Y can represent unsigned integers
|
|
func (version *Version) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var versionString string
|
|
err := unmarshal(&versionString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
newVersion := Version(versionString)
|
|
if _, err := newVersion.major(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := newVersion.minor(); err != nil {
|
|
return err
|
|
}
|
|
|
|
*version = newVersion
|
|
return nil
|
|
}
|
|
|
|
// CurrentVersion is the most recent Version that can be parsed
|
|
var CurrentVersion = MajorMinorVersion(0, 1)
|
|
|
|
// Loglevel is the level at which operations are logged
|
|
// This can be error, warn, info, or debug
|
|
type Loglevel string
|
|
|
|
// UnmarshalYAML implements the yaml.Umarshaler interface
|
|
// Unmarshals a string into a Loglevel, lowercasing the string and validating that it represents a
|
|
// valid loglevel
|
|
func (loglevel *Loglevel) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var loglevelString string
|
|
err := unmarshal(&loglevelString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
loglevelString = strings.ToLower(loglevelString)
|
|
switch loglevelString {
|
|
case "error", "warn", "info", "debug":
|
|
default:
|
|
return fmt.Errorf("invalid loglevel %s Must be one of [error, warn, info, debug]", loglevelString)
|
|
}
|
|
|
|
*loglevel = Loglevel(loglevelString)
|
|
return nil
|
|
}
|
|
|
|
// Parameters defines a key-value parameters mapping
|
|
type Parameters map[string]interface{}
|
|
|
|
// Storage defines the configuration for registry object storage
|
|
type Storage map[string]Parameters
|
|
|
|
// Type returns the storage driver type, such as filesystem or s3
|
|
func (storage Storage) Type() string {
|
|
var storageType []string
|
|
|
|
// Return only key in this map
|
|
for k := range storage {
|
|
switch k {
|
|
case "maintenance":
|
|
// allow configuration of maintenance
|
|
case "cache":
|
|
// allow configuration of caching
|
|
case "delete":
|
|
// allow configuration of delete
|
|
case "redirect":
|
|
// allow configuration of redirect
|
|
case "tag":
|
|
// allow configuration of tag
|
|
default:
|
|
storageType = append(storageType, k)
|
|
}
|
|
}
|
|
if len(storageType) > 1 {
|
|
panic("multiple storage drivers specified in configuration or environment: " + strings.Join(storageType, ", "))
|
|
}
|
|
if len(storageType) == 1 {
|
|
return storageType[0]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// TagParameters returns the Parameters map for a Storage tag configuration
|
|
func (storage Storage) TagParameters() Parameters {
|
|
return storage["tag"]
|
|
}
|
|
|
|
// setTagParameter changes the parameter at the provided key to the new value
|
|
func (storage Storage) setTagParameter(key string, value interface{}) {
|
|
if _, ok := storage["tag"]; !ok {
|
|
storage["tag"] = make(Parameters)
|
|
}
|
|
storage["tag"][key] = value
|
|
}
|
|
|
|
// Parameters returns the Parameters map for a Storage configuration
|
|
func (storage Storage) Parameters() Parameters {
|
|
return storage[storage.Type()]
|
|
}
|
|
|
|
// setParameter changes the parameter at the provided key to the new value
|
|
func (storage Storage) setParameter(key string, value interface{}) {
|
|
storage[storage.Type()][key] = value
|
|
}
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface
|
|
// Unmarshals a single item map into a Storage or a string into a Storage type with no parameters
|
|
func (storage *Storage) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var storageMap map[string]Parameters
|
|
err := unmarshal(&storageMap)
|
|
if err == nil {
|
|
if len(storageMap) > 1 {
|
|
types := make([]string, 0, len(storageMap))
|
|
for k := range storageMap {
|
|
switch k {
|
|
case "maintenance":
|
|
// allow for configuration of maintenance
|
|
case "cache":
|
|
// allow configuration of caching
|
|
case "delete":
|
|
// allow configuration of delete
|
|
case "redirect":
|
|
// allow configuration of redirect
|
|
case "tag":
|
|
// allow configuration of tag
|
|
default:
|
|
types = append(types, k)
|
|
}
|
|
}
|
|
|
|
if len(types) > 1 {
|
|
return fmt.Errorf("must provide exactly one storage type. Provided: %v", types)
|
|
}
|
|
}
|
|
*storage = storageMap
|
|
return nil
|
|
}
|
|
|
|
var storageType string
|
|
err = unmarshal(&storageType)
|
|
if err == nil {
|
|
*storage = Storage{storageType: Parameters{}}
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// MarshalYAML implements the yaml.Marshaler interface
|
|
func (storage Storage) MarshalYAML() (interface{}, error) {
|
|
if storage.Parameters() == nil {
|
|
return storage.Type(), nil
|
|
}
|
|
return map[string]Parameters(storage), nil
|
|
}
|
|
|
|
// Auth defines the configuration for registry authorization.
|
|
type Auth map[string]Parameters
|
|
|
|
// Type returns the auth type, such as htpasswd or token
|
|
func (auth Auth) Type() string {
|
|
// Return only key in this map
|
|
for k := range auth {
|
|
return k
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Parameters returns the Parameters map for an Auth configuration
|
|
func (auth Auth) Parameters() Parameters {
|
|
return auth[auth.Type()]
|
|
}
|
|
|
|
// setParameter changes the parameter at the provided key to the new value
|
|
func (auth Auth) setParameter(key string, value interface{}) {
|
|
auth[auth.Type()][key] = value
|
|
}
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface
|
|
// Unmarshals a single item map into a Storage or a string into a Storage type with no parameters
|
|
func (auth *Auth) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var m map[string]Parameters
|
|
err := unmarshal(&m)
|
|
if err == nil {
|
|
if len(m) > 1 {
|
|
types := make([]string, 0, len(m))
|
|
for k := range m {
|
|
types = append(types, k)
|
|
}
|
|
|
|
// TODO(stevvooe): May want to change this slightly for
|
|
// authorization to allow multiple challenges.
|
|
return fmt.Errorf("must provide exactly one type. Provided: %v", types)
|
|
|
|
}
|
|
*auth = m
|
|
return nil
|
|
}
|
|
|
|
var authType string
|
|
err = unmarshal(&authType)
|
|
if err == nil {
|
|
*auth = Auth{authType: Parameters{}}
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// MarshalYAML implements the yaml.Marshaler interface
|
|
func (auth Auth) MarshalYAML() (interface{}, error) {
|
|
if auth.Parameters() == nil {
|
|
return auth.Type(), nil
|
|
}
|
|
return map[string]Parameters(auth), nil
|
|
}
|
|
|
|
// Notifications configures multiple http endpoints.
|
|
type Notifications struct {
|
|
// EventConfig is the configuration for the event format that is sent to each Endpoint.
|
|
EventConfig Events `yaml:"events,omitempty"`
|
|
// Endpoints is a list of http configurations for endpoints that
|
|
// respond to webhook notifications. In the future, we may allow other
|
|
// kinds of endpoints, such as external queues.
|
|
Endpoints []Endpoint `yaml:"endpoints,omitempty"`
|
|
}
|
|
|
|
// Endpoint describes the configuration of an http webhook notification
|
|
// endpoint.
|
|
type Endpoint struct {
|
|
Name string `yaml:"name"` // identifies the endpoint in the registry instance.
|
|
Disabled bool `yaml:"disabled"` // disables the endpoint
|
|
URL string `yaml:"url"` // post url for the endpoint.
|
|
Headers http.Header `yaml:"headers"` // static headers that should be added to all requests
|
|
Timeout time.Duration `yaml:"timeout"` // HTTP timeout
|
|
Threshold int `yaml:"threshold"` // circuit breaker threshold before backing off on failure
|
|
Backoff time.Duration `yaml:"backoff"` // backoff duration
|
|
IgnoredMediaTypes []string `yaml:"ignoredmediatypes"` // target media types to ignore
|
|
Ignore Ignore `yaml:"ignore"` // ignore event types
|
|
}
|
|
|
|
// Events configures notification events.
|
|
type Events struct {
|
|
IncludeReferences bool `yaml:"includereferences"` // include reference data in manifest events
|
|
}
|
|
|
|
// Ignore configures mediaTypes and actions of the event, that it won't be propagated
|
|
type Ignore struct {
|
|
MediaTypes []string `yaml:"mediatypes"` // target media types to ignore
|
|
Actions []string `yaml:"actions"` // ignore action types
|
|
}
|
|
|
|
// Middleware configures named middlewares to be applied at injection points.
|
|
type Middleware struct {
|
|
// Name the middleware registers itself as
|
|
Name string `yaml:"name"`
|
|
// Flag to disable middleware easily
|
|
Disabled bool `yaml:"disabled,omitempty"`
|
|
// Map of parameters that will be passed to the middleware's initialization function
|
|
Options Parameters `yaml:"options"`
|
|
}
|
|
|
|
// Proxy configures the registry as a pull through cache
|
|
type Proxy struct {
|
|
// RemoteURL is the URL of the remote registry
|
|
RemoteURL string `yaml:"remoteurl"`
|
|
|
|
// Username of the hub user
|
|
Username string `yaml:"username"`
|
|
|
|
// Password of the hub user
|
|
Password string `yaml:"password"`
|
|
|
|
// TTL is the expiry time of the content and will be cleaned up when it expires
|
|
// if not set, defaults to 7 * 24 hours
|
|
// If set to zero, will never expire cache
|
|
TTL *time.Duration `yaml:"ttl,omitempty"`
|
|
}
|
|
|
|
type Validation struct {
|
|
// Enabled enables the other options in this section. This field is
|
|
// deprecated in favor of Disabled.
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
// Disabled disables the other options in this section.
|
|
Disabled bool `yaml:"disabled,omitempty"`
|
|
// Manifests configures manifest validation.
|
|
Manifests ValidationManifests `yaml:"manifests,omitempty"`
|
|
}
|
|
|
|
type ValidationManifests struct {
|
|
// URLs configures validation for URLs in pushed manifests.
|
|
URLs struct {
|
|
// Allow specifies regular expressions (https://godoc.org/regexp/syntax)
|
|
// that URLs in pushed manifests must match.
|
|
Allow []string `yaml:"allow,omitempty"`
|
|
// Deny specifies regular expressions (https://godoc.org/regexp/syntax)
|
|
// that URLs in pushed manifests must not match.
|
|
Deny []string `yaml:"deny,omitempty"`
|
|
} `yaml:"urls,omitempty"`
|
|
// ImageIndexes configures validation of image indexes
|
|
Indexes ValidationIndexes `yaml:"indexes,omitempty"`
|
|
}
|
|
|
|
type ValidationIndexes struct {
|
|
// Platforms configures the validation applies to the platform images included in an image index
|
|
Platforms Platforms `yaml:"platforms"`
|
|
// PlatformList filters the set of platforms to validate for image existence.
|
|
PlatformList []Platform `yaml:"platformlist,omitempty"`
|
|
}
|
|
|
|
// Platforms configures the validation applies to the platform images included in an image index
|
|
// This can be all, none, or list
|
|
type Platforms string
|
|
|
|
// UnmarshalYAML implements the yaml.Umarshaler interface
|
|
// Unmarshals a string into a Platforms option, lowercasing the string and validating that it represents a
|
|
// valid option
|
|
func (platforms *Platforms) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var platformsString string
|
|
err := unmarshal(&platformsString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
platformsString = strings.ToLower(platformsString)
|
|
switch platformsString {
|
|
case "all", "none", "list":
|
|
default:
|
|
return fmt.Errorf("invalid platforms option %s Must be one of [all, none, list]", platformsString)
|
|
}
|
|
|
|
*platforms = Platforms(platformsString)
|
|
return nil
|
|
}
|
|
|
|
// Parse parses an input configuration yaml document into a Configuration struct
|
|
// This should generally be capable of handling old configuration format versions
|
|
//
|
|
// Environment variables may be used to override configuration parameters other than version,
|
|
// following the scheme below:
|
|
// Configuration.Abc may be replaced by the value of REGISTRY_ABC,
|
|
// Configuration.Abc.Xyz may be replaced by the value of REGISTRY_ABC_XYZ, and so forth
|
|
func Parse(rd io.Reader) (*Configuration, error) {
|
|
in, err := io.ReadAll(rd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p := NewParser("registry", []VersionedParseInfo{
|
|
{
|
|
Version: MajorMinorVersion(0, 1),
|
|
ParseAs: reflect.TypeOf(v0_1Configuration{}),
|
|
ConversionFunc: func(c interface{}) (interface{}, error) {
|
|
if v0_1, ok := c.(*v0_1Configuration); ok {
|
|
if v0_1.Log.Level == Loglevel("") {
|
|
if v0_1.Loglevel != Loglevel("") {
|
|
v0_1.Log.Level = v0_1.Loglevel
|
|
} else {
|
|
v0_1.Log.Level = Loglevel("info")
|
|
}
|
|
}
|
|
if v0_1.Loglevel != Loglevel("") {
|
|
v0_1.Loglevel = Loglevel("")
|
|
}
|
|
|
|
if v0_1.Catalog.MaxEntries <= 0 {
|
|
v0_1.Catalog.MaxEntries = 1000
|
|
}
|
|
|
|
if v0_1.Storage.Type() == "" {
|
|
return nil, errors.New("no storage configuration provided")
|
|
}
|
|
return (*Configuration)(v0_1), nil
|
|
}
|
|
return nil, fmt.Errorf("expected *v0_1Configuration, received %#v", c)
|
|
},
|
|
},
|
|
})
|
|
|
|
config := new(Configuration)
|
|
err = p.Parse(in, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return config, nil
|
|
}
|