// NewMethodNotSupported returns an error indicating the requested action is not supported on this kind. func NewMethodNotSupported(qualifiedResource unversioned.GroupResource, action string) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusMethodNotAllowed, Reason: unversioned.StatusReasonMethodNotAllowed, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, }, Message: fmt.Sprintf("%s is not supported on resources of kind %q", action, qualifiedResource.String()), }} }
// NewNotFound returns a new error which indicates that the resource of the kind and the name was not found. func NewNotFound(qualifiedResource unversioned.GroupResource, name string) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusNotFound, Reason: unversioned.StatusReasonNotFound, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: name, }, Message: fmt.Sprintf("%s %q not found", qualifiedResource.String(), name), }} }
// NewConflict returns an error indicating the item can't be updated as provided. func NewConflict(qualifiedResource unversioned.GroupResource, name string, err error) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusConflict, Reason: unversioned.StatusReasonConflict, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: name, }, Message: fmt.Sprintf("Operation cannot be fulfilled on %s %q: %v", qualifiedResource.String(), name, err), }} }
// NewForbidden returns an error indicating the requested action was forbidden func NewForbidden(qualifiedResource unversioned.GroupResource, name string, err error) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusForbidden, Reason: unversioned.StatusReasonForbidden, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: name, }, Message: fmt.Sprintf("%s %q is forbidden: %v", qualifiedResource.String(), name, err), }} }
// NewAlreadyExists returns an error indicating the item requested exists by that identifier. func NewAlreadyExists(qualifiedResource unversioned.GroupResource, name string) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusConflict, Reason: unversioned.StatusReasonAlreadyExists, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: name, }, Message: fmt.Sprintf("%s %q already exists", qualifiedResource.String(), name), }} }
func (g *configRESTOptionsGetter) GetRESTOptions(resource unversioned.GroupResource) (genericrest.RESTOptions, error) { g.restOptionsLock.Lock() defer g.restOptionsLock.Unlock() if resourceOptions, ok := g.restOptionsMap[resource]; ok { return resourceOptions, nil } if g.etcdHelper == nil { // TODO: choose destination etcd based on input resource etcdClient, err := etcd.MakeNewEtcdClient(g.masterOptions.EtcdClientInfo) if err != nil { return genericrest.RESTOptions{}, err } // TODO: choose destination group/version based on input group/resource // TODO: Tune the cache size groupVersion := unversioned.GroupVersion{Group: "", Version: g.masterOptions.EtcdStorageConfig.OpenShiftStorageVersion} g.etcdHelper = etcdstorage.NewEtcdStorage(etcdClient, kapi.Codecs.LegacyCodec(groupVersion), g.masterOptions.EtcdStorageConfig.OpenShiftStoragePrefix, false, genericapiserver.DefaultDeserializationCacheSize) } configuredCacheSize, specified := g.cacheSizes[resource] if !specified || configuredCacheSize < 0 { configuredCacheSize = g.defaultCacheSize } decorator := func(s storage.Interface, requestedSize int, objectType runtime.Object, resourcePrefix string, scopeStrategy rest.NamespaceScopedStrategy, newListFunc func() runtime.Object) storage.Interface { capacity := requestedSize if capacity == UseConfiguredCacheSize { capacity = configuredCacheSize } if capacity == 0 || !g.cacheEnabled { glog.V(5).Infof("using uncached watch storage for %s", resource.String()) return genericrest.UndecoratedStorage(s, capacity, objectType, resourcePrefix, scopeStrategy, newListFunc) } else { glog.V(5).Infof("using watch cache storage (capacity=%d) for %s", capacity, resource.String()) return registry.StorageWithCacher(s, capacity, objectType, resourcePrefix, scopeStrategy, newListFunc) } } resourceOptions := genericrest.RESTOptions{ Storage: g.etcdHelper, Decorator: decorator, DeleteCollectionWorkers: 1, } g.restOptionsMap[resource] = resourceOptions return resourceOptions, nil }
func (g *configRESTOptionsGetter) GetRESTOptions(resource unversioned.GroupResource) (genericrest.RESTOptions, error) { g.restOptionsLock.Lock() defer g.restOptionsLock.Unlock() if resourceOptions, ok := g.restOptionsMap[resource]; ok { return resourceOptions, nil } config, err := g.storageFactory.NewConfig(resource) if err != nil { return genericrest.RESTOptions{}, err } if _, ok := g.quorumResources[resource]; ok { config.Quorum = true } configuredCacheSize, specified := g.cacheSizes[resource] if !specified || configuredCacheSize < 0 { configuredCacheSize = g.defaultCacheSize } decorator := func(s *storagebackend.Config, requestedSize int, objectType runtime.Object, resourcePrefix string, scopeStrategy rest.NamespaceScopedStrategy, newListFn func() runtime.Object, triggerFn storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) { capacity := requestedSize if capacity == UseConfiguredCacheSize { capacity = configuredCacheSize } if capacity == 0 || !g.cacheEnabled { glog.V(5).Infof("using uncached watch storage for %s", resource.String()) return genericrest.UndecoratedStorage(s, capacity, objectType, resourcePrefix, scopeStrategy, newListFn, triggerFn) } glog.V(5).Infof("using watch cache storage (capacity=%d) for %s %#v", capacity, resource.String(), s) return registry.StorageWithCacher(s, capacity, objectType, resourcePrefix, scopeStrategy, newListFn, triggerFn) } resourceOptions := genericrest.RESTOptions{ StorageConfig: config, Decorator: decorator, DeleteCollectionWorkers: 1, ResourcePrefix: g.storageFactory.ResourcePrefix(resource), } g.restOptionsMap[resource] = resourceOptions return resourceOptions, nil }
// TODO: Move this upstream func printAutoscalingInfo(res unversioned.GroupResource, namespace, name string, kclient kclient.Interface, w *tabwriter.Writer) { hpaList, err := kclient.Autoscaling().HorizontalPodAutoscalers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()}) if err != nil { return } scaledBy := []autoscaling.HorizontalPodAutoscaler{} for _, hpa := range hpaList.Items { if hpa.Spec.ScaleTargetRef.Name == name && hpa.Spec.ScaleTargetRef.Kind == res.String() { scaledBy = append(scaledBy, hpa) } } for _, hpa := range scaledBy { cpuUtil := "" if hpa.Spec.TargetCPUUtilizationPercentage != nil { cpuUtil = fmt.Sprintf(", triggered at %d%% CPU usage", *hpa.Spec.TargetCPUUtilizationPercentage) } fmt.Fprintf(w, "Autoscaling:\tbetween %d and %d replicas%s\n", *hpa.Spec.MinReplicas, hpa.Spec.MaxReplicas, cpuUtil) // TODO: Print a warning in case of multiple hpas. // Related oc status PR: https://github.com/openshift/origin/pull/7799 break } }
// NewGenericServerResponse returns a new error for server responses that are not in a recognizable form. func NewGenericServerResponse(code int, verb string, qualifiedResource unversioned.GroupResource, name, serverMessage string, retryAfterSeconds int, isUnexpectedResponse bool) *StatusError { reason := unversioned.StatusReasonUnknown message := fmt.Sprintf("the server responded with the status code %d but did not return more information", code) switch code { case http.StatusConflict: if verb == "POST" { reason = unversioned.StatusReasonAlreadyExists } else { reason = unversioned.StatusReasonConflict } message = "the server reported a conflict" case http.StatusNotFound: reason = unversioned.StatusReasonNotFound message = "the server could not find the requested resource" case http.StatusBadRequest: reason = unversioned.StatusReasonBadRequest message = "the server rejected our request for an unknown reason" case http.StatusUnauthorized: reason = unversioned.StatusReasonUnauthorized message = "the server has asked for the client to provide credentials" case http.StatusForbidden: reason = unversioned.StatusReasonForbidden message = "the server does not allow access to the requested resource" case http.StatusMethodNotAllowed: reason = unversioned.StatusReasonMethodNotAllowed message = "the server does not allow this method on the requested resource" case StatusUnprocessableEntity: reason = unversioned.StatusReasonInvalid message = "the server rejected our request due to an error in our request" case StatusServerTimeout: reason = unversioned.StatusReasonServerTimeout message = "the server cannot complete the requested operation at this time, try again later" case StatusTooManyRequests: reason = unversioned.StatusReasonTimeout message = "the server has received too many requests and has asked us to try again later" default: if code >= 500 { reason = unversioned.StatusReasonInternalError message = fmt.Sprintf("an error on the server (%q) has prevented the request from succeeding", serverMessage) } } switch { case !qualifiedResource.Empty() && len(name) > 0: message = fmt.Sprintf("%s (%s %s %s)", message, strings.ToLower(verb), qualifiedResource.String(), name) case !qualifiedResource.Empty(): message = fmt.Sprintf("%s (%s %s)", message, strings.ToLower(verb), qualifiedResource.String()) } var causes []unversioned.StatusCause if isUnexpectedResponse { causes = []unversioned.StatusCause{ { Type: unversioned.CauseTypeUnexpectedServerResponse, Message: serverMessage, }, } } else { causes = nil } return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: int32(code), Reason: reason, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: name, Causes: causes, RetryAfterSeconds: int32(retryAfterSeconds), }, Message: message, }} }
// NewServerTimeout returns an error indicating the requested action could not be completed due to a // transient error, and the client should try again. func NewServerTimeout(qualifiedResource unversioned.GroupResource, operation string, retryAfterSeconds int) *StatusError { return &StatusError{unversioned.Status{ Status: unversioned.StatusFailure, Code: http.StatusInternalServerError, Reason: unversioned.StatusReasonServerTimeout, Details: &unversioned.StatusDetails{ Group: qualifiedResource.Group, Kind: qualifiedResource.Resource, Name: operation, RetryAfterSeconds: int32(retryAfterSeconds), }, Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, qualifiedResource.String()), }} }