forked from TrueCloudLab/distribution
Merge pull request #841 from stevvooe/next-generation
Export error descriptors and provide tool generate markdown table
This commit is contained in:
commit
500d11564b
3 changed files with 120 additions and 19 deletions
|
@ -20,16 +20,21 @@ type ErrorDescriptor struct {
|
||||||
// for use in documentation.
|
// for use in documentation.
|
||||||
Description string
|
Description string
|
||||||
|
|
||||||
// DefaultStatusCode should to be returned via the HTTP API. Some error
|
// HTTPStatusCodes provides a list of status under which this error
|
||||||
// may have different status codes depending on the situation.
|
// condition may arise. If it is empty, the error condition may be seen
|
||||||
DefaultStatusCode int
|
// for any status code.
|
||||||
|
HTTPStatusCodes []int
|
||||||
}
|
}
|
||||||
|
|
||||||
var descriptors = []ErrorDescriptor{
|
// Descriptors provides a list of HTTP API Error codes that may be encountered
|
||||||
|
// when interacting with the registry API.
|
||||||
|
var Descriptors = []ErrorDescriptor{
|
||||||
{
|
{
|
||||||
Code: ErrorCodeUnknown,
|
Code: ErrorCodeUnknown,
|
||||||
Value: "UNKNOWN",
|
Value: "UNKNOWN",
|
||||||
Message: "unknown error",
|
Message: "unknown error",
|
||||||
|
Description: `Generic error returned when the error does not have an
|
||||||
|
API classification.`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeDigestInvalid,
|
Code: ErrorCodeDigestInvalid,
|
||||||
|
@ -40,7 +45,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
include a detail structure with the key "digest", including the
|
include a detail structure with the key "digest", including the
|
||||||
invalid digest string. This error may also be returned when a manifest
|
invalid digest string. This error may also be returned when a manifest
|
||||||
includes an invalid layer digest.`,
|
includes an invalid layer digest.`,
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeSizeInvalid,
|
Code: ErrorCodeSizeInvalid,
|
||||||
|
@ -49,7 +54,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Description: `When a layer is uploaded, the provided size will be
|
Description: `When a layer is uploaded, the provided size will be
|
||||||
checked against the uploaded content. If they do not match, this error
|
checked against the uploaded content. If they do not match, this error
|
||||||
will be returned.`,
|
will be returned.`,
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeNameInvalid,
|
Code: ErrorCodeNameInvalid,
|
||||||
|
@ -57,7 +62,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "manifest name did not match URI",
|
Message: "manifest name did not match URI",
|
||||||
Description: `During a manifest upload, if the name in the manifest
|
Description: `During a manifest upload, if the name in the manifest
|
||||||
does not match the uri name, this error will be returned.`,
|
does not match the uri name, this error will be returned.`,
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeTagInvalid,
|
Code: ErrorCodeTagInvalid,
|
||||||
|
@ -65,7 +70,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "manifest tag did not match URI",
|
Message: "manifest tag did not match URI",
|
||||||
Description: `During a manifest upload, if the tag in the manifest
|
Description: `During a manifest upload, if the tag in the manifest
|
||||||
does not match the uri tag, this error will be returned.`,
|
does not match the uri tag, this error will be returned.`,
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeNameUnknown,
|
Code: ErrorCodeNameUnknown,
|
||||||
|
@ -73,7 +78,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "repository name not known to registry",
|
Message: "repository name not known to registry",
|
||||||
Description: `This is returned if the name used during an operation is
|
Description: `This is returned if the name used during an operation is
|
||||||
unknown to the registry.`,
|
unknown to the registry.`,
|
||||||
DefaultStatusCode: http.StatusNotFound,
|
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeManifestUnknown,
|
Code: ErrorCodeManifestUnknown,
|
||||||
|
@ -81,7 +86,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "manifest unknown",
|
Message: "manifest unknown",
|
||||||
Description: `This error is returned when the manifest, identified by
|
Description: `This error is returned when the manifest, identified by
|
||||||
name and tag is unknown to the repository.`,
|
name and tag is unknown to the repository.`,
|
||||||
DefaultStatusCode: http.StatusNotFound,
|
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeManifestInvalid,
|
Code: ErrorCodeManifestInvalid,
|
||||||
|
@ -89,8 +94,9 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "manifest invalid",
|
Message: "manifest invalid",
|
||||||
Description: `During upload, manifests undergo several checks ensuring
|
Description: `During upload, manifests undergo several checks ensuring
|
||||||
validity. If those checks fail, this error may be returned, unless a
|
validity. If those checks fail, this error may be returned, unless a
|
||||||
more specific error is included.`,
|
more specific error is included. The detail will contain information
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
the failed validation.`,
|
||||||
|
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeManifestUnverified,
|
Code: ErrorCodeManifestUnverified,
|
||||||
|
@ -98,7 +104,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "manifest failed signature verification",
|
Message: "manifest failed signature verification",
|
||||||
Description: `During manifest upload, if the manifest fails signature
|
Description: `During manifest upload, if the manifest fails signature
|
||||||
verification, this error will be returned.`,
|
verification, this error will be returned.`,
|
||||||
DefaultStatusCode: http.StatusBadRequest,
|
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Code: ErrorCodeBlobUnknown,
|
Code: ErrorCodeBlobUnknown,
|
||||||
|
@ -108,7 +114,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
registry in a specified repository. This can be returned with a
|
registry in a specified repository. This can be returned with a
|
||||||
standard get or if a manifest references an unknown layer during
|
standard get or if a manifest references an unknown layer during
|
||||||
upload.`,
|
upload.`,
|
||||||
DefaultStatusCode: http.StatusNotFound,
|
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -117,7 +123,7 @@ var descriptors = []ErrorDescriptor{
|
||||||
Message: "blob upload unknown to registry",
|
Message: "blob upload unknown to registry",
|
||||||
Description: `If a blob upload has been cancelled or was never
|
Description: `If a blob upload has been cancelled or was never
|
||||||
started, this error code may be returned.`,
|
started, this error code may be returned.`,
|
||||||
DefaultStatusCode: http.StatusNotFound,
|
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,10 +131,10 @@ var errorCodeToDescriptors map[ErrorCode]ErrorDescriptor
|
||||||
var idToDescriptors map[string]ErrorDescriptor
|
var idToDescriptors map[string]ErrorDescriptor
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(descriptors))
|
errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(Descriptors))
|
||||||
idToDescriptors = make(map[string]ErrorDescriptor, len(descriptors))
|
idToDescriptors = make(map[string]ErrorDescriptor, len(Descriptors))
|
||||||
|
|
||||||
for _, descriptor := range descriptors {
|
for _, descriptor := range Descriptors {
|
||||||
errorCodeToDescriptors[descriptor.Code] = descriptor
|
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||||
idToDescriptors[descriptor.Value] = descriptor
|
idToDescriptors[descriptor.Value] = descriptor
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
// TestErrorCodes ensures that error code format, mappings and
|
// TestErrorCodes ensures that error code format, mappings and
|
||||||
// marshaling/unmarshaling. round trips are stable.
|
// marshaling/unmarshaling. round trips are stable.
|
||||||
func TestErrorCodes(t *testing.T) {
|
func TestErrorCodes(t *testing.T) {
|
||||||
for _, desc := range descriptors {
|
for _, desc := range Descriptors {
|
||||||
if desc.Code.String() != desc.Value {
|
if desc.Code.String() != desc.Value {
|
||||||
t.Fatalf("error code string incorrect: %q != %q", desc.Code.String(), desc.Value)
|
t.Fatalf("error code string incorrect: %q != %q", desc.Code.String(), desc.Value)
|
||||||
}
|
}
|
||||||
|
|
95
cmd/registry-api-doctable-gen/main.go
Normal file
95
cmd/registry-api-doctable-gen/main.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// registry-api-doctable-gen uses various descriptors within the registry code
|
||||||
|
// base to generate markdown tables for use in documentation. This is only
|
||||||
|
// meant to facilitate updates to documentation and not as an automated tool.
|
||||||
|
//
|
||||||
|
// For now, this only includes support for error codes:
|
||||||
|
//
|
||||||
|
// $ registry-api-doctable-gen errors
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/docker/docker-registry/api/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
log.Fatalln("please specify a table to generate: (errors)")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch os.Args[1] {
|
||||||
|
case "errors":
|
||||||
|
dumpErrors(os.Stdout)
|
||||||
|
default:
|
||||||
|
log.Fatalln("unknown descriptor table:", os.Args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpErrors(wr io.Writer) {
|
||||||
|
writer := tabwriter.NewWriter(os.Stdout, 8, 8, 0, '\t', 0)
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
fmt.Fprint(writer, "|")
|
||||||
|
dtype := reflect.TypeOf(errors.ErrorDescriptor{})
|
||||||
|
var fieldsPrinted int
|
||||||
|
for i := 0; i < dtype.NumField(); i++ {
|
||||||
|
field := dtype.Field(i)
|
||||||
|
if field.Name == "Value" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(writer, field.Name, "|")
|
||||||
|
fieldsPrinted++
|
||||||
|
}
|
||||||
|
|
||||||
|
divider := strings.Repeat("-", 8)
|
||||||
|
var parts []string
|
||||||
|
for i := 0; i < fieldsPrinted; i++ {
|
||||||
|
parts = append(parts, divider)
|
||||||
|
}
|
||||||
|
divider = strings.Join(parts, "|")
|
||||||
|
|
||||||
|
fmt.Fprintln(writer, "\n"+divider)
|
||||||
|
|
||||||
|
for _, descriptor := range errors.Descriptors {
|
||||||
|
fmt.Fprint(writer, "|")
|
||||||
|
|
||||||
|
v := reflect.ValueOf(descriptor)
|
||||||
|
for i := 0; i < dtype.NumField(); i++ {
|
||||||
|
value := v.Field(i).Interface()
|
||||||
|
field := v.Type().Field(i)
|
||||||
|
if field.Name == "Value" {
|
||||||
|
continue
|
||||||
|
} else if field.Name == "Description" {
|
||||||
|
value = strings.Replace(value.(string), "\n", " ", -1)
|
||||||
|
} else if field.Name == "Code" {
|
||||||
|
value = fmt.Sprintf("`%s`", value)
|
||||||
|
} else if field.Name == "HTTPStatusCodes" {
|
||||||
|
if len(value.([]int)) > 0 {
|
||||||
|
var codes []string
|
||||||
|
for _, code := range value.([]int) {
|
||||||
|
codes = append(codes, fmt.Sprint(code))
|
||||||
|
}
|
||||||
|
value = strings.Join(codes, ", ")
|
||||||
|
} else {
|
||||||
|
value = "Any"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(writer, value, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(writer, "\n")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue