Skip to content

Commit

Permalink
Merge pull request #1 from akashsinghal/akashsinghal/updateDiscover
Browse files Browse the repository at this point in the history
Update OCI Discover
  • Loading branch information
juliusl authored Apr 21, 2022
2 parents 06bcda5 + 9610162 commit d130b09
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 43 deletions.
4 changes: 0 additions & 4 deletions cmd/registry/config-example-with-extensions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
# auth:
# htpasswd:
# realm: basic-realm
# path: /home/sajay/code/src/github.com/mnltejaswini/distribution/data/passwords
health:
storagedriver:
enabled: true
Expand Down
17 changes: 17 additions & 0 deletions registry/extension/distribution/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const (
extensionName = "registry"
manifestsComponentName = "manifests"
tagHistoryComponentName = "taghistory"
namespaceUrl = "insert link"
namespaceDescription = "distribution extension adds tag history and manifest list functionality"
)

type distributionNamespace struct {
Expand Down Expand Up @@ -134,6 +136,21 @@ func (d *distributionNamespace) GetRegistryRoutes() []extension.Route {
return nil
}

// GetNamespaceName returns the name associated with the namespace
func (d *distributionNamespace) GetNamespaceName() string {
return namespaceName
}

// GetNamespaceUrl returns the url link to the documentation where the namespace's extension and endpoints are defined
func (d *distributionNamespace) GetNamespaceUrl() string {
return namespaceUrl
}

// GetNamespaceDescription returns the description associated with the namespace
func (d *distributionNamespace) GetNamespaceDescription() string {
return namespaceDescription
}

func (d *distributionNamespace) tagHistoryDispatcher(ctx *extension.Context, r *http.Request) http.Handler {
tagHistoryHandler := &tagHistoryHandler{
Context: ctx,
Expand Down
60 changes: 45 additions & 15 deletions registry/extension/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,52 @@ type Namespace interface {
GetRepositoryRoutes() []Route
// GetRegistryRoutes returns a list of extension routes scoped at a registry level
GetRegistryRoutes() []Route
// GetNamespaceName returns the name associated with the namespace
GetNamespaceName() string
// GetNamespaceUrl returns the url link to the documentation where the namespace's extension and endpoints are defined
GetNamespaceUrl() string
// GetNamespaceDescription returns the description associated with the namespace
GetNamespaceDescription() string
}

// InitExtensionNamespace is the initialize function for creating the extension namespace
type InitExtensionNamespace func(ctx c.Context, storageDriver driver.StorageDriver, options configuration.ExtensionConfig) (Namespace, error)

// EnumerateExtension specifies extension information at the namespace level
type EnumerateExtension struct {
Name string `json:"name"`
Url string `json:"url"`
Description string `json:"description,omitempty"`
Endpoints []string `json:"endpoints"`
}

var extensions map[string]InitExtensionNamespace
var extensionsNamespaces map[string]Namespace

func EnumerateRegistered(ctx context.Context) (enumeratedExtensions []EnumerateExtension) {
for _, namespace := range extensionsNamespaces {
enumerateExtension := EnumerateExtension{
Name: namespace.GetNamespaceName(),
Url: namespace.GetNamespaceUrl(),
Description: namespace.GetNamespaceDescription(),
}

func EnumerateRegistered(ctx context.Context) (repositoryRoutes []v2.RouteDescriptor, registryRoutes []v2.RouteDescriptor) {
for _, ext := range extensions {
// TODO: It's probably okay to pass a nil storage driver, but should probably figure out where the extension config is stored and pass that here
namespace, err := ext(ctx, nil, nil)
if err != nil {
registryScoped := namespace.GetRegistryRoutes()
for _, regScoped := range registryScoped {
registryRoutes = append(registryRoutes, regScoped.Descriptor)
}
registryScoped := namespace.GetRegistryRoutes()
for _, regScoped := range registryScoped {
path := fmt.Sprintf("_%s/%s/%s", regScoped.Namespace, regScoped.Extension, regScoped.Component)
enumerateExtension.Endpoints = append(enumerateExtension.Endpoints, path)
}

repositoryScoped := namespace.GetRepositoryRoutes()
for _, repScoped := range repositoryScoped {
repositoryRoutes = append(repositoryRoutes, repScoped.Descriptor)
}
repositoryScoped := namespace.GetRepositoryRoutes()
for _, repScoped := range repositoryScoped {
path := fmt.Sprintf("_%s/%s/%s", repScoped.Namespace, repScoped.Extension, repScoped.Component)
enumerateExtension.Endpoints = append(enumerateExtension.Endpoints, path)
}

enumeratedExtensions = append(enumeratedExtensions, enumerateExtension)
}

return repositoryRoutes, registryRoutes
return enumeratedExtensions
}

// Register is used to register an InitExtensionNamespace for
Expand All @@ -94,8 +115,17 @@ func Register(name string, initFunc InitExtensionNamespace) {
// Get constructs an extension namespace with the given options using the given name.
func Get(ctx c.Context, name string, storageDriver driver.StorageDriver, options configuration.ExtensionConfig) (Namespace, error) {
if extensions != nil {
if extensionsNamespaces == nil {
extensionsNamespaces = make(map[string]Namespace)
}

if initFunc, exists := extensions[name]; exists {
return initFunc(ctx, storageDriver, options)
namespace, err := initFunc(ctx, storageDriver, options)
if err == nil {
// adds the initialized namespace to map for simple access to namespaces by EnumerateRegistered
extensionsNamespaces[name] = namespace
}
return namespace, err
}
}

Expand Down
24 changes: 10 additions & 14 deletions registry/extension/oci/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@ import (
"github.com/distribution/distribution/v3/registry/storage/driver"
)

type ociExtension struct {
Name string `json:"name"`
Description string `json:"description"`
Url string `json:"url"`
}

type discoverGetAPIResponse struct {
Name string `json:"name"`
Extensions []ociExtension `json:"extensions"`
Name string `json:"name"`
Extensions []extension.EnumerateExtension `json:"extensions"`
}

// extensionHandler handles requests for manifests under a manifest name.
Expand All @@ -31,18 +25,20 @@ func (th *extensionHandler) getExtensions(w http.ResponseWriter, r *http.Request

w.Header().Set("Content-Type", "application/json")

// TODO: currently this is only handling repository_routes
repository_routes, _ := extension.EnumerateRegistered(r.Context())
// get list of extension information seperated at the namespace level
enumeratedExtensions := extension.EnumerateRegistered(r.Context())

extensions := make([]ociExtension, len(repository_routes))
for _, e := range repository_routes {
extensions = append(extensions, ociExtension{Name: e.Name, Description: e.Description, Url: e.Path})
// remove the oci extension so it's not returned by discover
for i, e := range enumeratedExtensions {
if e.Name == namespaceName {
enumeratedExtensions = append(enumeratedExtensions[:i], enumeratedExtensions[i+1:]...)
}
}

enc := json.NewEncoder(w)
if err := enc.Encode(discoverGetAPIResponse{
Name: th.Repository.Named().Name(),
Extensions: extensions,
Extensions: enumeratedExtensions,
}); err != nil {
th.Errors = append(th.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
return
Expand Down
37 changes: 27 additions & 10 deletions registry/extension/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ const (
namespaceName = "oci"
extensionName = "ext"
discoverComponentName = "discover"
namespaceUrl = "https://github.com/opencontainers/distribution-spec/blob/main/extensions/_oci.md"
namespaceDescription = "oci extension enables listing of supported registry and repository extensions"
)

type distributionNamespace struct {
type ociNamespace struct {
storageDriver driver.StorageDriver
discoverEnabled bool
}

type distributionOptions struct {
type ociOptions struct {
RegExtensionComponents []string `yaml:"ext,omitempty"`
}

Expand All @@ -36,21 +38,21 @@ func newOciNamespace(ctx context.Context, storageDriver driver.StorageDriver, op
return nil, err
}

var distOptions distributionOptions
err = yaml.Unmarshal(optionsYaml, &distOptions)
var ociOption ociOptions
err = yaml.Unmarshal(optionsYaml, &ociOption)
if err != nil {
return nil, err
}

discoverEnabled := false
for _, component := range distOptions.RegExtensionComponents {
for _, component := range ociOption.RegExtensionComponents {
switch component {
case "discover":
discoverEnabled = true
}
}

return &distributionNamespace{
return &ociNamespace{
storageDriver: storageDriver,
discoverEnabled: discoverEnabled,
}, nil
Expand All @@ -62,13 +64,13 @@ func init() {
}

// GetManifestHandlers returns a list of manifest handlers that will be registered in the manifest store.
func (o *distributionNamespace) GetManifestHandlers(repo distribution.Repository, blobStore distribution.BlobStore) []storage.ManifestHandler {
func (o *ociNamespace) GetManifestHandlers(repo distribution.Repository, blobStore distribution.BlobStore) []storage.ManifestHandler {
// This extension doesn't extend any manifest store operations.
return []storage.ManifestHandler{}
}

// GetRepositoryRoutes returns a list of extension routes scoped at a repository level
func (d *distributionNamespace) GetRepositoryRoutes() []extension.Route {
func (d *ociNamespace) GetRepositoryRoutes() []extension.Route {
var routes []extension.Route

if d.discoverEnabled {
Expand All @@ -94,11 +96,26 @@ func (d *distributionNamespace) GetRepositoryRoutes() []extension.Route {

// GetRegistryRoutes returns a list of extension routes scoped at a registry level
// There are no registry scoped routes exposed by this namespace
func (d *distributionNamespace) GetRegistryRoutes() []extension.Route {
func (d *ociNamespace) GetRegistryRoutes() []extension.Route {
return nil
}

func (d *distributionNamespace) discoverDispatcher(ctx *extension.Context, r *http.Request) http.Handler {
// GetNamespaceName returns the name associated with the namespace
func (d *ociNamespace) GetNamespaceName() string {
return namespaceName
}

// GetNamespaceUrl returns the url link to the documentation where the namespace's extension and endpoints are defined
func (d *ociNamespace) GetNamespaceUrl() string {
return namespaceUrl
}

// GetNamespaceDescription returns the description associated with the namespace
func (d *ociNamespace) GetNamespaceDescription() string {
return namespaceDescription
}

func (d *ociNamespace) discoverDispatcher(ctx *extension.Context, r *http.Request) http.Handler {
extensionHandler := &extensionHandler{
Context: ctx,
storageDriver: d.storageDriver,
Expand Down
17 changes: 17 additions & 0 deletions registry/extension/oras/oras.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const (
namespaceName = "oras"
extensionName = "artifacts"
referrersComponentName = "referrers"
namespaceUrl = "https://github.com/oras-project/artifacts-spec/blob/main/manifest-referrers-api.md"
namespaceDescription = "oras extension enables listing of all reference artifacts associated with subject"
)

type orasNamespace struct {
Expand Down Expand Up @@ -107,6 +109,21 @@ func (d *orasNamespace) GetRegistryRoutes() []extension.Route {
return nil
}

// GetNamespaceName returns the name associated with the namespace
func (d *orasNamespace) GetNamespaceName() string {
return namespaceName
}

// GetNamespaceUrl returns the url link to the documentation where the namespace's extension and endpoints are defined
func (d *orasNamespace) GetNamespaceUrl() string {
return namespaceUrl
}

// GetNamespaceDescription returns the description associated with the namespace
func (d *orasNamespace) GetNamespaceDescription() string {
return namespaceDescription
}

func (o *orasNamespace) referrersDispatcher(extCtx *extension.Context, r *http.Request) http.Handler {

handler := &referrersHandler{
Expand Down

0 comments on commit d130b09

Please sign in to comment.