From 176759624daf96cbf67d959c696a91b34ab5d25b Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 23 Jun 2025 21:16:01 -0400 Subject: [PATCH] better 429 messages for both share/enable when over limit --- controller/enable.go | 2 +- controller/share.go | 6 +- .../environment/enable_responses.go | 74 +++++++++++++++++++ rest_client_zrok/share/share_responses.go | 14 +++- rest_server_zrok/embedded_spec.go | 22 +++++- .../environment/enable_responses.go | 45 +++++++++++ .../operations/share/share_responses.go | 22 +++++- sdk/python/src/docs/EnvironmentApi.md | 1 + .../src/zrok_api/api/environment_api.py | 3 + sdk/python/src/zrok_api/api/share_api.py | 6 +- specs/zrok.yml | 6 ++ 11 files changed, 187 insertions(+), 14 deletions(-) diff --git a/controller/enable.go b/controller/enable.go index 06dca26d..1d395499 100644 --- a/controller/enable.go +++ b/controller/enable.go @@ -29,7 +29,7 @@ func (h *enableHandler) Handle(params environment.EnableParams, principal *rest_ if err := h.checkLimits(principal, trx); err != nil { logrus.Errorf("limits error for user '%v': %v", principal.Email, err) - return environment.NewEnableUnauthorized() + return environment.NewEnableTooManyRequests().WithPayload("too many environments; account limit exceeded") } client, err := zrokEdgeSdk.Client(cfg.Ziti) diff --git a/controller/share.go b/controller/share.go index 3ab4be10..df00bd68 100644 --- a/controller/share.go +++ b/controller/share.go @@ -23,8 +23,6 @@ func newShareHandler() *shareHandler { } func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zrok.Principal) middleware.Responder { - logrus.Info("handling") - trx, err := str.Begin() if err != nil { logrus.Errorf("error starting transaction: %v", err) @@ -40,7 +38,7 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr if err := h.checkLimits(envId, principal, params.Body.Reserved, params.Body.UniqueName != "", sdk.ShareMode(params.Body.ShareMode), sdk.BackendMode(params.Body.BackendMode), trx); err != nil { logrus.Errorf("limits error for '%v': %v", principal.Email, err) - return share.NewShareTooManyRequests() + return share.NewShareTooManyRequests().WithPayload("too many shares; account limit exceeded") } accessGrantAcctIds, err := h.processAccessGrants(params, principal, trx) @@ -51,7 +49,7 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr edge, err := zrokEdgeSdk.Client(cfg.Ziti) if err != nil { - logrus.Error(err) + logrus.Errorf("error getting ziti management client: %v", err) return share.NewShareInternalServerError() } diff --git a/rest_client_zrok/environment/enable_responses.go b/rest_client_zrok/environment/enable_responses.go index e846e122..738bb6f7 100644 --- a/rest_client_zrok/environment/enable_responses.go +++ b/rest_client_zrok/environment/enable_responses.go @@ -13,6 +13,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + + "github.com/openziti/zrok/rest_model_zrok" ) // EnableReader is a Reader for the Enable structure. @@ -41,6 +43,12 @@ func (o *EnableReader) ReadResponse(response runtime.ClientResponse, consumer ru return nil, err } return nil, result + case 429: + result := NewEnableTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result case 500: result := NewEnableInternalServerError() if err := result.readResponse(response, consumer, o.formats); err != nil { @@ -232,6 +240,72 @@ func (o *EnableNotFound) readResponse(response runtime.ClientResponse, consumer return nil } +// NewEnableTooManyRequests creates a EnableTooManyRequests with default headers values +func NewEnableTooManyRequests() *EnableTooManyRequests { + return &EnableTooManyRequests{} +} + +/* +EnableTooManyRequests describes a response with status code 429, with default header values. + +over limit +*/ +type EnableTooManyRequests struct { + Payload rest_model_zrok.ErrorMessage +} + +// IsSuccess returns true when this enable too many requests response has a 2xx status code +func (o *EnableTooManyRequests) IsSuccess() bool { + return false +} + +// IsRedirect returns true when this enable too many requests response has a 3xx status code +func (o *EnableTooManyRequests) IsRedirect() bool { + return false +} + +// IsClientError returns true when this enable too many requests response has a 4xx status code +func (o *EnableTooManyRequests) IsClientError() bool { + return true +} + +// IsServerError returns true when this enable too many requests response has a 5xx status code +func (o *EnableTooManyRequests) IsServerError() bool { + return false +} + +// IsCode returns true when this enable too many requests response a status code equal to that given +func (o *EnableTooManyRequests) IsCode(code int) bool { + return code == 429 +} + +// Code gets the status code for the enable too many requests response +func (o *EnableTooManyRequests) Code() int { + return 429 +} + +func (o *EnableTooManyRequests) Error() string { + return fmt.Sprintf("[POST /enable][%d] enableTooManyRequests %+v", 429, o.Payload) +} + +func (o *EnableTooManyRequests) String() string { + return fmt.Sprintf("[POST /enable][%d] enableTooManyRequests %+v", 429, o.Payload) +} + +func (o *EnableTooManyRequests) GetPayload() rest_model_zrok.ErrorMessage { + return o.Payload +} + +func (o *EnableTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + // NewEnableInternalServerError creates a EnableInternalServerError with default headers values func NewEnableInternalServerError() *EnableInternalServerError { return &EnableInternalServerError{} diff --git a/rest_client_zrok/share/share_responses.go b/rest_client_zrok/share/share_responses.go index 46c170ac..58a04ffa 100644 --- a/rest_client_zrok/share/share_responses.go +++ b/rest_client_zrok/share/share_responses.go @@ -373,6 +373,7 @@ ShareTooManyRequests describes a response with status code 429, with default hea over limit */ type ShareTooManyRequests struct { + Payload rest_model_zrok.ErrorMessage } // IsSuccess returns true when this share too many requests response has a 2xx status code @@ -406,15 +407,24 @@ func (o *ShareTooManyRequests) Code() int { } func (o *ShareTooManyRequests) Error() string { - return fmt.Sprintf("[POST /share][%d] shareTooManyRequests ", 429) + return fmt.Sprintf("[POST /share][%d] shareTooManyRequests %+v", 429, o.Payload) } func (o *ShareTooManyRequests) String() string { - return fmt.Sprintf("[POST /share][%d] shareTooManyRequests ", 429) + return fmt.Sprintf("[POST /share][%d] shareTooManyRequests %+v", 429, o.Payload) +} + +func (o *ShareTooManyRequests) GetPayload() rest_model_zrok.ErrorMessage { + return o.Payload } func (o *ShareTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + return nil } diff --git a/rest_server_zrok/embedded_spec.go b/rest_server_zrok/embedded_spec.go index cf402b88..5222816d 100644 --- a/rest_server_zrok/embedded_spec.go +++ b/rest_server_zrok/embedded_spec.go @@ -1020,6 +1020,12 @@ func init() { "404": { "description": "account not found" }, + "429": { + "description": "over limit", + "schema": { + "$ref": "#/definitions/errorMessage" + } + }, "500": { "description": "internal server error" } @@ -2299,7 +2305,10 @@ func init() { "description": "unprocessable" }, "429": { - "description": "over limit" + "description": "over limit", + "schema": { + "$ref": "#/definitions/errorMessage" + } }, "500": { "description": "internal server error", @@ -3970,6 +3979,12 @@ func init() { "404": { "description": "account not found" }, + "429": { + "description": "over limit", + "schema": { + "$ref": "#/definitions/errorMessage" + } + }, "500": { "description": "internal server error" } @@ -5198,7 +5213,10 @@ func init() { "description": "unprocessable" }, "429": { - "description": "over limit" + "description": "over limit", + "schema": { + "$ref": "#/definitions/errorMessage" + } }, "500": { "description": "internal server error", diff --git a/rest_server_zrok/operations/environment/enable_responses.go b/rest_server_zrok/operations/environment/enable_responses.go index ee8b7eb3..c53cc0c1 100644 --- a/rest_server_zrok/operations/environment/enable_responses.go +++ b/rest_server_zrok/operations/environment/enable_responses.go @@ -9,6 +9,8 @@ import ( "net/http" "github.com/go-openapi/runtime" + + "github.com/openziti/zrok/rest_model_zrok" ) // EnableCreatedCode is the HTTP code returned for type EnableCreated @@ -106,6 +108,49 @@ func (o *EnableNotFound) WriteResponse(rw http.ResponseWriter, producer runtime. rw.WriteHeader(404) } +// EnableTooManyRequestsCode is the HTTP code returned for type EnableTooManyRequests +const EnableTooManyRequestsCode int = 429 + +/* +EnableTooManyRequests over limit + +swagger:response enableTooManyRequests +*/ +type EnableTooManyRequests struct { + + /* + In: Body + */ + Payload rest_model_zrok.ErrorMessage `json:"body,omitempty"` +} + +// NewEnableTooManyRequests creates EnableTooManyRequests with default headers values +func NewEnableTooManyRequests() *EnableTooManyRequests { + + return &EnableTooManyRequests{} +} + +// WithPayload adds the payload to the enable too many requests response +func (o *EnableTooManyRequests) WithPayload(payload rest_model_zrok.ErrorMessage) *EnableTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the enable too many requests response +func (o *EnableTooManyRequests) SetPayload(payload rest_model_zrok.ErrorMessage) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *EnableTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + // EnableInternalServerErrorCode is the HTTP code returned for type EnableInternalServerError const EnableInternalServerErrorCode int = 500 diff --git a/rest_server_zrok/operations/share/share_responses.go b/rest_server_zrok/operations/share/share_responses.go index aeb0e90f..ceaed72f 100644 --- a/rest_server_zrok/operations/share/share_responses.go +++ b/rest_server_zrok/operations/share/share_responses.go @@ -167,6 +167,11 @@ ShareTooManyRequests over limit swagger:response shareTooManyRequests */ type ShareTooManyRequests struct { + + /* + In: Body + */ + Payload rest_model_zrok.ErrorMessage `json:"body,omitempty"` } // NewShareTooManyRequests creates ShareTooManyRequests with default headers values @@ -175,12 +180,25 @@ func NewShareTooManyRequests() *ShareTooManyRequests { return &ShareTooManyRequests{} } +// WithPayload adds the payload to the share too many requests response +func (o *ShareTooManyRequests) WithPayload(payload rest_model_zrok.ErrorMessage) *ShareTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the share too many requests response +func (o *ShareTooManyRequests) SetPayload(payload rest_model_zrok.ErrorMessage) { + o.Payload = payload +} + // WriteResponse to the client func (o *ShareTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { - rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses - rw.WriteHeader(429) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } } // ShareInternalServerErrorCode is the HTTP code returned for type ShareInternalServerError diff --git a/sdk/python/src/docs/EnvironmentApi.md b/sdk/python/src/docs/EnvironmentApi.md index a50ae1d3..2d6f1ec9 100644 --- a/sdk/python/src/docs/EnvironmentApi.md +++ b/sdk/python/src/docs/EnvironmentApi.md @@ -156,6 +156,7 @@ Name | Type | Description | Notes **201** | environment enabled | - | **401** | unauthorized | - | **404** | account not found | - | +**429** | over limit | - | **500** | internal server error | - | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/sdk/python/src/zrok_api/api/environment_api.py b/sdk/python/src/zrok_api/api/environment_api.py index 4495d736..1a22d149 100644 --- a/sdk/python/src/zrok_api/api/environment_api.py +++ b/sdk/python/src/zrok_api/api/environment_api.py @@ -365,6 +365,7 @@ class EnvironmentApi: '201': "CreateIdentity201Response", '401': None, '404': None, + '429': "str", '500': None, } response_data = self.api_client.call_api( @@ -434,6 +435,7 @@ class EnvironmentApi: '201': "CreateIdentity201Response", '401': None, '404': None, + '429': "str", '500': None, } response_data = self.api_client.call_api( @@ -503,6 +505,7 @@ class EnvironmentApi: '201': "CreateIdentity201Response", '401': None, '404': None, + '429': "str", '500': None, } response_data = self.api_client.call_api( diff --git a/sdk/python/src/zrok_api/api/share_api.py b/sdk/python/src/zrok_api/api/share_api.py index 79311bca..f376f51e 100644 --- a/sdk/python/src/zrok_api/api/share_api.py +++ b/sdk/python/src/zrok_api/api/share_api.py @@ -382,7 +382,7 @@ class ShareApi: '404': None, '409': None, '422': None, - '429': None, + '429': "str", '500': "str", } response_data = self.api_client.call_api( @@ -454,7 +454,7 @@ class ShareApi: '404': None, '409': None, '422': None, - '429': None, + '429': "str", '500': "str", } response_data = self.api_client.call_api( @@ -526,7 +526,7 @@ class ShareApi: '404': None, '409': None, '422': None, - '429': None, + '429': "str", '500': "str", } response_data = self.api_client.call_api( diff --git a/specs/zrok.yml b/specs/zrok.yml index 7310c204..6c5296a0 100644 --- a/specs/zrok.yml +++ b/specs/zrok.yml @@ -1026,6 +1026,10 @@ paths: description: unauthorized 404: description: account not found + 429: + description: over limit + schema: + $ref: "#/definitions/errorMessage" 500: description: internal server error @@ -1499,6 +1503,8 @@ paths: description: unprocessable 429: description: over limit + schema: + $ref: "#/definitions/errorMessage" 500: description: internal server error schema: