diff --git a/.golangci.yaml b/.golangci.yaml index ed1e5ac..2430123 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -21,6 +21,8 @@ linters: - goconst - perfsprint - mnd + - execinquery + - exportloopref linters-settings: gci: sections: diff --git a/go.mod b/go.mod index 8134457..7d17488 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/unikorn-cloud/core v0.1.85 github.com/unikorn-cloud/identity v0.2.45 - github.com/unikorn-cloud/region v0.1.46 + github.com/unikorn-cloud/region v0.1.47-rc1 go.opentelemetry.io/otel/sdk v1.31.0 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 diff --git a/go.sum b/go.sum index 367bb7a..7514651 100644 --- a/go.sum +++ b/go.sum @@ -137,8 +137,8 @@ github.com/unikorn-cloud/core v0.1.85 h1:S4B0nr0jhxF8SCsKyCRVwcx8+kJsI8fQVONLJDf github.com/unikorn-cloud/core v0.1.85/go.mod h1:wEKzCwAnIyTbo27l++Wl+gK95TAxMsFS3y3jbFB03aw= github.com/unikorn-cloud/identity v0.2.45 h1:YFmw3uunwdZMuYiimv4lfU6s7iTtYoc22xJqLTrlOVg= github.com/unikorn-cloud/identity v0.2.45/go.mod h1:WzNNv05ReDMLfWsOtq53uzhX2GU2nXDw76Bdsf3BPnM= -github.com/unikorn-cloud/region v0.1.46 h1:LzyrBRej40YeOMr54zL2emkrqY1ypgOyYG8hDledlCU= -github.com/unikorn-cloud/region v0.1.46/go.mod h1:cofPuJjseRKE95xAqNa23nSL7/+LDXOBxNIHwwODpys= +github.com/unikorn-cloud/region v0.1.47-rc1 h1:1cFLBF4npcAGiLYiG8o0AGS0h5xkBzvRLJn9Df9Xiao= +github.com/unikorn-cloud/region v0.1.47-rc1/go.mod h1:cofPuJjseRKE95xAqNa23nSL7/+LDXOBxNIHwwODpys= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/pkg/openapi/client.go b/pkg/openapi/client.go index 108500f..398df74 100644 --- a/pkg/openapi/client.go +++ b/pkg/openapi/client.go @@ -15,6 +15,7 @@ import ( "github.com/oapi-codegen/runtime" externalRef0 "github.com/unikorn-cloud/core/pkg/openapi" + externalRef1 "github.com/unikorn-cloud/region/pkg/openapi" ) // RequestEditorFn is the function signature for the RequestEditor callback function @@ -105,6 +106,12 @@ type ClientInterface interface { PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDWithBody(ctx context.Context, organizationID OrganizationIDParameter, projectID ProjectIDParameter, clusterID ClusterIDParameter, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterID(ctx context.Context, organizationID OrganizationIDParameter, projectID ProjectIDParameter, clusterID ClusterIDParameter, body PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors request + GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages request + GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) GetApiV1OrganizationsOrganizationIDClusters(ctx context.Context, organizationID OrganizationIDParameter, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -179,6 +186,30 @@ func (c *Client) PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClu return c.Client.Do(req) } +func (c *Client) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsRequest(c.Server, organizationID, regionID) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesRequest(c.Server, organizationID, regionID) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + // NewGetApiV1OrganizationsOrganizationIDClustersRequest generates requests for GetApiV1OrganizationsOrganizationIDClusters func NewGetApiV1OrganizationsOrganizationIDClustersRequest(server string, organizationID OrganizationIDParameter) (*http.Request, error) { var err error @@ -376,6 +407,88 @@ func NewPutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDReq return req, nil } +// NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsRequest generates requests for GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors +func NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsRequest(server string, organizationID OrganizationIDParameter, regionID RegionIDParameter) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "organizationID", runtime.ParamLocationPath, organizationID) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "regionID", runtime.ParamLocationPath, regionID) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/api/v1/organizations/%s/regions/%s/flavors", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesRequest generates requests for GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages +func NewGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesRequest(server string, organizationID OrganizationIDParameter, regionID RegionIDParameter) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "organizationID", runtime.ParamLocationPath, organizationID) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "regionID", runtime.ParamLocationPath, regionID) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/api/v1/organizations/%s/regions/%s/images", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -434,6 +547,12 @@ type ClientWithResponsesInterface interface { PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDWithBodyWithResponse(ctx context.Context, organizationID OrganizationIDParameter, projectID ProjectIDParameter, clusterID ClusterIDParameter, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDResponse, error) PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDWithResponse(ctx context.Context, organizationID OrganizationIDParameter, projectID ProjectIDParameter, clusterID ClusterIDParameter, body PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDJSONRequestBody, reqEditors ...RequestEditorFn) (*PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDResponse, error) + + // GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse request + GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse, error) + + // GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse request + GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse, error) } type GetApiV1OrganizationsOrganizationIDClustersResponse struct { @@ -542,6 +661,56 @@ func (r PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDRes return 0 } +type GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *externalRef1.FlavorsResponse + JSON400 *externalRef0.BadRequestResponse + JSON401 *externalRef0.UnauthorizedResponse + JSON500 *externalRef0.InternalServerErrorResponse +} + +// Status returns HTTPResponse.Status +func (r GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *externalRef1.ImagesResponse + JSON400 *externalRef0.BadRequestResponse + JSON401 *externalRef0.UnauthorizedResponse + JSON500 *externalRef0.InternalServerErrorResponse +} + +// Status returns HTTPResponse.Status +func (r GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + // GetApiV1OrganizationsOrganizationIDClustersWithResponse request returning *GetApiV1OrganizationsOrganizationIDClustersResponse func (c *ClientWithResponses) GetApiV1OrganizationsOrganizationIDClustersWithResponse(ctx context.Context, organizationID OrganizationIDParameter, reqEditors ...RequestEditorFn) (*GetApiV1OrganizationsOrganizationIDClustersResponse, error) { rsp, err := c.GetApiV1OrganizationsOrganizationIDClusters(ctx, organizationID, reqEditors...) @@ -594,6 +763,24 @@ func (c *ClientWithResponses) PutApiV1OrganizationsOrganizationIDProjectsProject return ParsePutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDResponse(rsp) } +// GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse request returning *GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse +func (c *ClientWithResponses) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse, error) { + rsp, err := c.GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(ctx, organizationID, regionID, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse(rsp) +} + +// GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse request returning *GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse +func (c *ClientWithResponses) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse(ctx context.Context, organizationID OrganizationIDParameter, regionID RegionIDParameter, reqEditors ...RequestEditorFn) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse, error) { + rsp, err := c.GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(ctx, organizationID, regionID, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse(rsp) +} + // ParseGetApiV1OrganizationsOrganizationIDClustersResponse parses an HTTP response from a GetApiV1OrganizationsOrganizationIDClustersWithResponse call func ParseGetApiV1OrganizationsOrganizationIDClustersResponse(rsp *http.Response) (*GetApiV1OrganizationsOrganizationIDClustersResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -823,3 +1010,97 @@ func ParsePutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterIDR return response, nil } + +// ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse parses an HTTP response from a GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse call +func ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse(rsp *http.Response) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest externalRef1.FlavorsResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest externalRef0.BadRequestResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest externalRef0.UnauthorizedResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest externalRef0.InternalServerErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse parses an HTTP response from a GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse call +func ParseGetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse(rsp *http.Response) (*GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest externalRef1.ImagesResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest externalRef0.BadRequestResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest externalRef0.UnauthorizedResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest externalRef0.InternalServerErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} diff --git a/pkg/openapi/config.yaml b/pkg/openapi/config.yaml index 0aa29e8..1327521 100644 --- a/pkg/openapi/config.yaml +++ b/pkg/openapi/config.yaml @@ -1,3 +1,5 @@ package: generated import-mapping: https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml: github.com/unikorn-cloud/core/pkg/openapi + https://raw.githubusercontent.com/unikorn-cloud/region/main/pkg/openapi/server.spec.yaml: github.com/unikorn-cloud/region/pkg/openapi + diff --git a/pkg/openapi/router.go b/pkg/openapi/router.go index 4880304..b15ff2b 100644 --- a/pkg/openapi/router.go +++ b/pkg/openapi/router.go @@ -26,6 +26,12 @@ type ServerInterface interface { // (PUT /api/v1/organizations/{organizationID}/projects/{projectID}/clusters/{clusterID}) PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterID(w http.ResponseWriter, r *http.Request, organizationID OrganizationIDParameter, projectID ProjectIDParameter, clusterID ClusterIDParameter) + + // (GET /api/v1/organizations/{organizationID}/regions/{regionID}/flavors) + GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request, organizationID OrganizationIDParameter, regionID RegionIDParameter) + + // (GET /api/v1/organizations/{organizationID}/regions/{regionID}/images) + GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request, organizationID OrganizationIDParameter, regionID RegionIDParameter) } // Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. @@ -52,6 +58,16 @@ func (_ Unimplemented) PutApiV1OrganizationsOrganizationIDProjectsProjectIDClust w.WriteHeader(http.StatusNotImplemented) } +// (GET /api/v1/organizations/{organizationID}/regions/{regionID}/flavors) +func (_ Unimplemented) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request, organizationID OrganizationIDParameter, regionID RegionIDParameter) { + w.WriteHeader(http.StatusNotImplemented) +} + +// (GET /api/v1/organizations/{organizationID}/regions/{regionID}/images) +func (_ Unimplemented) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request, organizationID OrganizationIDParameter, regionID RegionIDParameter) { + w.WriteHeader(http.StatusNotImplemented) +} + // ServerInterfaceWrapper converts contexts to parameters. type ServerInterfaceWrapper struct { Handler ServerInterface @@ -230,6 +246,86 @@ func (siw *ServerInterfaceWrapper) PutApiV1OrganizationsOrganizationIDProjectsPr handler.ServeHTTP(w, r) } +// GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors operation middleware +func (siw *ServerInterfaceWrapper) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "organizationID" ------------- + var organizationID OrganizationIDParameter + + err = runtime.BindStyledParameterWithOptions("simple", "organizationID", chi.URLParam(r, "organizationID"), &organizationID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "organizationID", Err: err}) + return + } + + // ------------- Path parameter "regionID" ------------- + var regionID RegionIDParameter + + err = runtime.BindStyledParameterWithOptions("simple", "regionID", chi.URLParam(r, "regionID"), ®ionID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "regionID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, Oauth2AuthenticationScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w, r, organizationID, regionID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages operation middleware +func (siw *ServerInterfaceWrapper) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "organizationID" ------------- + var organizationID OrganizationIDParameter + + err = runtime.BindStyledParameterWithOptions("simple", "organizationID", chi.URLParam(r, "organizationID"), &organizationID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "organizationID", Err: err}) + return + } + + // ------------- Path parameter "regionID" ------------- + var regionID RegionIDParameter + + err = runtime.BindStyledParameterWithOptions("simple", "regionID", chi.URLParam(r, "regionID"), ®ionID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "regionID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, Oauth2AuthenticationScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w, r, organizationID, regionID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + type UnescapedCookieParamError struct { ParamName string Err error @@ -355,6 +451,12 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Put(options.BaseURL+"/api/v1/organizations/{organizationID}/projects/{projectID}/clusters/{clusterID}", wrapper.PutApiV1OrganizationsOrganizationIDProjectsProjectIDClustersClusterID) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/organizations/{organizationID}/regions/{regionID}/flavors", wrapper.GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/organizations/{organizationID}/regions/{regionID}/images", wrapper.GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages) + }) return r } diff --git a/pkg/openapi/schema.go b/pkg/openapi/schema.go index 28c30e0..6708e95 100644 --- a/pkg/openapi/schema.go +++ b/pkg/openapi/schema.go @@ -14,78 +14,103 @@ import ( "github.com/getkin/kin-openapi/openapi3" externalRef0 "github.com/unikorn-cloud/core/pkg/openapi" + externalRef1 "github.com/unikorn-cloud/region/pkg/openapi" ) // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+w8a2/bOLZ/heBdYO8F5GccJ/GXhafdR7DTabbpzOJOkxtQ0rHNCUVqSSqJG/i/X/Ah", - "WbLpV+J2Z4GgXxrp8PDwvHhe8jNORJYLDlwrPHrGOZEkAw3S/pWwQmmQl++vysfmaQoqkTTXVHA8wp9n", - "gDwc4iSDNvpQKI1iQAQ9EEZT9P6na5QIrgnllE+R4GyOmHgEiRKiACUzIklitoxuOC+yGKRCQqLZPJ8B", - "VxFSmkiNCE8R8BQ9Uj1DZLnKgLpVkYUxG2uUCaVv+PCkhh1RjhjwqZ61cYSpoT0neoYjbMjGo+VpcYQl", - "/KugElI80rKACKtkBhkxp/+DhAke4f/qLBnXcW+VfVRo+IlksOTYYhFhIaeE06/E8GwnN+vAjqVheptI", - "j090LsVvkOid9Hq4baRWqI5N5cLhA6V/ECkFp7USiIZ3bsE7J9RPDsi+FlwDt/8lec5oYhnY+U2ZAz1j", - "eCJZzsD8NwNNUqItbU0dwYsIqxwS80bC1AggxSMcd08v4hMYti4InLYG/fisdTGIB63JoD+Jz8gwJgA4", - "wo9C3jNB0ishmMKjL894QiU8EsYMPsqnEpR7ntBU4tEX3Lvot3vD83av3e30B/g2wrmQ9ghO9fHovOsk", - "pkUiGB5hneR4EdUwdNv2X+ccR7h3ZtDZP3v9OjZJ+NQeHXiKR72Li4sIW/PDo153OFwE9rhdRJhmxC0T", - "Co9wERdcFzjCDyCVVZN+t90dLCKckWRGuYWcMPIgpOVacnY6PId+2ppckLg1OD1JWxfkhLROeydnp5Oz", - "80F/GFu9scJSeHSyqBQrhQkpmMYRzouY0eTyasyYcCJ15yAxK3XNCE3NrJuzwH+HuWGzediSiqDxeHzy", - "09d3vXnSH4/H78f/GP8wHv8w/cf7X4ftttHsJiDxkAZw7AHPDODtYnFrWHWQZntF/aekGpxiNy3N63Pl", - "a73ao6XHbq8ZlzMPlQuuvGmsGIV79XKrsKZGBf9MrTT63f5Jq3vWOul97nVHg9PR4PRX4xAOkPKKna24", - "ToMoHQy73XQILbgYnrYG8WDQIufd89b5YBL3J+RkeNbt46X3snsT6Pcu0rNWr2vsctjttc6TftICOIPu", - "cBhfnCTgljxQo7GUT6810YVyrss9hPTN6t+sfofVW8ZZxXkOCNxzwv0xE0r78/jnrZ5VQvpANFxe4VEp", - "vl7toOZpKUej5iqop7drrHq5R/oEJA05pDFacUltYx/NteolLubLm4958zFvPuY/08fcvszJqLCHYVRp", - "JCarnkZZV1Nwei8kbyVMFOldIiTcZYTyu/x+eidy4CSnd4nIMsHvSJJAriGtu6P1RKYMqWZEoRiAo3KZ", - "TSwfKWMmu5wUbEIZM0/VnCczKbgoFJu3b/j/igJlZI5ywRjSFqMShUzAIsgEp1pIRLVCjqVoIiQyjGBg", - "yDj0VDFJfV7zskgOpBQSjzDlNlG/8+fHkXtz1+RQyZ1YpHPkl+C975QDjuXICujDpzoFE0KNDBx+V2mw", - "B42QkJ73DjoVoBAXuqxB3HBSSccFy2hCgaUHK1Ui+ITR5JXML7Fs4DpZ6pCtfBi6FcnAZtuIMAkknSN4", - "okqr7y0NT1d5AuVrM1zoGcgIFaogjM2RnlGFMiBcGernaEYeoHmOQzk/ETKmaQr8dayv0GzgfaFAokRC", - "ClxTwhRKhVWk6gCVAhmHShlMQf17LOKRKJQCp5CieI5IoWdCUuXtwfGfzI3zSkihHJChvwF4w7W4B16e", - "kPJp84wqETlYj0U4Gl9dVoZm2WSsjP9xyZsbziEBpYic17iDBLdL7EWSgkQ5I3oiZHaoBlCuQXLCrkE+", - "gPyz4c/rdEFZRJ7TYXXwHkcL5BiVMEKz7yvvMUcFh6ccEnMrWTAkkqSQEtKmoEkDUkvCFQWu/RrC0xtu", - "IFWRJACpkYvxNFrO2+hy4jBRK1AjroQoiFDOgCijECamQ1Qjosw2VKniYAvmQv9FFDx9ndC40HcTg2aD", - "xGrXAKRLR1rdCNZtfl8J/mzDRqNEE8pTtHTvh3Kw4N56v8IruWiiHKXunP/YdA0Vema8oMPmL9/vrPsh", - "Ekof5M7gDdPEb/CUG6/Vxsu0N1AB++CC4usqnt5ec/MxtI/e2i6dy0FqX3lehturmPxGqIQwa/U8N9Gz", - "0pLyKV40wvJN6z0IurxCJE1NNhfGVEXyGxFZiF141AbGfFhjBPAiMxlPwe+5eOQrmW79T6tjKay8dmK/", - "XaNhUa9pfllyuM6tis7lchGbxHy9IOEJV5skvjHlKGWvamemGjJ1WJ7TVLhFRS+RkszXybW1l51qaWLA", - "dWWs11COZJu+3nFtIoG0jP8MjR/KvWrVi/2Zcm1WNLTtgLWekyt6Uh3e07NbM6492dtZXRajVsruTc4v", - "6zbhLNO8NTdAZQLukvVbUB40xZVM/6CeQmPpKqsqalf32INne/rNTf7yWGeqKcEOiuvLQta/SnlJIcqF", - "YAEbW5adtpHuweymVYVpdfN/1rdCGy6JFdl5V1iScXvQ+feVXoMHG2W5rDu9wB+qpUM8MnMOY8lBN0KD", - "Ly+9EBoKuYhwRvmlw9LbdTmETODF5L/uWguo1c67zXU69/O4YOK8Ik+Jhu9y0ZVB+THutVffTIdI9aUC", - "dE2ejSJrjl1s8ZuvnQBCxxwAQlvmfzLy9KP9A4+GJ9bsyj97gcu33kXZJIkSBsmCgUI2+XLlArLrGqka", - "M9tFVu7wyWwQvu3qICFiG0QeRKNr92xRxMv3n1DMRHKvLD7GxGOEqEYZnc6cNvA5urx6GBiBXV49DI1A", - "7CouNHH175rurslgVTXLztK+HLsy8I0204ZhJvu2OkM9udFJjiNcpPnuRKXaxRMaOQbe7pDZlT9UgDAh", - "NUphQjnVPn609CEtyWRCk3WJlQ28jdjqR/RUUa5h6uabqo7dIQz+ZBftVM0l6Gbq7P57HNM2FENYjLMQ", - "E1dvrBCGz+o7kSEszvnshWdFBRzSyBK4S+7qaJ5lL+ffcBMB27Jt12tgkGgRtHpXLkUWDikPuC4boTaM", - "OOYgiTZ3gZorDZk5S6HCVZGq17sXIg+9GeGKkISqtZNDUqrH7nskDB58nRX1K2Qf0VgNqVrZqxv/xb5B", - "l+/tXbb98qp66Nu2bUp8sanrvQ1FYMWi3lxfPcNP1j8ZBa9qK7a7YENRmtjekaJfwQf9vtKXkSeaFVnZ", - "iCCFFi2VEAZLEwjYt2vON/e/vv4bUqCN9gTymXojf7Np+jKaQXUP8+XNtyxIeqIrrdj3glt3oSGnGpbS", - "KrW1Yl8Ft+Xo1WjDKqY/u+J1CF2N77EQDAhfM7USbcjKDi4Qr9H2V+AgaeIbHBkoRaYQ2e460dSQbQNH", - "QQo96wfOHMY6RiZ0BI/VyQrBU0546iJZK96/ff585UESkUIb2YaUQkQCioly/RUD+HFsdkcm8KcTX8mO", - "UFxoC+rwgg9xDX2SgiZyXo4LGOTOSMZXlwrZPivSM2KQCwUlXtfgc3vVw5f1Pn+9iXCXMArcPF1tCBRc", - "Fbm5+sCsda2GOyvCqMJpu4Mmp2n20TRkuZBEUja/Kzh5IJQZJagtrHYtH0wl4XplV/us3LLe9al1zzPQ", - "M5HembfWBNdIzyClpESy7P3eBlxmoAWyqhm/gIwNz72mIfc2LtumFsPu62dzv/GVVnJfxCA5aFA/khjY", - "L4QVwYTAJWh/L2KwwIgZaPO0gAjpee79sO0aG8Wrmmgm01NG+TRKCEcx3HDKU3iC1MT1hgUmyzXab42N", - "aA3SbPl/X7qti3HrV9L6evvffxot/2rdtW+fu9Gwt6hB/M+f/hCKCQ5gRH22b0vhevSMCWMfJ3Zs6shV", - "hJUK+fNqkLQyfbjzmxBqBxImFGRzyCgGJvjUXDp7xD3NTde17fYwNu9uDXwLDu8p3HWe1yY3t33ScgxO", - "L7d6NZPXylJrxFdDOWWZyRu4jZYYM/fG8hQSSKrcbJukGgKRwFYP+LnOkdorP4gg7B/We5BimhkRWyba", - "wSV7w2VC2ukhDU86GPqXteAjaUvQJ5qoikzVEbfRZPqjnSsI1qNfJvGrwNjwBsWt4GzUACZKrU8ZfLtW", - "7YsO9s1dhEsmPq0XdJ/XdN1NYbo58xBzNc2g6Qfc3BUDDbYBOxEyIxqPcEo0tAx4uM0fkuWR75yAwgQc", - "0ypIwENFB3oY61QOHWbZIKRveSlv0QTXckh/mIfVwM67Pc6Eb02kDZUI+rHmJwz7q5bfYH/Vohvus4LT", - "fxU15K5usLY8E6lNH3ae3LVi9jh5iXHHyUnz3B79vude0WtqE4M6y/dQ689uSNWrNFWNYNfHub8Vys+M", - "uU5DKvgfdTkgecMJnzf9r4GZAWF65hM4l+qZUHtCNZpIkblqB0+JTcFueEWBO3f7huPX5QGaTANhP0dE", - "xlRLk1tqMvXDxDx1gX+glBxsyo5LvSpRhOt34dTDyN6+Kmurmkz3bng7nLevZo29p7eUd0xksHdR9UCp", - "hCo+CpJCUj2/Nih9dmALFs3ht3WSP7o6qOClOqqy1hADkSZ8tZNxzTE+a19MPNp9ykKAffNOpLD28GfJ", - "8AjPtM7VqNNxobGetxvHbgs57TiSOw/9TmM9jrCtEpjtzOENRS/Aadc1qmH2lRsZpHwiwrpWFmqvQT7Q", - "BGwk7MeQlS1n08rObflArdsyoxNAyTxhcMMzwskUTFQb7MIiP5mtUGachivMzH2x6MOPyE9pmgwbbvgM", - "SAquWkA1g1oXvEZt/bMn3G332l2jQl6x8AiftLvtE5dqz6xEOySnnYdep54kqc5z82cDFp1kY5f5XTm+", - "47ljCJxCwGCMGdnLv8Rl43tfBqjvZzCIUlXtJ1p/BT3O6S+9j3UiPzZIrNrgKx8z97vdTSZZwXU2fY+4", - "iPBgn/Wv+xzH7tI76i7BuV+7z8lR91n/xsJuMjjqJmtj4IsInx5ZLNs+Faj7XBtkhr3tl1ubqdd/HGVD", - "QLoE6Wz6zQ+Lak/b9LUD1XmufkHjUIM9EtHRzqWBnwtZ2A9AQ1fsOxvZKkQQh8flSNLSa7ieIqS1xppx", - "uHLdg1wJtdOFXHk+XpU0NnxK+fsh8816V/uJkc623xdZrPmo/qE+6s1FvdJFXRx1k7Wv/H7XLuqplYqk", - "MGGJfd6aSlHk9utfaruxx/A7nefql5IWVeEkEOG/t88RqUzYJjzexsmBVu6QvdjO3zV+2+lQA33Nl8Zv", - "VvwWaBxqxb/zW333qsAPx9lYoAiEAj/bYk/NTbwsCij0kZzDvzsaeHM2b87m9xMyLBb/HwAA//8EM2RG", - "I1IAAA==", + "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", + "2Xz+/wEAAP//Oaj7ruB2AAA=", } // GetSwagger returns the content of the embedded swagger specification file @@ -131,6 +156,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { } res[rawPath] = rawFunc } + for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "https://raw.githubusercontent.com/unikorn-cloud/region/main/pkg/openapi/server.spec.yaml")) { + if _, ok := res[rawPath]; ok { + // it is not possible to compare functions in golang, so always overwrite the old value + } + res[rawPath] = rawFunc + } return res } diff --git a/pkg/openapi/server.spec.yaml b/pkg/openapi/server.spec.yaml index 968b15f..6ac3cbb 100644 --- a/pkg/openapi/server.spec.yaml +++ b/pkg/openapi/server.spec.yaml @@ -7,6 +7,46 @@ info: header. version: 0.1.0 paths: + /api/v1/organizations/{organizationID}/regions/{regionID}/flavors: + description: |- + Compute flavor services. + parameters: + - $ref: '#/components/parameters/organizationIDParameter' + - $ref: '#/components/parameters/regionIDParameter' + get: + description: |- + Lists all compute compatible flavors that the user has access to. + security: + - oauth2Authentication: [] + responses: + '200': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/region/main/pkg/openapi/server.spec.yaml#/components/responses/flavorsResponse' + '400': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/badRequestResponse' + '401': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/unauthorizedResponse' + '500': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/internalServerErrorResponse' + /api/v1/organizations/{organizationID}/regions/{regionID}/images: + description: |- + Compute image services. + parameters: + - $ref: '#/components/parameters/organizationIDParameter' + - $ref: '#/components/parameters/regionIDParameter' + get: + description: |- + Lists all compute compatible images that the user has access to. + security: + - oauth2Authentication: [] + responses: + '200': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/region/main/pkg/openapi/server.spec.yaml#/components/responses/imagesResponse' + '400': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/badRequestResponse' + '401': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/unauthorizedResponse' + '500': + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/core/main/pkg/openapi/common.spec.yaml#/components/responses/internalServerErrorResponse' /api/v1/organizations/{organizationID}/clusters: description: Cluster services. parameters: @@ -109,7 +149,7 @@ components: The organization name. required: true schema: - $ref: '#/components/schemas/computeNameParameter' + $ref: '#/components/schemas/kubernetesNameParameter' projectIDParameter: name: projectID in: path @@ -117,7 +157,14 @@ components: The project name. required: true schema: - $ref: '#/components/schemas/computeNameParameter' + $ref: '#/components/schemas/kubernetesNameParameter' + regionIDParameter: + name: regionID + in: path + description: The region identifier. + required: true + schema: + $ref: '#/components/schemas/kubernetesNameParameter' clusterIDParameter: name: clusterID in: path @@ -127,9 +174,9 @@ components: 63 characters in length. required: true schema: - $ref: '#/components/schemas/computeNameParameter' + $ref: '#/components/schemas/kubernetesNameParameter' schemas: - computeNameParameter: + kubernetesNameParameter: description: A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. type: string minLength: 1 @@ -147,9 +194,22 @@ components: items: description: A DNS nameserver IPv4 address. type: string + volume: + description: A volume. + type: object + required: + - size + properties: + size: + description: Disk size in GiB. + type: integer machinePool: description: A Compute cluster machine. type: object + required: + - replicas + - flavorId + - image properties: replicas: description: Number of machines for a statically sized pool or the maximum @@ -159,6 +219,8 @@ components: description: Flavor ID. type: string minLength: 1 + disk: + $ref: '#/components/schemas/volume' firewall: $ref: '#/components/schemas/firewall' publicIPAllocation: @@ -241,14 +303,15 @@ components: description: A server image selector. type: object required: - - os - - version + - distro properties: - os: - description: The operating system to use. + distro: + $ref: 'https://raw.githubusercontent.com/unikorn-cloud/region/main/pkg/openapi/server.spec.yaml#/components/schemas/osDistro' + variant: + description: The operating system variant. type: string version: - description: The operating system version to use. + description: The operating system version to use, if not defined it will use the latest. type: string computeClusterWorkloadPool: description: A Compute cluster workload pool. @@ -379,6 +442,9 @@ components: - name: default machine: flavorId: c7568e2d-f9ab-453d-9a3a-51375f78426b + image: + distro: ubuntu + version: '24.04' replicas: 3 firewall: ingress: @@ -425,6 +491,9 @@ components: - name: default machine: flavorId: c7568e2d-f9ab-453d-9a3a-51375f78426b + image: + distro: ubuntu + version: '24.04' replicas: 3 firewall: ingress: @@ -444,8 +513,10 @@ components: publicIPAllocation: enabled: true image: - os: ubuntu - version: 20.04 + kernel: linux + family: debian + distro: ubuntu + version: '20.04' ssh: publicKeys: - ssh-rsa AAA3NzC1yc2AAADAQABAABgQDZ6... @@ -478,6 +549,9 @@ components: - name: default machine: flavorId: c7568e2d-f9ab-453d-9a3a-51375f78426b + image: + distro: ubuntu + version: '24.04' replicas: 3 firewall: ingress: @@ -497,7 +571,9 @@ components: publicIPAllocation: enabled: true image: - os: ubuntu + kernel: linux + family: debian + dsitro: ubuntu version: 20.04 ssh: publicKeys: diff --git a/pkg/openapi/types.go b/pkg/openapi/types.go index 6ba6845..76773a0 100644 --- a/pkg/openapi/types.go +++ b/pkg/openapi/types.go @@ -5,6 +5,7 @@ package openapi import ( externalRef0 "github.com/unikorn-cloud/core/pkg/openapi" + externalRef1 "github.com/unikorn-cloud/region/pkg/openapi" ) const ( @@ -109,9 +110,6 @@ type ComputeClusterWrite struct { // ComputeClusters A list of Compute clusters. type ComputeClusters = []ComputeClusterRead -// ComputeNameParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. -type ComputeNameParameter = string - // Firewall A list of firewall rules applied to a workload pool. type Firewall struct { // Ingress A list of firewall rules applied to a workload pool. @@ -156,29 +154,38 @@ type FirewallRules = []FirewallRule // ImageSelector A server image selector. type ImageSelector struct { - // Os The operating system to use. - Os string `json:"os"` + // Distro A distribution name. + Distro externalRef1.OsDistro `json:"distro"` + + // Variant The operating system variant. + Variant *string `json:"variant,omitempty"` - // Version The operating system version to use. - Version string `json:"version"` + // Version The operating system version to use, if not defined it will use the latest. + Version *string `json:"version,omitempty"` } +// KubernetesNameParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. +type KubernetesNameParameter = string + // MachinePool A Compute cluster machine. type MachinePool struct { + // Disk A volume. + Disk *Volume `json:"disk,omitempty"` + // Firewall A list of firewall rules applied to a workload pool. Firewall *Firewall `json:"firewall,omitempty"` // FlavorId Flavor ID. - FlavorId *string `json:"flavorId,omitempty"` + FlavorId string `json:"flavorId"` // Image A server image selector. - Image *ImageSelector `json:"image,omitempty"` + Image ImageSelector `json:"image"` // PublicIPAllocation A public IP allocation settings. PublicIPAllocation *PublicIPAllocation `json:"publicIPAllocation,omitempty"` // Replicas Number of machines for a statically sized pool or the maximum for an auto-scaled pool. - Replicas *int `json:"replicas,omitempty"` + Replicas int `json:"replicas"` // Ssh SSH settings. Ssh *struct { @@ -193,14 +200,23 @@ type PublicIPAllocation struct { Enabled bool `json:"enabled"` } +// Volume A volume. +type Volume struct { + // Size Disk size in GiB. + Size int `json:"size"` +} + // ClusterIDParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. -type ClusterIDParameter = ComputeNameParameter +type ClusterIDParameter = KubernetesNameParameter // OrganizationIDParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. -type OrganizationIDParameter = ComputeNameParameter +type OrganizationIDParameter = KubernetesNameParameter // ProjectIDParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. -type ProjectIDParameter = ComputeNameParameter +type ProjectIDParameter = KubernetesNameParameter + +// RegionIDParameter A Compute name. Must be a valid DNS containing only lower case characters, numbers or hyphens, start and end with a character or number, and be at most 63 characters in length. +type RegionIDParameter = KubernetesNameParameter // ComputeClusterResponse Compute cluster read. type ComputeClusterResponse = ComputeClusterRead diff --git a/pkg/server/handler/cluster/conversion.go b/pkg/server/handler/cluster/conversion.go index b360cf4..434e0b8 100644 --- a/pkg/server/handler/cluster/conversion.go +++ b/pkg/server/handler/cluster/conversion.go @@ -78,8 +78,8 @@ func newGenerator(client client.Client, options *Options, region regionapi.Clien // convertMachine converts from a custom resource into the API definition. func convertMachine(in *unikornv1.ComputeWorkloadPoolSpec) *openapi.MachinePool { machine := &openapi.MachinePool{ - Replicas: in.Replicas, - FlavorId: in.FlavorID, + Replicas: *in.Replicas, + FlavorId: *in.FlavorID, PublicIPAllocation: convertPublicIPAllocation(in.PublicIPAllocation), Firewall: convertFirewall(in.Firewall), // TODO: Image @@ -218,9 +218,8 @@ func convertList(in *unikornv1.ComputeClusterList) openapi.ComputeClusters { return out } -// defaultImage returns a default image for either control planes or workload pools -// based on the specified Compute version. -func (g *generator) defaultImage(ctx context.Context, request *openapi.ComputeClusterWrite) (*regionapi.Image, error) { +// chooseImages returns an image for the requested machine and flavor. +func (g *generator) chooseImage(ctx context.Context, request *openapi.ComputeClusterWrite, m *openapi.MachinePool, _ *regionapi.Flavor) (*regionapi.Image, error) { resp, err := g.region.GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse(ctx, g.organizationID, request.Spec.RegionId) if err != nil { return nil, err @@ -232,10 +231,39 @@ func (g *generator) defaultImage(ctx context.Context, request *openapi.ComputeCl images := *resp.JSON200 + // TODO: is the image compatible with the flavor virtualization type??? + images = slices.DeleteFunc(images, func(image regionapi.Image) bool { + // Is it the right distro? + if image.Spec.Os.Distro != m.Image.Distro { + return true + } + + // Is it the right variant? + if m.Image.Variant != nil { + if image.Spec.Os.Variant == nil { + return true + } + + if *m.Image.Variant != *image.Spec.Os.Variant { + return true + } + } + + // Is it the right version? + if m.Image.Version != nil { + if *m.Image.Version != image.Spec.Os.Version { + return true + } + } + + return false + }) + if len(images) == 0 { return nil, errors.OAuth2ServerError("unable to select an image") } + // Select the most recent, the region servie guarantees temporal ordering. return &images[0], nil } @@ -256,17 +284,13 @@ func (g *generator) generateNetwork() *unikornv1core.NetworkGeneric { // generateMachineGeneric generates a generic machine part of the cluster. func (g *generator) generateMachineGeneric(ctx context.Context, request *openapi.ComputeClusterWrite, m *openapi.MachinePool, flavor *regionapi.Flavor) (*unikornv1core.MachineGeneric, error) { - if m.Replicas == nil { - m.Replicas = ptr.To(3) - } - - image, err := g.defaultImage(ctx, request) + image, err := g.chooseImage(ctx, request, m, flavor) if err != nil { return nil, err } machine := &unikornv1core.MachineGeneric{ - Replicas: m.Replicas, + Replicas: &m.Replicas, ImageID: ptr.To(image.Metadata.Id), FlavorID: &flavor.Metadata.Id, } @@ -281,7 +305,7 @@ func (g *generator) generateWorkloadPools(ctx context.Context, request *openapi. for i := range request.Spec.WorkloadPools { pool := &request.Spec.WorkloadPools[i] - flavor, err := g.lookupFlavor(ctx, request, *pool.Machine.FlavorId) + flavor, err := g.lookupFlavor(ctx, request, pool.Machine.FlavorId) if err != nil { return nil, err } diff --git a/pkg/server/handler/handler.go b/pkg/server/handler/handler.go index d763dcf..3b4bb60 100644 --- a/pkg/server/handler/handler.go +++ b/pkg/server/handler/handler.go @@ -24,6 +24,7 @@ import ( "github.com/unikorn-cloud/compute/pkg/openapi" "github.com/unikorn-cloud/compute/pkg/server/handler/cluster" + "github.com/unikorn-cloud/compute/pkg/server/handler/region" "github.com/unikorn-cloud/core/pkg/server/errors" "github.com/unikorn-cloud/core/pkg/server/util" identityclient "github.com/unikorn-cloud/identity/pkg/client" @@ -66,7 +67,7 @@ func New(client client.Client, namespace string, options *Options, issuer *ident } func (h *Handler) regionClient(ctx context.Context) (*regionapi.ClientWithResponses, error) { - token, err := h.issuer.Issue(ctx, "kubernetes-api") + token, err := h.issuer.Issue(ctx, "compute-api") if err != nil { return nil, err } @@ -90,6 +91,48 @@ func (h *Handler) setUncacheable(w http.ResponseWriter) { w.Header().Add("Cache-Control", "no-cache") } +func (h *Handler) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, regionID openapi.RegionIDParameter) { + if err := rbac.AllowOrganizationScope(r.Context(), "compute:flavors", identityapi.Read, organizationID); err != nil { + errors.HandleError(w, r, err) + return + } + + client, err := h.regionClient(r.Context()) + if err != nil { + errors.HandleError(w, r, err) + return + } + + result, err := region.Flavors(r.Context(), client, organizationID, regionID) + if err != nil { + errors.HandleError(w, r, errors.OAuth2ServerError("unable to read flavors").WithError(err)) + return + } + + util.WriteJSONResponse(w, r, http.StatusOK, result) +} + +func (h *Handler) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, regionID openapi.RegionIDParameter) { + if err := rbac.AllowOrganizationScope(r.Context(), "compute:images", identityapi.Read, organizationID); err != nil { + errors.HandleError(w, r, err) + return + } + + client, err := h.regionClient(r.Context()) + if err != nil { + errors.HandleError(w, r, err) + return + } + + result, err := region.Images(r.Context(), client, organizationID, regionID) + if err != nil { + errors.HandleError(w, r, errors.OAuth2ServerError("unable to read flavors").WithError(err)) + return + } + + util.WriteJSONResponse(w, r, http.StatusOK, result) +} + func (h *Handler) GetApiV1OrganizationsOrganizationIDClusters(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter) { region, err := h.regionClient(r.Context()) if err != nil { diff --git a/pkg/server/handler/region/region.go b/pkg/server/handler/region/region.go new file mode 100644 index 0000000..7a58dd4 --- /dev/null +++ b/pkg/server/handler/region/region.go @@ -0,0 +1,64 @@ +/* +Copyright 2024 the Unikorn 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 region + +import ( + "context" + "errors" + "fmt" + "net/http" + + regionapi "github.com/unikorn-cloud/region/pkg/openapi" +) + +var ( + ErrStatusCode = errors.New("unexpected status code") +) + +// Flavors returns all Kubernetes compatible flavors. +func Flavors(ctx context.Context, client regionapi.ClientWithResponsesInterface, organizationID, regionID string) ([]regionapi.Flavor, error) { + resp, err := client.GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavorsWithResponse(ctx, organizationID, regionID) + if err != nil { + return nil, err + } + + if resp.StatusCode() != http.StatusOK { + return nil, fmt.Errorf("%w: expected 200, got %d", ErrStatusCode, resp.StatusCode()) + } + + flavors := *resp.JSON200 + + // TODO: filtering. + return flavors, nil +} + +// Images returns all Kubernetes compatible images. +func Images(ctx context.Context, client regionapi.ClientWithResponsesInterface, organizationID, regionID string) ([]regionapi.Image, error) { + resp, err := client.GetApiV1OrganizationsOrganizationIDRegionsRegionIDImagesWithResponse(ctx, organizationID, regionID) + if err != nil { + return nil, err + } + + if resp.StatusCode() != http.StatusOK { + return nil, fmt.Errorf("%w: expected 200, got %d", ErrStatusCode, resp.StatusCode()) + } + + images := *resp.JSON200 + + // TODO: filtering. + return images, nil +}