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.
|
||||
Description string
|
||||
|
||||
// DefaultStatusCode should to be returned via the HTTP API. Some error
|
||||
// may have different status codes depending on the situation.
|
||||
DefaultStatusCode int
|
||||
// HTTPStatusCodes provides a list of status under which this error
|
||||
// condition may arise. If it is empty, the error condition may be seen
|
||||
// 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,
|
||||
Value: "UNKNOWN",
|
||||
Message: "unknown error",
|
||||
Description: `Generic error returned when the error does not have an
|
||||
API classification.`,
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeDigestInvalid,
|
||||
|
@ -40,7 +45,7 @@ var descriptors = []ErrorDescriptor{
|
|||
include a detail structure with the key "digest", including the
|
||||
invalid digest string. This error may also be returned when a manifest
|
||||
includes an invalid layer digest.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeSizeInvalid,
|
||||
|
@ -49,7 +54,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Description: `When a layer is uploaded, the provided size will be
|
||||
checked against the uploaded content. If they do not match, this error
|
||||
will be returned.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeNameInvalid,
|
||||
|
@ -57,7 +62,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "manifest name did not match URI",
|
||||
Description: `During a manifest upload, if the name in the manifest
|
||||
does not match the uri name, this error will be returned.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeTagInvalid,
|
||||
|
@ -65,7 +70,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "manifest tag did not match URI",
|
||||
Description: `During a manifest upload, if the tag in the manifest
|
||||
does not match the uri tag, this error will be returned.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeNameUnknown,
|
||||
|
@ -73,7 +78,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "repository name not known to registry",
|
||||
Description: `This is returned if the name used during an operation is
|
||||
unknown to the registry.`,
|
||||
DefaultStatusCode: http.StatusNotFound,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestUnknown,
|
||||
|
@ -81,7 +86,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "manifest unknown",
|
||||
Description: `This error is returned when the manifest, identified by
|
||||
name and tag is unknown to the repository.`,
|
||||
DefaultStatusCode: http.StatusNotFound,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestInvalid,
|
||||
|
@ -89,8 +94,9 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "manifest invalid",
|
||||
Description: `During upload, manifests undergo several checks ensuring
|
||||
validity. If those checks fail, this error may be returned, unless a
|
||||
more specific error is included.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
more specific error is included. The detail will contain information
|
||||
the failed validation.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestUnverified,
|
||||
|
@ -98,7 +104,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "manifest failed signature verification",
|
||||
Description: `During manifest upload, if the manifest fails signature
|
||||
verification, this error will be returned.`,
|
||||
DefaultStatusCode: http.StatusBadRequest,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeBlobUnknown,
|
||||
|
@ -108,7 +114,7 @@ var descriptors = []ErrorDescriptor{
|
|||
registry in a specified repository. This can be returned with a
|
||||
standard get or if a manifest references an unknown layer during
|
||||
upload.`,
|
||||
DefaultStatusCode: http.StatusNotFound,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -117,7 +123,7 @@ var descriptors = []ErrorDescriptor{
|
|||
Message: "blob upload unknown to registry",
|
||||
Description: `If a blob upload has been cancelled or was never
|
||||
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
|
||||
|
||||
func init() {
|
||||
errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(descriptors))
|
||||
idToDescriptors = make(map[string]ErrorDescriptor, len(descriptors))
|
||||
errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(Descriptors))
|
||||
idToDescriptors = make(map[string]ErrorDescriptor, len(Descriptors))
|
||||
|
||||
for _, descriptor := range descriptors {
|
||||
for _, descriptor := range Descriptors {
|
||||
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||
idToDescriptors[descriptor.Value] = descriptor
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
// TestErrorCodes ensures that error code format, mappings and
|
||||
// marshaling/unmarshaling. round trips are stable.
|
||||
func TestErrorCodes(t *testing.T) {
|
||||
for _, desc := range descriptors {
|
||||
for _, desc := range Descriptors {
|
||||
if 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