workers: Backwards compatible api.openshift.com spec compliance
The main changes are: - Kind, Href, Id fields for every object returned - Attach operationIds to each request, return it for errors - Errors are predefined and queryable
This commit is contained in:
parent
5e206322a2
commit
2f328b0e97
14 changed files with 816 additions and 209 deletions
|
|
@ -4,29 +4,86 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/deepmap/oapi-codegen/pkg/runtime"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Error defines model for Error.
|
||||
type Error struct {
|
||||
Message string `json:"message"`
|
||||
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
|
||||
ObjectReference
|
||||
// Embedded fields due to inline allOf schema
|
||||
Code string `json:"code"`
|
||||
|
||||
// Backward compatibility with workers <= v33, equals reason
|
||||
Message string `json:"message"`
|
||||
OperationId string `json:"operation_id"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// RequestJobJSONBody defines parameters for RequestJob.
|
||||
type RequestJobJSONBody struct {
|
||||
// GetJobResponse defines model for GetJobResponse.
|
||||
type GetJobResponse struct {
|
||||
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
|
||||
ObjectReference
|
||||
// Embedded fields due to inline allOf schema
|
||||
Canceled bool `json:"canceled"`
|
||||
}
|
||||
|
||||
// ObjectReference defines model for ObjectReference.
|
||||
type ObjectReference struct {
|
||||
Href string `json:"href"`
|
||||
Id string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
// RequestJobRequest defines model for RequestJobRequest.
|
||||
type RequestJobRequest struct {
|
||||
Arch string `json:"arch"`
|
||||
Types []string `json:"types"`
|
||||
}
|
||||
|
||||
// UpdateJobJSONBody defines parameters for UpdateJob.
|
||||
type UpdateJobJSONBody struct {
|
||||
Result interface{} `json:"result"`
|
||||
Status string `json:"status"`
|
||||
// RequestJobResponse defines model for RequestJobResponse.
|
||||
type RequestJobResponse struct {
|
||||
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
|
||||
ObjectReference
|
||||
// Embedded fields due to inline allOf schema
|
||||
Args *json.RawMessage `json:"args,omitempty"`
|
||||
ArtifactLocation string `json:"artifact_location"`
|
||||
DynamicArgs *[]json.RawMessage `json:"dynamic_args,omitempty"`
|
||||
Location string `json:"location"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// StatusResponse defines model for StatusResponse.
|
||||
type StatusResponse struct {
|
||||
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
|
||||
ObjectReference
|
||||
// Embedded fields due to inline allOf schema
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// UpdateJobRequest defines model for UpdateJobRequest.
|
||||
type UpdateJobRequest struct {
|
||||
Result json.RawMessage `json:"result"`
|
||||
}
|
||||
|
||||
// UpdateJobResponse defines model for UpdateJobResponse.
|
||||
type UpdateJobResponse ObjectReference
|
||||
|
||||
// RequestJobJSONBody defines parameters for RequestJob.
|
||||
type RequestJobJSONBody RequestJobRequest
|
||||
|
||||
// UpdateJobJSONBody defines parameters for UpdateJob.
|
||||
type UpdateJobJSONBody UpdateJobRequest
|
||||
|
||||
// RequestJobRequestBody defines body for RequestJob for application/json ContentType.
|
||||
type RequestJobJSONRequestBody RequestJobJSONBody
|
||||
|
||||
|
|
@ -35,6 +92,9 @@ type UpdateJobJSONRequestBody UpdateJobJSONBody
|
|||
|
||||
// ServerInterface represents all server handlers.
|
||||
type ServerInterface interface {
|
||||
// Get error description
|
||||
// (GET /errors/{id})
|
||||
GetError(ctx echo.Context, id string) error
|
||||
// Request a job
|
||||
// (POST /jobs)
|
||||
RequestJob(ctx echo.Context) error
|
||||
|
|
@ -47,6 +107,9 @@ type ServerInterface interface {
|
|||
// Upload an artifact
|
||||
// (PUT /jobs/{token}/artifacts/{name})
|
||||
UploadJobArtifact(ctx echo.Context, token string, name string) error
|
||||
// Get the openapi spec in json format
|
||||
// (GET /openapi)
|
||||
GetOpenapi(ctx echo.Context) error
|
||||
// status
|
||||
// (GET /status)
|
||||
GetStatus(ctx echo.Context) error
|
||||
|
|
@ -57,6 +120,24 @@ type ServerInterfaceWrapper struct {
|
|||
Handler ServerInterface
|
||||
}
|
||||
|
||||
// GetError converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetError(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "id" -------------
|
||||
var id string
|
||||
|
||||
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set("Bearer.Scopes", []string{""})
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.GetError(ctx, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// RequestJob converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) RequestJob(ctx echo.Context) error {
|
||||
var err error
|
||||
|
|
@ -122,6 +203,15 @@ func (w *ServerInterfaceWrapper) UploadJobArtifact(ctx echo.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// GetOpenapi converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetOpenapi(ctx echo.Context) error {
|
||||
var err error
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.GetOpenapi(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetStatus converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetStatus(ctx echo.Context) error {
|
||||
var err error
|
||||
|
|
@ -153,10 +243,60 @@ func RegisterHandlers(router EchoRouter, si ServerInterface) {
|
|||
Handler: si,
|
||||
}
|
||||
|
||||
router.GET("/errors/:id", wrapper.GetError)
|
||||
router.POST("/jobs", wrapper.RequestJob)
|
||||
router.GET("/jobs/:token", wrapper.GetJob)
|
||||
router.PATCH("/jobs/:token", wrapper.UpdateJob)
|
||||
router.PUT("/jobs/:token/artifacts/:name", wrapper.UploadJobArtifact)
|
||||
router.GET("/openapi", wrapper.GetOpenapi)
|
||||
router.GET("/status", wrapper.GetStatus)
|
||||
|
||||
}
|
||||
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"H4sIAAAAAAAC/9xXTW/jNhD9KwTbo2I5TfcioIfNtlhkiyJF0kUXSINgTI0tJhKpDCknhqH/XvDDX5Ji",
|
||||
"Z4H4sDlZCcmZN2/eDIdLLnRVa4XKGp4tuREFVuA//yDS5D6gLC+nPLtZ8p8JpzzjP6WbQ2k8kV5O7lHY",
|
||||
"K5wioRLI22TJa9I1kpXoDQqdo/u1ixp5xo0lqWa8TXiFxsDMr+VoBMnaSq14xs9BPDwB5cz5AysnspR2",
|
||||
"wZ6kLdiTpgckw/5rxuMz8Rubn50lDB8bKA0jBKMVT/quHB5w1u9kPoglHu0v+bXHRhLmPLsJway3dwxv",
|
||||
"QrpdY9CeH97etgn/jPaLnlyhqbUy+KYcgxJY4nZsE61LBNWPYLV1GGPXV9Z1VXigAxS+wOyDVPlhXj17",
|
||||
"fmsSPPTRJfwKHxs0gUP/1UcHJIpBGO4ffoe0WJkXt/CMAxEsegDD+SQ4OATu7RMMNPO/zyczfRJ93xut",
|
||||
"Rlfw9FcUXevQWTkFYe9KLSBU00Cg+UJBJcXdyuiakgPWdwlK+F4n4R+H8u5XtywNhTAs1GsLtjHH4Np4",
|
||||
"y4exx33D8L7WOVjcJ1VC05T2IO0dp/HUkAK3XG5I+S4qnDOpprrfkv8ppGHSMFDs498XbKpp3YmtZhRi",
|
||||
"ZKByVoDKS2T3emJGrhVLWzqYl9fnjSxz9snBMEjshP3rDfCEz5FMcHMam7WCWvKMn43GozFPeA228Jyl",
|
||||
"6G4nky5l3rq/Z2j7WD+jQ8KkMtb1OqanzBbI/FFmahRyKjFnkwXzXWfdwi/ycDjcgM4rQYUWyXhR7Tq5",
|
||||
"+H3HLnfE8cwj5QlXULmgvf1N9iw1mMS71sHGZ6hqz87pWf/Wam/d2ZBJH/wv43G4T5VF5eOGui5lqJL0",
|
||||
"Pt5fG/P7Uh9ibH3Gf/327Sh2PxzFbptwg6IhaRc+LecIhMSzm1tHmGmqCmgRVRBSvp04dzx12vT1qM2A",
|
||||
"fGLBGgZOxCPmpb8WCZuUWjwY1igry7DF18UcZAmTEkc9RW0uhigGNPZc54s346Z/LQaaOuI5PYrD2Gm8",
|
||||
"w10ePxGCxZz/aArrxuE1s9HV1arXudRv9JQurX5Atd2Veo1lJYEj1XRnvBwI5fJP/kPW+05RU6OUVLNA",
|
||||
"f69LD3Rhn5i9jXig89ZgwyS5m8X1HXukWu6NDYOlPD6Gv3csmxAlg13tdEs3XY2eJl066fharhs7pIJS",
|
||||
"Q/5FTz7GE/w1OvQ/3yPD5O3k/DqtamHRnhhLCNUu6V2TL4ny3QnHJdpNkyttBNmsR9SXm/1l3PIanqI5",
|
||||
"P5wyqZjD7mbsCvxg/+EYg1+3yL8qfK5RWMzj2KSFaMjpq9+C3di7F7PjaPOMGpzSr6WbfVnYFV8NxJ4K",
|
||||
"KQpGaBtShhmkuRSrTUOz+vVq5WgdsvPOfI/tMdIbZ2uar3pYQyXPeAq1TMNjL52f+vfy1oKI77mTrR23",
|
||||
"7f8BAAD//yi1+mtgFAAA",
|
||||
}
|
||||
|
||||
// GetSwagger returns the Swagger specification corresponding to the generated code
|
||||
// in this file.
|
||||
func GetSwagger() (*openapi3.Swagger, error) {
|
||||
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
|
||||
}
|
||||
zr, err := gzip.NewReader(bytes.NewReader(zipped))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decompressing spec: %s", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_, err = buf.ReadFrom(zr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decompressing spec: %s", err)
|
||||
}
|
||||
|
||||
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading Swagger: %s", err)
|
||||
}
|
||||
return swagger, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -package=api -generate types,server -o api.gen.go openapi.yml
|
||||
//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -package=api -generate types,server,spec -o api.gen.go openapi.yml
|
||||
|
||||
package api
|
||||
|
||||
|
|
|
|||
186
internal/worker/api/errors.go
Normal file
186
internal/worker/api/errors.go
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorCodePrefix = "COMPOSER-WORKER-"
|
||||
ErrorHREF = "/api/composer-worker/v1/errors"
|
||||
|
||||
ErrorUnsupportedMediaType ServiceErrorCode = 3
|
||||
ErrorJobNotFound ServiceErrorCode = 5
|
||||
ErrorJobNotRunning ServiceErrorCode = 6
|
||||
ErrorMalformedJobId ServiceErrorCode = 7
|
||||
ErrorMalformedJobToken ServiceErrorCode = 8
|
||||
ErrorInvalidErrorId ServiceErrorCode = 9
|
||||
ErrorBodyDecodingError ServiceErrorCode = 10
|
||||
ErrorResourceNotFound ServiceErrorCode = 11
|
||||
ErrorMethodNotAllowed ServiceErrorCode = 12
|
||||
ErrorNotAcceptable ServiceErrorCode = 13
|
||||
ErrorErrorNotFound ServiceErrorCode = 14
|
||||
// ErrorTokenNotFound ServiceErrorCode = 6
|
||||
|
||||
// internal errors
|
||||
ErrorDiscardingArtifact ServiceErrorCode = 1000
|
||||
ErrorCreatingArtifact ServiceErrorCode = 1001
|
||||
ErrorWritingArtifact ServiceErrorCode = 1002
|
||||
ErrorResolvingJobId ServiceErrorCode = 1003
|
||||
ErrorFinishingJob ServiceErrorCode = 1004
|
||||
ErrorRetrievingJobStatus ServiceErrorCode = 1005
|
||||
ErrorRequestingJob ServiceErrorCode = 1006
|
||||
ErrorFailedLoadingOpenAPISpec ServiceErrorCode = 1007
|
||||
|
||||
// Errors contained within this file
|
||||
ErrorUnspecified ServiceErrorCode = 10000
|
||||
ErrorNotHTTPError ServiceErrorCode = 10001
|
||||
ErrorServiceErrorNotFound ServiceErrorCode = 10002
|
||||
ErrorMalformedOperationID ServiceErrorCode = 10003
|
||||
)
|
||||
|
||||
type ServiceErrorCode int
|
||||
|
||||
type serviceError struct {
|
||||
code ServiceErrorCode
|
||||
httpStatus int
|
||||
reason string
|
||||
}
|
||||
|
||||
type serviceErrors []serviceError
|
||||
|
||||
func getServiceErrors() serviceErrors {
|
||||
return serviceErrors{
|
||||
serviceError{ErrorUnsupportedMediaType, http.StatusUnsupportedMediaType, "Only 'application/json' content is supported"},
|
||||
serviceError{ErrorBodyDecodingError, http.StatusBadRequest, "Malformed json, unable to decode body"},
|
||||
|
||||
serviceError{ErrorJobNotFound, http.StatusNotFound, "Token not found"},
|
||||
serviceError{ErrorJobNotRunning, http.StatusBadRequest, "Job is not running"},
|
||||
serviceError{ErrorMalformedJobId, http.StatusBadRequest, "Given job id is not a uuidv4"},
|
||||
serviceError{ErrorMalformedJobToken, http.StatusBadRequest, "Given job id is not a uuidv4"},
|
||||
|
||||
serviceError{ErrorDiscardingArtifact, http.StatusInternalServerError, "Error discarding artifact"},
|
||||
serviceError{ErrorCreatingArtifact, http.StatusInternalServerError, "Error creating artifact"},
|
||||
serviceError{ErrorWritingArtifact, http.StatusInternalServerError, "Error writing artifact"},
|
||||
serviceError{ErrorResolvingJobId, http.StatusInternalServerError, "Error resolving id from job token"},
|
||||
serviceError{ErrorFinishingJob, http.StatusInternalServerError, "Error finishing job"},
|
||||
serviceError{ErrorRetrievingJobStatus, http.StatusInternalServerError, "Error requesting job"},
|
||||
serviceError{ErrorRequestingJob, http.StatusInternalServerError, "Error requesting job"},
|
||||
serviceError{ErrorInvalidErrorId, http.StatusBadRequest, "Invalid format for error id, it should be an integer as a string"},
|
||||
serviceError{ErrorFailedLoadingOpenAPISpec, http.StatusInternalServerError, "Unable to load openapi spec"},
|
||||
serviceError{ErrorResourceNotFound, http.StatusNotFound, "Requested resource doesn't exist"},
|
||||
serviceError{ErrorMethodNotAllowed, http.StatusMethodNotAllowed, "Requested method isn't supported for resource"},
|
||||
serviceError{ErrorNotAcceptable, http.StatusNotAcceptable, "Only 'application/json' content is supported"},
|
||||
serviceError{ErrorErrorNotFound, http.StatusNotFound, "Error with given id not found"},
|
||||
|
||||
serviceError{ErrorUnspecified, http.StatusInternalServerError, "Unspecified internal error "},
|
||||
serviceError{ErrorNotHTTPError, http.StatusInternalServerError, "Error is not an instance of HTTPError"},
|
||||
serviceError{ErrorServiceErrorNotFound, http.StatusInternalServerError, "Error does not exist"},
|
||||
serviceError{ErrorMalformedOperationID, http.StatusInternalServerError, "OperationID is empty or is not a string"},
|
||||
}
|
||||
}
|
||||
|
||||
func find(code ServiceErrorCode) *serviceError {
|
||||
for _, e := range getServiceErrors() {
|
||||
if e.code == code {
|
||||
return &e
|
||||
}
|
||||
}
|
||||
return &serviceError{ErrorServiceErrorNotFound, http.StatusInternalServerError, "Error does not exist"}
|
||||
}
|
||||
|
||||
// Make an echo compatible error out of a service error
|
||||
func HTTPError(code ServiceErrorCode) error {
|
||||
return HTTPErrorWithInternal(code, nil)
|
||||
}
|
||||
|
||||
// echo.HTTPError has a message interface{} field, which can be used to include the ServiceErrorCode
|
||||
func HTTPErrorWithInternal(code ServiceErrorCode, internalErr error) error {
|
||||
se := find(code)
|
||||
he := echo.NewHTTPError(se.httpStatus, se.code)
|
||||
if internalErr != nil {
|
||||
he.Internal = internalErr
|
||||
}
|
||||
return he
|
||||
}
|
||||
|
||||
// Convert a ServiceErrorCode into an Error as defined in openapi.v2.yml
|
||||
// serviceError is optional, prevents multiple find() calls
|
||||
func APIError(code ServiceErrorCode, serviceError *serviceError, c echo.Context) *Error {
|
||||
se := serviceError
|
||||
if se == nil {
|
||||
se = find(code)
|
||||
}
|
||||
|
||||
operationID, ok := c.Get("operationID").(string)
|
||||
if !ok || operationID == "" {
|
||||
c.Logger().Errorf("Couldn't find operationID handling error %v", code)
|
||||
se = find(ErrorMalformedOperationID)
|
||||
}
|
||||
|
||||
return &Error{
|
||||
ObjectReference: ObjectReference{
|
||||
Href: fmt.Sprintf("%s/%d", ErrorHREF, se.code),
|
||||
Id: fmt.Sprintf("%d", se.code),
|
||||
Kind: "Error",
|
||||
},
|
||||
Code: fmt.Sprintf("%s%d", ErrorCodePrefix, se.code),
|
||||
OperationId: operationID, // set operation id from context
|
||||
Reason: se.reason,
|
||||
Message: se.reason, // backward compatibility
|
||||
}
|
||||
}
|
||||
|
||||
func apiErrorFromEchoError(echoError *echo.HTTPError) ServiceErrorCode {
|
||||
switch echoError.Code {
|
||||
case http.StatusNotFound:
|
||||
return ErrorResourceNotFound
|
||||
case http.StatusMethodNotAllowed:
|
||||
return ErrorMethodNotAllowed
|
||||
case http.StatusNotAcceptable:
|
||||
return ErrorNotAcceptable
|
||||
default:
|
||||
return ErrorUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an echo error into an AOC compliant one so we send a correct json error response
|
||||
func HTTPErrorHandler(echoError error, c echo.Context) {
|
||||
doResponse := func(code ServiceErrorCode, c echo.Context) {
|
||||
if !c.Response().Committed {
|
||||
var err error
|
||||
sec := find(code)
|
||||
apiErr := APIError(code, sec, c)
|
||||
|
||||
if sec.httpStatus == http.StatusInternalServerError {
|
||||
c.Logger().Errorf("Internal server error. Code: %s, OperationId: %s",
|
||||
apiErr.Code, apiErr.OperationId)
|
||||
}
|
||||
|
||||
if c.Request().Method == http.MethodHead {
|
||||
err = c.NoContent(sec.httpStatus)
|
||||
} else {
|
||||
err = c.JSON(sec.httpStatus, apiErr)
|
||||
}
|
||||
if err != nil {
|
||||
c.Logger().Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
he, ok := echoError.(*echo.HTTPError)
|
||||
if !ok {
|
||||
doResponse(ErrorNotHTTPError, c)
|
||||
return
|
||||
}
|
||||
|
||||
sec, ok := he.Message.(ServiceErrorCode)
|
||||
if !ok {
|
||||
// No service code was set, so Echo threw this error
|
||||
doResponse(apiErrorFromEchoError(he), c)
|
||||
return
|
||||
}
|
||||
doResponse(sec, c)
|
||||
}
|
||||
|
|
@ -5,105 +5,76 @@ info:
|
|||
description: This is an API for workers to request and handle jobs.
|
||||
servers:
|
||||
- url: /api/worker/v1
|
||||
- url: /api/composer-worker/v1
|
||||
|
||||
paths:
|
||||
/openapi:
|
||||
get:
|
||||
operationId: getOpenapi
|
||||
summary: Get the openapi spec in json format
|
||||
responses:
|
||||
'200':
|
||||
description: openapi spec in json format
|
||||
'500':
|
||||
description: Unexpected error occurred
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/status:
|
||||
get:
|
||||
operationId: GetStatus
|
||||
summary: status
|
||||
tags: []
|
||||
description: Simple status handler which returns service status
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
headers: {}
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- OK
|
||||
required:
|
||||
- status
|
||||
4XX:
|
||||
$ref: '#/components/schemas/StatusResponse'
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
5XX:
|
||||
description: ''
|
||||
'5XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
operationId: GetStatus
|
||||
description: Simple status handler to check whether the service is up.
|
||||
|
||||
/jobs:
|
||||
post:
|
||||
operationId: RequestJob
|
||||
summary: Request a job
|
||||
tags: []
|
||||
description: Requests a job. This operation blocks until a job is available.
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RequestJobRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
location:
|
||||
type: string
|
||||
artifact_location:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- osbuild
|
||||
args: {}
|
||||
dynamic_args:
|
||||
type: array
|
||||
items: {}
|
||||
required:
|
||||
- type
|
||||
- location
|
||||
- id
|
||||
4XX:
|
||||
$ref: '#/components/schemas/RequestJobResponse'
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
5XX:
|
||||
'5XX':
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
operationId: RequestJob
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
types:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- osbuild
|
||||
arch:
|
||||
type: string
|
||||
required:
|
||||
- types
|
||||
- arch
|
||||
description: ''
|
||||
description: Requests a job. This operation blocks until a job is available.
|
||||
parameters: []
|
||||
'/jobs/{token}':
|
||||
|
||||
/jobs/{token}:
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
|
|
@ -111,98 +82,212 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
get:
|
||||
operationId: GetJob
|
||||
summary: Get running job
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
canceled:
|
||||
type: boolean
|
||||
required:
|
||||
- canceled
|
||||
4XX:
|
||||
description: ''
|
||||
$ref: '#/components/schemas/GetJobResponse'
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
5XX:
|
||||
description: ''
|
||||
'5XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
operationId: GetJob
|
||||
description: ''
|
||||
patch:
|
||||
summary: Update a running job
|
||||
tags: []
|
||||
responses: {}
|
||||
operationId: UpdateJob
|
||||
summary: Update a running job
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- WAITING
|
||||
- RUNNING
|
||||
- FINISHED
|
||||
- FAILED
|
||||
result: {}
|
||||
required:
|
||||
- status
|
||||
- result
|
||||
'/jobs/{token}/artifacts/{name}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: name
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: token
|
||||
in: path
|
||||
required: true
|
||||
put:
|
||||
summary: Upload an artifact
|
||||
tags: []
|
||||
$ref: '#/components/schemas/UpdateJobRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
4XX:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateJobResponse'
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
5XX:
|
||||
description: ''
|
||||
'5XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/jobs/{token}/artifacts/{name}:
|
||||
put:
|
||||
operationId: UploadJobArtifact
|
||||
summary: Upload an artifact
|
||||
requestBody:
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: name
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: token
|
||||
in: path
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'5XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/errors/{id}:
|
||||
get:
|
||||
operationId: getError
|
||||
summary: Get error description
|
||||
description: Get an instance of the error specified by id
|
||||
security:
|
||||
- Bearer: []
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
example: '13'
|
||||
required: true
|
||||
description: ID of the error
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'4XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'5XX':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Error:
|
||||
title: Error
|
||||
ObjectReference:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
required:
|
||||
- message
|
||||
- id
|
||||
- kind
|
||||
- href
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
href:
|
||||
type: string
|
||||
|
||||
Error:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ObjectReference'
|
||||
- type: object
|
||||
required:
|
||||
- code
|
||||
- reason
|
||||
- operation_id
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
reason:
|
||||
type: string
|
||||
operation_id:
|
||||
type: string
|
||||
message:
|
||||
description: Backward compatibility with workers <= v33, equals reason
|
||||
type: string
|
||||
|
||||
StatusResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ObjectReference'
|
||||
- type: object
|
||||
required:
|
||||
- status
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
|
||||
RequestJobRequest:
|
||||
type: object
|
||||
required:
|
||||
- types
|
||||
- arch
|
||||
properties:
|
||||
types:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
arch:
|
||||
type: string
|
||||
RequestJobResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ObjectReference'
|
||||
- type: object
|
||||
required:
|
||||
- type
|
||||
- location
|
||||
- artifact_location
|
||||
properties:
|
||||
location:
|
||||
type: string
|
||||
artifact_location:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
args:
|
||||
x-go-type: json.RawMessage
|
||||
dynamic_args:
|
||||
type: array
|
||||
items:
|
||||
x-go-type: json.RawMessage
|
||||
|
||||
GetJobResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ObjectReference'
|
||||
- type: object
|
||||
required:
|
||||
- canceled
|
||||
properties:
|
||||
canceled:
|
||||
type: boolean
|
||||
UpdateJobRequest:
|
||||
type: object
|
||||
required:
|
||||
- result
|
||||
properties:
|
||||
result:
|
||||
x-go-type: json.RawMessage
|
||||
UpdateJobResponse:
|
||||
$ref: '#/components/schemas/ObjectReference'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue