/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "fmt" "net/http" "sort" "sync" ) var ( errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{} idToDescriptors = map[string]ErrorDescriptor{} groupToDescriptors = map[string][]ErrorDescriptor{} ) var ( // ErrorCodeUnknown is a generic error that can be used as a last // resort if there is no situation-specific error message that can be used ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ Value: "UNKNOWN", Message: "unknown error", Description: `Generic error returned when the error does not have an API classification.`, HTTPStatusCode: http.StatusInternalServerError, }) // ErrorCodeUnsupported is returned when an operation is not supported. ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{ Value: "UNSUPPORTED", Message: "The operation is unsupported.", Description: `The operation was unsupported due to a missing implementation or invalid set of parameters.`, HTTPStatusCode: http.StatusMethodNotAllowed, }) // ErrorCodeUnauthorized is returned if a request requires // authentication. ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ Value: "UNAUTHORIZED", Message: "authentication required", Description: `The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate.`, HTTPStatusCode: http.StatusUnauthorized, }) // ErrorCodeDenied is returned if a client does not have sufficient // permission to perform an action. ErrorCodeDenied = Register("errcode", ErrorDescriptor{ Value: "DENIED", Message: "requested access to the resource is denied", Description: `The access controller denied access for the operation on a resource.`, HTTPStatusCode: http.StatusForbidden, }) // ErrorCodeUnavailable provides a common error to report unavailability // of a service or endpoint. ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ Value: "UNAVAILABLE", Message: "service unavailable", Description: "Returned when a service is not available", HTTPStatusCode: http.StatusServiceUnavailable, }) // ErrorCodeTooManyRequests is returned if a client attempts too many // times to contact a service endpoint. ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{ Value: "TOOMANYREQUESTS", Message: "too many requests", Description: `Returned when a client attempts to contact a service too many times`, HTTPStatusCode: http.StatusTooManyRequests, }) ) var nextCode = 1000 var registerLock sync.Mutex // Register will make the passed-in error known to the environment and // return a new ErrorCode func Register(group string, descriptor ErrorDescriptor) ErrorCode { registerLock.Lock() defer registerLock.Unlock() descriptor.Code = ErrorCode(nextCode) if _, ok := idToDescriptors[descriptor.Value]; ok { panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value)) } if _, ok := errorCodeToDescriptors[descriptor.Code]; ok { panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code)) } groupToDescriptors[group] = append(groupToDescriptors[group], descriptor) errorCodeToDescriptors[descriptor.Code] = descriptor idToDescriptors[descriptor.Value] = descriptor nextCode++ return descriptor.Code } type byValue []ErrorDescriptor func (a byValue) Len() int { return len(a) } func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value } // GetGroupNames returns the list of Error group names that are registered func GetGroupNames() []string { keys := []string{} for k := range groupToDescriptors { keys = append(keys, k) } sort.Strings(keys) return keys } // GetErrorCodeGroup returns the named group of error descriptors func GetErrorCodeGroup(name string) []ErrorDescriptor { desc := groupToDescriptors[name] sort.Sort(byValue(desc)) return desc } // GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are // registered, irrespective of what group they're in func GetErrorAllDescriptors() []ErrorDescriptor { result := []ErrorDescriptor{} for _, group := range GetGroupNames() { result = append(result, GetErrorCodeGroup(group)...) } sort.Sort(byValue(result)) return result }