diff --git a/apiserver/controllers/forge_instances.go b/apiserver/controllers/forge_instances.go new file mode 100644 index 000000000..619b056a8 --- /dev/null +++ b/apiserver/controllers/forge_instances.go @@ -0,0 +1,677 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 controllers + +import ( + "encoding/json" + "log/slog" + "net/http" + "strconv" + + "github.com/gorilla/mux" + + gErrors "github.com/cloudbase/garm-provider-common/errors" + "github.com/cloudbase/garm/apiserver/params" + runnerParams "github.com/cloudbase/garm/params" +) + +// swagger:route POST /forge-instances forge-instances CreateForgeInstance +// +// Create forge instance with the given parameters. +// +// Parameters: +// + name: Body +// description: Parameters used to create the forge instance. +// type: CreateForgeInstanceParams +// in: body +// required: true +// +// Responses: +// 200: ForgeInstance +// default: APIErrorResponse +func (a *APIController) CreateForgeInstanceHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var createData runnerParams.CreateForgeInstanceParams + if err := json.NewDecoder(r.Body).Decode(&createData); err != nil { + handleError(ctx, w, gErrors.ErrBadRequest) + return + } + + forgeInstance, err := a.r.CreateForgeInstance(ctx, createData) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating forge instance") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(forgeInstance); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route GET /forge-instances forge-instances ListForgeInstances +// +// List all forge instances. +// +// Parameters: +// + name: endpoint +// description: Exact endpoint name to filter by +// type: string +// in: query +// required: false +// +// Responses: +// 200: ForgeInstances +// default: APIErrorResponse +func (a *APIController) ListForgeInstancesHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + filter := runnerParams.ForgeInstanceFilter{ + Endpoint: r.URL.Query().Get("endpoint"), + } + forgeInstances, err := a.r.ListForgeInstances(ctx, filter) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing forge instances") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(forgeInstances); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route GET /forge-instances/{forgeInstanceID} forge-instances GetForgeInstance +// +// Get forge instance by ID. +// +// Parameters: +// + name: forgeInstanceID +// description: The ID of the forge instance to fetch. +// type: string +// in: path +// required: true +// +// Responses: +// 200: ForgeInstance +// default: APIErrorResponse +func (a *APIController) GetForgeInstanceByIDHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + forgeInstance, err := a.r.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching forge instance") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(forgeInstance); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route DELETE /forge-instances/{forgeInstanceID} forge-instances DeleteForgeInstance +// +// Delete forge instance by ID. +// +// Parameters: +// + name: forgeInstanceID +// description: ID of the forge instance to delete. +// type: string +// in: path +// required: true +// +// + name: keepWebhook +// description: If true and a webhook is installed for this forge instance, it will not be removed. +// type: boolean +// in: query +// +// Responses: +// default: APIErrorResponse +func (a *APIController) DeleteForgeInstanceHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + keepWebhook, _ := strconv.ParseBool(r.URL.Query().Get("keepWebhook")) + + if err := a.r.DeleteForgeInstance(ctx, forgeInstanceID, keepWebhook); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing forge instance") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + +// swagger:route PUT /forge-instances/{forgeInstanceID} forge-instances UpdateForgeInstance +// +// Update forge instance with the given parameters. +// +// Parameters: +// + name: forgeInstanceID +// description: The ID of the forge instance to update. +// type: string +// in: path +// required: true +// + name: Body +// description: Parameters used when updating the forge instance. +// type: UpdateEntityParams +// in: body +// required: true +// +// Responses: +// 200: ForgeInstance +// default: APIErrorResponse +func (a *APIController) UpdateForgeInstanceHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + var updatePayload runnerParams.UpdateEntityParams + if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil { + handleError(ctx, w, gErrors.ErrBadRequest) + return + } + + forgeInstance, err := a.r.UpdateForgeInstance(ctx, forgeInstanceID, updatePayload) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "error updating forge instance") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(forgeInstance); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route POST /forge-instances/{forgeInstanceID}/pools forge-instances pools CreateForgeInstancePool +// +// Create forge instance pool with the parameters given. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// + name: Body +// description: Parameters used when creating the forge instance pool. +// type: CreatePoolParams +// in: body +// required: true +// +// Responses: +// 200: Pool +// default: APIErrorResponse +func (a *APIController) CreateForgeInstancePoolHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + var poolData runnerParams.CreatePoolParams + if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode") + handleError(ctx, w, gErrors.ErrBadRequest) + return + } + + pool, err := a.r.CreateForgeInstancePool(ctx, forgeInstanceID, poolData) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating forge instance pool") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(pool); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route GET /forge-instances/{forgeInstanceID}/pools forge-instances pools ListForgeInstancePools +// +// List forge instance pools. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// Responses: +// 200: Pools +// default: APIErrorResponse +func (a *APIController) ListForgeInstancePoolsHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + pools, err := a.r.ListForgeInstancePools(ctx, forgeInstanceID) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(pools); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route GET /forge-instances/{forgeInstanceID}/pools/{poolID} forge-instances pools GetForgeInstancePool +// +// Get forge instance pool by ID. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// + name: poolID +// description: Pool ID. +// type: string +// in: path +// required: true +// +// Responses: +// 200: Pool +// default: APIErrorResponse +func (a *APIController) GetForgeInstancePoolHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + forgeInstanceID, fiOk := vars["forgeInstanceID"] + poolID, poolOk := vars["poolID"] + if !fiOk || !poolOk { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance or pool ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + pool, err := a.r.GetForgeInstancePoolByID(ctx, forgeInstanceID, poolID) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(pool); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route DELETE /forge-instances/{forgeInstanceID}/pools/{poolID} forge-instances pools DeleteForgeInstancePool +// +// Delete forge instance pool by ID. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// + name: poolID +// description: ID of the forge instance pool to delete. +// type: string +// in: path +// required: true +// +// Responses: +// default: APIErrorResponse +func (a *APIController) DeleteForgeInstancePoolHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, fiOk := vars["forgeInstanceID"] + poolID, poolOk := vars["poolID"] + if !fiOk || !poolOk { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance or pool ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + if err := a.r.DeleteForgeInstancePool(ctx, forgeInstanceID, poolID); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing pool") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + +// swagger:route PUT /forge-instances/{forgeInstanceID}/pools/{poolID} forge-instances pools UpdateForgeInstancePool +// +// Update forge instance pool with the parameters given. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// + name: poolID +// description: ID of the forge instance pool to update. +// type: string +// in: path +// required: true +// +// + name: Body +// description: Parameters used when updating the forge instance pool. +// type: UpdatePoolParams +// in: body +// required: true +// +// Responses: +// 200: Pool +// default: APIErrorResponse +func (a *APIController) UpdateForgeInstancePoolHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, fiOk := vars["forgeInstanceID"] + poolID, poolOk := vars["poolID"] + if !fiOk || !poolOk { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance or pool ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + var poolData runnerParams.UpdatePoolParams + if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode") + handleError(ctx, w, gErrors.ErrBadRequest) + return + } + + pool, err := a.r.UpdateForgeInstancePool(ctx, forgeInstanceID, poolID, poolData) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "error updating forge instance pool") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(pool); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route GET /forge-instances/{forgeInstanceID}/instances forge-instances ListForgeInstanceInstances +// +// List forge instance runner instances. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// Responses: +// 200: Instances +// default: APIErrorResponse +func (a *APIController) ListForgeInstanceInstancesHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + instances, err := a.r.ListForgeInstanceInstances(ctx, forgeInstanceID) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing instances") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(instances); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route POST /forge-instances/{forgeInstanceID}/webhook forge-instances hooks InstallForgeInstanceWebhook +// +// Install the GARM webhook for a forge instance. The secret configured on the forge instance will +// be used to validate the requests. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// + name: Body +// description: Parameters used when creating the forge instance webhook. +// type: InstallWebhookParams +// in: body +// required: true +// +// Responses: +// 200: HookInfo +// default: APIErrorResponse +func (a *APIController) InstallForgeInstanceWebhookHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + var hookParam runnerParams.InstallWebhookParams + if err := json.NewDecoder(r.Body).Decode(&hookParam); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode") + handleError(ctx, w, gErrors.ErrBadRequest) + return + } + + info, err := a.r.InstallForgeInstanceWebhook(ctx, forgeInstanceID, hookParam) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "installing webhook") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(info); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} + +// swagger:route DELETE /forge-instances/{forgeInstanceID}/webhook forge-instances hooks UninstallForgeInstanceWebhook +// +// Uninstall forge instance webhook. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// Responses: +// default: APIErrorResponse +func (a *APIController) UninstallForgeInstanceWebhookHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + if err := a.r.UninstallForgeInstanceWebhook(ctx, forgeInstanceID); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing webhook") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + +// swagger:route GET /forge-instances/{forgeInstanceID}/webhook forge-instances hooks GetForgeInstanceWebhookInfo +// +// Get information about the GARM installed webhook on a forge instance. +// +// Parameters: +// + name: forgeInstanceID +// description: Forge instance ID. +// type: string +// in: path +// required: true +// +// Responses: +// 200: HookInfo +// default: APIErrorResponse +func (a *APIController) GetForgeInstanceWebhookInfoHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + vars := mux.Vars(r) + forgeInstanceID, ok := vars["forgeInstanceID"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ + Error: "Bad Request", + Details: "No forge instance ID specified", + }); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } + return + } + + info, err := a.r.GetForgeInstanceWebhookInfo(ctx, forgeInstanceID) + if err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "getting webhook info") + handleError(ctx, w, err) + return + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(info); err != nil { + slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response") + } +} diff --git a/apiserver/routers/routers.go b/apiserver/routers/routers.go index 2d09f8de4..0f85a10e7 100644 --- a/apiserver/routers/routers.go +++ b/apiserver/routers/routers.go @@ -497,6 +497,57 @@ func NewAPIRouter(han *controllers.APIController, authMiddleware, initMiddleware apiRouter.Handle("/enterprises/", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/enterprises", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS") + ///////////////////////////////// + // Forge instances and pools // + ///////////////////////////////// + + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}/", http.HandlerFunc(han.GetForgeInstancePoolHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}", http.HandlerFunc(han.GetForgeInstancePoolHandler)).Methods("GET", "OPTIONS") + + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}/", http.HandlerFunc(han.DeleteForgeInstancePoolHandler)).Methods("DELETE", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}", http.HandlerFunc(han.DeleteForgeInstancePoolHandler)).Methods("DELETE", "OPTIONS") + + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}/", http.HandlerFunc(han.UpdateForgeInstancePoolHandler)).Methods("PUT", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/{poolID}", http.HandlerFunc(han.UpdateForgeInstancePoolHandler)).Methods("PUT", "OPTIONS") + + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/", http.HandlerFunc(han.ListForgeInstancePoolsHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools", http.HandlerFunc(han.ListForgeInstancePoolsHandler)).Methods("GET", "OPTIONS") + + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools/", http.HandlerFunc(han.CreateForgeInstancePoolHandler)).Methods("POST", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/pools", http.HandlerFunc(han.CreateForgeInstancePoolHandler)).Methods("POST", "OPTIONS") + + // Forge instance instances list + apiRouter.Handle("/forge-instances/{forgeInstanceID}/instances/", http.HandlerFunc(han.ListForgeInstanceInstancesHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/instances", http.HandlerFunc(han.ListForgeInstanceInstancesHandler)).Methods("GET", "OPTIONS") + + // Get forge instance + apiRouter.Handle("/forge-instances/{forgeInstanceID}/", http.HandlerFunc(han.GetForgeInstanceByIDHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}", http.HandlerFunc(han.GetForgeInstanceByIDHandler)).Methods("GET", "OPTIONS") + // Update forge instance + apiRouter.Handle("/forge-instances/{forgeInstanceID}/", http.HandlerFunc(han.UpdateForgeInstanceHandler)).Methods("PUT", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}", http.HandlerFunc(han.UpdateForgeInstanceHandler)).Methods("PUT", "OPTIONS") + // Delete forge instance + apiRouter.Handle("/forge-instances/{forgeInstanceID}/", http.HandlerFunc(han.DeleteForgeInstanceHandler)).Methods("DELETE", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}", http.HandlerFunc(han.DeleteForgeInstanceHandler)).Methods("DELETE", "OPTIONS") + // List forge instances + apiRouter.Handle("/forge-instances/", http.HandlerFunc(han.ListForgeInstancesHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances", http.HandlerFunc(han.ListForgeInstancesHandler)).Methods("GET", "OPTIONS") + // Create forge instance + apiRouter.Handle("/forge-instances/", http.HandlerFunc(han.CreateForgeInstanceHandler)).Methods("POST", "OPTIONS") + apiRouter.Handle("/forge-instances", http.HandlerFunc(han.CreateForgeInstanceHandler)).Methods("POST", "OPTIONS") + + if manageWebhooks { + // Install Webhook + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook/", http.HandlerFunc(han.InstallForgeInstanceWebhookHandler)).Methods("POST", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook", http.HandlerFunc(han.InstallForgeInstanceWebhookHandler)).Methods("POST", "OPTIONS") + // Uninstall Webhook + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook/", http.HandlerFunc(han.UninstallForgeInstanceWebhookHandler)).Methods("DELETE", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook", http.HandlerFunc(han.UninstallForgeInstanceWebhookHandler)).Methods("DELETE", "OPTIONS") + // Get webhook info + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook/", http.HandlerFunc(han.GetForgeInstanceWebhookInfoHandler)).Methods("GET", "OPTIONS") + apiRouter.Handle("/forge-instances/{forgeInstanceID}/webhook", http.HandlerFunc(han.GetForgeInstanceWebhookInfoHandler)).Methods("GET", "OPTIONS") + } + // Providers apiRouter.Handle("/providers/", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS") apiRouter.Handle("/providers", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS") diff --git a/apiserver/swagger-models.yaml b/apiserver/swagger-models.yaml index 5f0e54281..02913d8eb 100644 --- a/apiserver/swagger-models.yaml +++ b/apiserver/swagger-models.yaml @@ -215,6 +215,29 @@ definitions: import: package: github.com/cloudbase/garm/params alias: garm_params + ForgeInstances: + type: array + x-go-type: + type: ForgeInstances + import: + package: github.com/cloudbase/garm/params + alias: garm_params + items: + $ref: '#/definitions/ForgeInstance' + ForgeInstance: + type: object + x-go-type: + type: ForgeInstance + import: + package: github.com/cloudbase/garm/params + alias: garm_params + CreateForgeInstanceParams: + type: object + x-go-type: + type: CreateForgeInstanceParams + import: + package: github.com/cloudbase/garm/params + alias: garm_params UpdateEntityParams: type: object x-go-type: diff --git a/apiserver/swagger.yaml b/apiserver/swagger.yaml index 4b4f0ad45..367165114 100644 --- a/apiserver/swagger.yaml +++ b/apiserver/swagger.yaml @@ -30,6 +30,13 @@ definitions: alias: garm_params package: github.com/cloudbase/garm/params type: CreateFileObjectParams + CreateForgeInstanceParams: + type: object + x-go-type: + import: + alias: garm_params + package: github.com/cloudbase/garm/params + type: CreateForgeInstanceParams CreateGiteaCredentialsParams: type: object x-go-type: @@ -162,6 +169,22 @@ definitions: alias: garm_params package: github.com/cloudbase/garm/params type: ForgeEndpoints + ForgeInstance: + type: object + x-go-type: + import: + alias: garm_params + package: github.com/cloudbase/garm/params + type: ForgeInstance + ForgeInstances: + items: + $ref: '#/definitions/ForgeInstance' + type: array + x-go-type: + import: + alias: garm_params + package: github.com/cloudbase/garm/params + type: ForgeInstances GARMAgentTool: type: object x-go-type: @@ -863,6 +886,343 @@ paths: summary: Initialize the first run of the controller. tags: - first-run + /forge-instances: + get: + operationId: ListForgeInstances + parameters: + - description: Exact endpoint name to filter by + in: query + name: endpoint + type: string + responses: + "200": + description: ForgeInstances + schema: + $ref: '#/definitions/ForgeInstances' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: List all forge instances. + tags: + - forge-instances + post: + operationId: CreateForgeInstance + parameters: + - description: Parameters used to create the forge instance. + in: body + name: Body + required: true + schema: + $ref: '#/definitions/CreateForgeInstanceParams' + description: Parameters used to create the forge instance. + type: object + responses: + "200": + description: ForgeInstance + schema: + $ref: '#/definitions/ForgeInstance' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Create forge instance with the given parameters. + tags: + - forge-instances + /forge-instances/{forgeInstanceID}: + delete: + operationId: DeleteForgeInstance + parameters: + - description: ID of the forge instance to delete. + in: path + name: forgeInstanceID + required: true + type: string + - description: If true and a webhook is installed for this forge instance, it will not be removed. + in: query + name: keepWebhook + type: boolean + responses: + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Delete forge instance by ID. + tags: + - forge-instances + get: + operationId: GetForgeInstance + parameters: + - description: The ID of the forge instance to fetch. + in: path + name: forgeInstanceID + required: true + type: string + responses: + "200": + description: ForgeInstance + schema: + $ref: '#/definitions/ForgeInstance' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Get forge instance by ID. + tags: + - forge-instances + put: + operationId: UpdateForgeInstance + parameters: + - description: The ID of the forge instance to update. + in: path + name: forgeInstanceID + required: true + type: string + - description: Parameters used when updating the forge instance. + in: body + name: Body + required: true + schema: + $ref: '#/definitions/UpdateEntityParams' + description: Parameters used when updating the forge instance. + type: object + responses: + "200": + description: ForgeInstance + schema: + $ref: '#/definitions/ForgeInstance' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Update forge instance with the given parameters. + tags: + - forge-instances + /forge-instances/{forgeInstanceID}/instances: + get: + operationId: ListForgeInstanceInstances + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + responses: + "200": + description: Instances + schema: + $ref: '#/definitions/Instances' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: List forge instance runner instances. + tags: + - forge-instances + /forge-instances/{forgeInstanceID}/pools: + get: + operationId: ListForgeInstancePools + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + responses: + "200": + description: Pools + schema: + $ref: '#/definitions/Pools' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: List forge instance pools. + tags: + - forge-instances + - pools + post: + operationId: CreateForgeInstancePool + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + - description: Parameters used when creating the forge instance pool. + in: body + name: Body + required: true + schema: + $ref: '#/definitions/CreatePoolParams' + description: Parameters used when creating the forge instance pool. + type: object + responses: + "200": + description: Pool + schema: + $ref: '#/definitions/Pool' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Create forge instance pool with the parameters given. + tags: + - forge-instances + - pools + /forge-instances/{forgeInstanceID}/pools/{poolID}: + delete: + operationId: DeleteForgeInstancePool + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + - description: ID of the forge instance pool to delete. + in: path + name: poolID + required: true + type: string + responses: + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Delete forge instance pool by ID. + tags: + - forge-instances + - pools + get: + operationId: GetForgeInstancePool + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + - description: Pool ID. + in: path + name: poolID + required: true + type: string + responses: + "200": + description: Pool + schema: + $ref: '#/definitions/Pool' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Get forge instance pool by ID. + tags: + - forge-instances + - pools + put: + operationId: UpdateForgeInstancePool + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + - description: ID of the forge instance pool to update. + in: path + name: poolID + required: true + type: string + - description: Parameters used when updating the forge instance pool. + in: body + name: Body + required: true + schema: + $ref: '#/definitions/UpdatePoolParams' + description: Parameters used when updating the forge instance pool. + type: object + responses: + "200": + description: Pool + schema: + $ref: '#/definitions/Pool' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Update forge instance pool with the parameters given. + tags: + - forge-instances + - pools + /forge-instances/{forgeInstanceID}/webhook: + delete: + operationId: UninstallForgeInstanceWebhook + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + responses: + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Uninstall forge instance webhook. + tags: + - forge-instances + - hooks + get: + operationId: GetForgeInstanceWebhookInfo + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + responses: + "200": + description: HookInfo + schema: + $ref: '#/definitions/HookInfo' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + summary: Get information about the GARM installed webhook on a forge instance. + tags: + - forge-instances + - hooks + post: + description: |- + Install the GARM webhook for a forge instance. The secret configured on the forge instance will + be used to validate the requests. + operationId: InstallForgeInstanceWebhook + parameters: + - description: Forge instance ID. + in: path + name: forgeInstanceID + required: true + type: string + - description: Parameters used when creating the forge instance webhook. + in: body + name: Body + required: true + schema: + $ref: '#/definitions/InstallWebhookParams' + description: Parameters used when creating the forge instance webhook. + type: object + responses: + "200": + description: HookInfo + schema: + $ref: '#/definitions/HookInfo' + default: + description: APIErrorResponse + schema: + $ref: '#/definitions/APIErrorResponse' + tags: + - forge-instances + - hooks /gitea/credentials: get: operationId: ListGiteaCredentials diff --git a/client/forge_instances/create_forge_instance_parameters.go b/client/forge_instances/create_forge_instance_parameters.go new file mode 100644 index 000000000..d0b008555 --- /dev/null +++ b/client/forge_instances/create_forge_instance_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + garm_params "github.com/cloudbase/garm/params" +) + +// NewCreateForgeInstanceParams creates a new CreateForgeInstanceParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewCreateForgeInstanceParams() *CreateForgeInstanceParams { + return &CreateForgeInstanceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewCreateForgeInstanceParamsWithTimeout creates a new CreateForgeInstanceParams object +// with the ability to set a timeout on a request. +func NewCreateForgeInstanceParamsWithTimeout(timeout time.Duration) *CreateForgeInstanceParams { + return &CreateForgeInstanceParams{ + timeout: timeout, + } +} + +// NewCreateForgeInstanceParamsWithContext creates a new CreateForgeInstanceParams object +// with the ability to set a context for a request. +func NewCreateForgeInstanceParamsWithContext(ctx context.Context) *CreateForgeInstanceParams { + return &CreateForgeInstanceParams{ + Context: ctx, + } +} + +// NewCreateForgeInstanceParamsWithHTTPClient creates a new CreateForgeInstanceParams object +// with the ability to set a custom HTTPClient for a request. +func NewCreateForgeInstanceParamsWithHTTPClient(client *http.Client) *CreateForgeInstanceParams { + return &CreateForgeInstanceParams{ + HTTPClient: client, + } +} + +/* +CreateForgeInstanceParams contains all the parameters to send to the API endpoint + + for the create forge instance operation. + + Typically these are written to a http.Request. +*/ +type CreateForgeInstanceParams struct { + + /* Body. + + Parameters used to create the forge instance. + */ + Body garm_params.CreateForgeInstanceParams + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the create forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateForgeInstanceParams) WithDefaults() *CreateForgeInstanceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the create forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateForgeInstanceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the create forge instance params +func (o *CreateForgeInstanceParams) WithTimeout(timeout time.Duration) *CreateForgeInstanceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the create forge instance params +func (o *CreateForgeInstanceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the create forge instance params +func (o *CreateForgeInstanceParams) WithContext(ctx context.Context) *CreateForgeInstanceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the create forge instance params +func (o *CreateForgeInstanceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the create forge instance params +func (o *CreateForgeInstanceParams) WithHTTPClient(client *http.Client) *CreateForgeInstanceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the create forge instance params +func (o *CreateForgeInstanceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the create forge instance params +func (o *CreateForgeInstanceParams) WithBody(body garm_params.CreateForgeInstanceParams) *CreateForgeInstanceParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the create forge instance params +func (o *CreateForgeInstanceParams) SetBody(body garm_params.CreateForgeInstanceParams) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *CreateForgeInstanceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/create_forge_instance_pool_parameters.go b/client/forge_instances/create_forge_instance_pool_parameters.go new file mode 100644 index 000000000..6a505c745 --- /dev/null +++ b/client/forge_instances/create_forge_instance_pool_parameters.go @@ -0,0 +1,173 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + garm_params "github.com/cloudbase/garm/params" +) + +// NewCreateForgeInstancePoolParams creates a new CreateForgeInstancePoolParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewCreateForgeInstancePoolParams() *CreateForgeInstancePoolParams { + return &CreateForgeInstancePoolParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewCreateForgeInstancePoolParamsWithTimeout creates a new CreateForgeInstancePoolParams object +// with the ability to set a timeout on a request. +func NewCreateForgeInstancePoolParamsWithTimeout(timeout time.Duration) *CreateForgeInstancePoolParams { + return &CreateForgeInstancePoolParams{ + timeout: timeout, + } +} + +// NewCreateForgeInstancePoolParamsWithContext creates a new CreateForgeInstancePoolParams object +// with the ability to set a context for a request. +func NewCreateForgeInstancePoolParamsWithContext(ctx context.Context) *CreateForgeInstancePoolParams { + return &CreateForgeInstancePoolParams{ + Context: ctx, + } +} + +// NewCreateForgeInstancePoolParamsWithHTTPClient creates a new CreateForgeInstancePoolParams object +// with the ability to set a custom HTTPClient for a request. +func NewCreateForgeInstancePoolParamsWithHTTPClient(client *http.Client) *CreateForgeInstancePoolParams { + return &CreateForgeInstancePoolParams{ + HTTPClient: client, + } +} + +/* +CreateForgeInstancePoolParams contains all the parameters to send to the API endpoint + + for the create forge instance pool operation. + + Typically these are written to a http.Request. +*/ +type CreateForgeInstancePoolParams struct { + + /* Body. + + Parameters used when creating the forge instance pool. + */ + Body garm_params.CreatePoolParams + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the create forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateForgeInstancePoolParams) WithDefaults() *CreateForgeInstancePoolParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the create forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateForgeInstancePoolParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) WithTimeout(timeout time.Duration) *CreateForgeInstancePoolParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) WithContext(ctx context.Context) *CreateForgeInstancePoolParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) WithHTTPClient(client *http.Client) *CreateForgeInstancePoolParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) WithBody(body garm_params.CreatePoolParams) *CreateForgeInstancePoolParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) SetBody(body garm_params.CreatePoolParams) { + o.Body = body +} + +// WithForgeInstanceID adds the forgeInstanceID to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) WithForgeInstanceID(forgeInstanceID string) *CreateForgeInstancePoolParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the create forge instance pool params +func (o *CreateForgeInstancePoolParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *CreateForgeInstancePoolParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/create_forge_instance_pool_responses.go b/client/forge_instances/create_forge_instance_pool_responses.go new file mode 100644 index 000000000..1891a621b --- /dev/null +++ b/client/forge_instances/create_forge_instance_pool_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// CreateForgeInstancePoolReader is a Reader for the CreateForgeInstancePool structure. +type CreateForgeInstancePoolReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CreateForgeInstancePoolReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewCreateForgeInstancePoolOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewCreateForgeInstancePoolDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewCreateForgeInstancePoolOK creates a CreateForgeInstancePoolOK with default headers values +func NewCreateForgeInstancePoolOK() *CreateForgeInstancePoolOK { + return &CreateForgeInstancePoolOK{} +} + +/* +CreateForgeInstancePoolOK describes a response with status code 200, with default header values. + +Pool +*/ +type CreateForgeInstancePoolOK struct { + Payload garm_params.Pool +} + +// IsSuccess returns true when this create forge instance pool o k response has a 2xx status code +func (o *CreateForgeInstancePoolOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this create forge instance pool o k response has a 3xx status code +func (o *CreateForgeInstancePoolOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create forge instance pool o k response has a 4xx status code +func (o *CreateForgeInstancePoolOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this create forge instance pool o k response has a 5xx status code +func (o *CreateForgeInstancePoolOK) IsServerError() bool { + return false +} + +// IsCode returns true when this create forge instance pool o k response a status code equal to that given +func (o *CreateForgeInstancePoolOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the create forge instance pool o k response +func (o *CreateForgeInstancePoolOK) Code() int { + return 200 +} + +func (o *CreateForgeInstancePoolOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/pools][%d] createForgeInstancePoolOK %s", 200, payload) +} + +func (o *CreateForgeInstancePoolOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/pools][%d] createForgeInstancePoolOK %s", 200, payload) +} + +func (o *CreateForgeInstancePoolOK) GetPayload() garm_params.Pool { + return o.Payload +} + +func (o *CreateForgeInstancePoolOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewCreateForgeInstancePoolDefault creates a CreateForgeInstancePoolDefault with default headers values +func NewCreateForgeInstancePoolDefault(code int) *CreateForgeInstancePoolDefault { + return &CreateForgeInstancePoolDefault{ + _statusCode: code, + } +} + +/* +CreateForgeInstancePoolDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type CreateForgeInstancePoolDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this create forge instance pool default response has a 2xx status code +func (o *CreateForgeInstancePoolDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this create forge instance pool default response has a 3xx status code +func (o *CreateForgeInstancePoolDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this create forge instance pool default response has a 4xx status code +func (o *CreateForgeInstancePoolDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this create forge instance pool default response has a 5xx status code +func (o *CreateForgeInstancePoolDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this create forge instance pool default response a status code equal to that given +func (o *CreateForgeInstancePoolDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the create forge instance pool default response +func (o *CreateForgeInstancePoolDefault) Code() int { + return o._statusCode +} + +func (o *CreateForgeInstancePoolDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/pools][%d] CreateForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *CreateForgeInstancePoolDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/pools][%d] CreateForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *CreateForgeInstancePoolDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *CreateForgeInstancePoolDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/create_forge_instance_responses.go b/client/forge_instances/create_forge_instance_responses.go new file mode 100644 index 000000000..bc0a874a9 --- /dev/null +++ b/client/forge_instances/create_forge_instance_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// CreateForgeInstanceReader is a Reader for the CreateForgeInstance structure. +type CreateForgeInstanceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CreateForgeInstanceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewCreateForgeInstanceOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewCreateForgeInstanceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewCreateForgeInstanceOK creates a CreateForgeInstanceOK with default headers values +func NewCreateForgeInstanceOK() *CreateForgeInstanceOK { + return &CreateForgeInstanceOK{} +} + +/* +CreateForgeInstanceOK describes a response with status code 200, with default header values. + +ForgeInstance +*/ +type CreateForgeInstanceOK struct { + Payload garm_params.ForgeInstance +} + +// IsSuccess returns true when this create forge instance o k response has a 2xx status code +func (o *CreateForgeInstanceOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this create forge instance o k response has a 3xx status code +func (o *CreateForgeInstanceOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create forge instance o k response has a 4xx status code +func (o *CreateForgeInstanceOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this create forge instance o k response has a 5xx status code +func (o *CreateForgeInstanceOK) IsServerError() bool { + return false +} + +// IsCode returns true when this create forge instance o k response a status code equal to that given +func (o *CreateForgeInstanceOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the create forge instance o k response +func (o *CreateForgeInstanceOK) Code() int { + return 200 +} + +func (o *CreateForgeInstanceOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances][%d] createForgeInstanceOK %s", 200, payload) +} + +func (o *CreateForgeInstanceOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances][%d] createForgeInstanceOK %s", 200, payload) +} + +func (o *CreateForgeInstanceOK) GetPayload() garm_params.ForgeInstance { + return o.Payload +} + +func (o *CreateForgeInstanceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewCreateForgeInstanceDefault creates a CreateForgeInstanceDefault with default headers values +func NewCreateForgeInstanceDefault(code int) *CreateForgeInstanceDefault { + return &CreateForgeInstanceDefault{ + _statusCode: code, + } +} + +/* +CreateForgeInstanceDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type CreateForgeInstanceDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this create forge instance default response has a 2xx status code +func (o *CreateForgeInstanceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this create forge instance default response has a 3xx status code +func (o *CreateForgeInstanceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this create forge instance default response has a 4xx status code +func (o *CreateForgeInstanceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this create forge instance default response has a 5xx status code +func (o *CreateForgeInstanceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this create forge instance default response a status code equal to that given +func (o *CreateForgeInstanceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the create forge instance default response +func (o *CreateForgeInstanceDefault) Code() int { + return o._statusCode +} + +func (o *CreateForgeInstanceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances][%d] CreateForgeInstance default %s", o._statusCode, payload) +} + +func (o *CreateForgeInstanceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances][%d] CreateForgeInstance default %s", o._statusCode, payload) +} + +func (o *CreateForgeInstanceDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *CreateForgeInstanceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/delete_forge_instance_parameters.go b/client/forge_instances/delete_forge_instance_parameters.go new file mode 100644 index 000000000..66512489a --- /dev/null +++ b/client/forge_instances/delete_forge_instance_parameters.go @@ -0,0 +1,186 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// NewDeleteForgeInstanceParams creates a new DeleteForgeInstanceParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewDeleteForgeInstanceParams() *DeleteForgeInstanceParams { + return &DeleteForgeInstanceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteForgeInstanceParamsWithTimeout creates a new DeleteForgeInstanceParams object +// with the ability to set a timeout on a request. +func NewDeleteForgeInstanceParamsWithTimeout(timeout time.Duration) *DeleteForgeInstanceParams { + return &DeleteForgeInstanceParams{ + timeout: timeout, + } +} + +// NewDeleteForgeInstanceParamsWithContext creates a new DeleteForgeInstanceParams object +// with the ability to set a context for a request. +func NewDeleteForgeInstanceParamsWithContext(ctx context.Context) *DeleteForgeInstanceParams { + return &DeleteForgeInstanceParams{ + Context: ctx, + } +} + +// NewDeleteForgeInstanceParamsWithHTTPClient creates a new DeleteForgeInstanceParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteForgeInstanceParamsWithHTTPClient(client *http.Client) *DeleteForgeInstanceParams { + return &DeleteForgeInstanceParams{ + HTTPClient: client, + } +} + +/* +DeleteForgeInstanceParams contains all the parameters to send to the API endpoint + + for the delete forge instance operation. + + Typically these are written to a http.Request. +*/ +type DeleteForgeInstanceParams struct { + + /* ForgeInstanceID. + + ID of the forge instance to delete. + */ + ForgeInstanceID string + + /* KeepWebhook. + + If true and a webhook is installed for this forge instance, it will not be removed. + */ + KeepWebhook *bool + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteForgeInstanceParams) WithDefaults() *DeleteForgeInstanceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteForgeInstanceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete forge instance params +func (o *DeleteForgeInstanceParams) WithTimeout(timeout time.Duration) *DeleteForgeInstanceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete forge instance params +func (o *DeleteForgeInstanceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete forge instance params +func (o *DeleteForgeInstanceParams) WithContext(ctx context.Context) *DeleteForgeInstanceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete forge instance params +func (o *DeleteForgeInstanceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete forge instance params +func (o *DeleteForgeInstanceParams) WithHTTPClient(client *http.Client) *DeleteForgeInstanceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete forge instance params +func (o *DeleteForgeInstanceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the delete forge instance params +func (o *DeleteForgeInstanceParams) WithForgeInstanceID(forgeInstanceID string) *DeleteForgeInstanceParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the delete forge instance params +func (o *DeleteForgeInstanceParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WithKeepWebhook adds the keepWebhook to the delete forge instance params +func (o *DeleteForgeInstanceParams) WithKeepWebhook(keepWebhook *bool) *DeleteForgeInstanceParams { + o.SetKeepWebhook(keepWebhook) + return o +} + +// SetKeepWebhook adds the keepWebhook to the delete forge instance params +func (o *DeleteForgeInstanceParams) SetKeepWebhook(keepWebhook *bool) { + o.KeepWebhook = keepWebhook +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteForgeInstanceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if o.KeepWebhook != nil { + + // query param keepWebhook + var qrKeepWebhook bool + + if o.KeepWebhook != nil { + qrKeepWebhook = *o.KeepWebhook + } + qKeepWebhook := swag.FormatBool(qrKeepWebhook) + if qKeepWebhook != "" { + + if err := r.SetQueryParam("keepWebhook", qKeepWebhook); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/delete_forge_instance_pool_parameters.go b/client/forge_instances/delete_forge_instance_pool_parameters.go new file mode 100644 index 000000000..fb4415c29 --- /dev/null +++ b/client/forge_instances/delete_forge_instance_pool_parameters.go @@ -0,0 +1,173 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewDeleteForgeInstancePoolParams creates a new DeleteForgeInstancePoolParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewDeleteForgeInstancePoolParams() *DeleteForgeInstancePoolParams { + return &DeleteForgeInstancePoolParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteForgeInstancePoolParamsWithTimeout creates a new DeleteForgeInstancePoolParams object +// with the ability to set a timeout on a request. +func NewDeleteForgeInstancePoolParamsWithTimeout(timeout time.Duration) *DeleteForgeInstancePoolParams { + return &DeleteForgeInstancePoolParams{ + timeout: timeout, + } +} + +// NewDeleteForgeInstancePoolParamsWithContext creates a new DeleteForgeInstancePoolParams object +// with the ability to set a context for a request. +func NewDeleteForgeInstancePoolParamsWithContext(ctx context.Context) *DeleteForgeInstancePoolParams { + return &DeleteForgeInstancePoolParams{ + Context: ctx, + } +} + +// NewDeleteForgeInstancePoolParamsWithHTTPClient creates a new DeleteForgeInstancePoolParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteForgeInstancePoolParamsWithHTTPClient(client *http.Client) *DeleteForgeInstancePoolParams { + return &DeleteForgeInstancePoolParams{ + HTTPClient: client, + } +} + +/* +DeleteForgeInstancePoolParams contains all the parameters to send to the API endpoint + + for the delete forge instance pool operation. + + Typically these are written to a http.Request. +*/ +type DeleteForgeInstancePoolParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + /* PoolID. + + ID of the forge instance pool to delete. + */ + PoolID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteForgeInstancePoolParams) WithDefaults() *DeleteForgeInstancePoolParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteForgeInstancePoolParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) WithTimeout(timeout time.Duration) *DeleteForgeInstancePoolParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) WithContext(ctx context.Context) *DeleteForgeInstancePoolParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) WithHTTPClient(client *http.Client) *DeleteForgeInstancePoolParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) WithForgeInstanceID(forgeInstanceID string) *DeleteForgeInstancePoolParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WithPoolID adds the poolID to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) WithPoolID(poolID string) *DeleteForgeInstancePoolParams { + o.SetPoolID(poolID) + return o +} + +// SetPoolID adds the poolId to the delete forge instance pool params +func (o *DeleteForgeInstancePoolParams) SetPoolID(poolID string) { + o.PoolID = poolID +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteForgeInstancePoolParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + // path param poolID + if err := r.SetPathParam("poolID", o.PoolID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/delete_forge_instance_pool_responses.go b/client/forge_instances/delete_forge_instance_pool_responses.go new file mode 100644 index 000000000..458d673d9 --- /dev/null +++ b/client/forge_instances/delete_forge_instance_pool_responses.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" +) + +// DeleteForgeInstancePoolReader is a Reader for the DeleteForgeInstancePool structure. +type DeleteForgeInstancePoolReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteForgeInstancePoolReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + result := NewDeleteForgeInstancePoolDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result +} + +// NewDeleteForgeInstancePoolDefault creates a DeleteForgeInstancePoolDefault with default headers values +func NewDeleteForgeInstancePoolDefault(code int) *DeleteForgeInstancePoolDefault { + return &DeleteForgeInstancePoolDefault{ + _statusCode: code, + } +} + +/* +DeleteForgeInstancePoolDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type DeleteForgeInstancePoolDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this delete forge instance pool default response has a 2xx status code +func (o *DeleteForgeInstancePoolDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete forge instance pool default response has a 3xx status code +func (o *DeleteForgeInstancePoolDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete forge instance pool default response has a 4xx status code +func (o *DeleteForgeInstancePoolDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete forge instance pool default response has a 5xx status code +func (o *DeleteForgeInstancePoolDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete forge instance pool default response a status code equal to that given +func (o *DeleteForgeInstancePoolDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete forge instance pool default response +func (o *DeleteForgeInstancePoolDefault) Code() int { + return o._statusCode +} + +func (o *DeleteForgeInstancePoolDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] DeleteForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *DeleteForgeInstancePoolDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] DeleteForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *DeleteForgeInstancePoolDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *DeleteForgeInstancePoolDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/delete_forge_instance_responses.go b/client/forge_instances/delete_forge_instance_responses.go new file mode 100644 index 000000000..1d4b480dd --- /dev/null +++ b/client/forge_instances/delete_forge_instance_responses.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" +) + +// DeleteForgeInstanceReader is a Reader for the DeleteForgeInstance structure. +type DeleteForgeInstanceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteForgeInstanceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + result := NewDeleteForgeInstanceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result +} + +// NewDeleteForgeInstanceDefault creates a DeleteForgeInstanceDefault with default headers values +func NewDeleteForgeInstanceDefault(code int) *DeleteForgeInstanceDefault { + return &DeleteForgeInstanceDefault{ + _statusCode: code, + } +} + +/* +DeleteForgeInstanceDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type DeleteForgeInstanceDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this delete forge instance default response has a 2xx status code +func (o *DeleteForgeInstanceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete forge instance default response has a 3xx status code +func (o *DeleteForgeInstanceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete forge instance default response has a 4xx status code +func (o *DeleteForgeInstanceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete forge instance default response has a 5xx status code +func (o *DeleteForgeInstanceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete forge instance default response a status code equal to that given +func (o *DeleteForgeInstanceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete forge instance default response +func (o *DeleteForgeInstanceDefault) Code() int { + return o._statusCode +} + +func (o *DeleteForgeInstanceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}][%d] DeleteForgeInstance default %s", o._statusCode, payload) +} + +func (o *DeleteForgeInstanceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}][%d] DeleteForgeInstance default %s", o._statusCode, payload) +} + +func (o *DeleteForgeInstanceDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *DeleteForgeInstanceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/forge_instances_client.go b/client/forge_instances/forge_instances_client.go new file mode 100644 index 000000000..dbfd5549b --- /dev/null +++ b/client/forge_instances/forge_instances_client.go @@ -0,0 +1,665 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "github.com/go-openapi/runtime" + httptransport "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// New creates a new forge instances API client. +func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { + return &Client{transport: transport, formats: formats} +} + +// New creates a new forge instances API client with basic auth credentials. +// It takes the following parameters: +// - host: http host (github.com). +// - basePath: any base path for the API client ("/v1", "/v3"). +// - scheme: http scheme ("http", "https"). +// - user: user for basic authentication header. +// - password: password for basic authentication header. +func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService { + transport := httptransport.New(host, basePath, []string{scheme}) + transport.DefaultAuthentication = httptransport.BasicAuth(user, password) + return &Client{transport: transport, formats: strfmt.Default} +} + +// New creates a new forge instances API client with a bearer token for authentication. +// It takes the following parameters: +// - host: http host (github.com). +// - basePath: any base path for the API client ("/v1", "/v3"). +// - scheme: http scheme ("http", "https"). +// - bearerToken: bearer token for Bearer authentication header. +func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService { + transport := httptransport.New(host, basePath, []string{scheme}) + transport.DefaultAuthentication = httptransport.BearerToken(bearerToken) + return &Client{transport: transport, formats: strfmt.Default} +} + +/* +Client for forge instances API +*/ +type Client struct { + transport runtime.ClientTransport + formats strfmt.Registry +} + +// ClientOption may be used to customize the behavior of Client methods. +type ClientOption func(*runtime.ClientOperation) + +// ClientService is the interface for Client methods +type ClientService interface { + CreateForgeInstance(params *CreateForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateForgeInstanceOK, error) + + CreateForgeInstancePool(params *CreateForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateForgeInstancePoolOK, error) + + DeleteForgeInstance(params *DeleteForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error + + DeleteForgeInstancePool(params *DeleteForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error + + GetForgeInstance(params *GetForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstanceOK, error) + + GetForgeInstancePool(params *GetForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstancePoolOK, error) + + GetForgeInstanceWebhookInfo(params *GetForgeInstanceWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstanceWebhookInfoOK, error) + + InstallForgeInstanceWebhook(params *InstallForgeInstanceWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InstallForgeInstanceWebhookOK, error) + + ListForgeInstanceInstances(params *ListForgeInstanceInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstanceInstancesOK, error) + + ListForgeInstancePools(params *ListForgeInstancePoolsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstancePoolsOK, error) + + ListForgeInstances(params *ListForgeInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstancesOK, error) + + UninstallForgeInstanceWebhook(params *UninstallForgeInstanceWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error + + UpdateForgeInstance(params *UpdateForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateForgeInstanceOK, error) + + UpdateForgeInstancePool(params *UpdateForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateForgeInstancePoolOK, error) + + SetTransport(transport runtime.ClientTransport) +} + +/* +CreateForgeInstance creates forge instance with the given parameters +*/ +func (a *Client) CreateForgeInstance(params *CreateForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateForgeInstanceOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewCreateForgeInstanceParams() + } + op := &runtime.ClientOperation{ + ID: "CreateForgeInstance", + Method: "POST", + PathPattern: "/forge-instances", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &CreateForgeInstanceReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*CreateForgeInstanceOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*CreateForgeInstanceDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +CreateForgeInstancePool creates forge instance pool with the parameters given +*/ +func (a *Client) CreateForgeInstancePool(params *CreateForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateForgeInstancePoolOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewCreateForgeInstancePoolParams() + } + op := &runtime.ClientOperation{ + ID: "CreateForgeInstancePool", + Method: "POST", + PathPattern: "/forge-instances/{forgeInstanceID}/pools", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &CreateForgeInstancePoolReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*CreateForgeInstancePoolOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*CreateForgeInstancePoolDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +DeleteForgeInstance deletes forge instance by ID +*/ +func (a *Client) DeleteForgeInstance(params *DeleteForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteForgeInstanceParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteForgeInstance", + Method: "DELETE", + PathPattern: "/forge-instances/{forgeInstanceID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &DeleteForgeInstanceReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + _, err := a.transport.Submit(op) + if err != nil { + return err + } + // no success response is defined: return nil + + return nil +} + +/* +DeleteForgeInstancePool deletes forge instance pool by ID +*/ +func (a *Client) DeleteForgeInstancePool(params *DeleteForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteForgeInstancePoolParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteForgeInstancePool", + Method: "DELETE", + PathPattern: "/forge-instances/{forgeInstanceID}/pools/{poolID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &DeleteForgeInstancePoolReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + _, err := a.transport.Submit(op) + if err != nil { + return err + } + // no success response is defined: return nil + + return nil +} + +/* +GetForgeInstance gets forge instance by ID +*/ +func (a *Client) GetForgeInstance(params *GetForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstanceOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetForgeInstanceParams() + } + op := &runtime.ClientOperation{ + ID: "GetForgeInstance", + Method: "GET", + PathPattern: "/forge-instances/{forgeInstanceID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &GetForgeInstanceReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*GetForgeInstanceOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetForgeInstanceDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetForgeInstancePool gets forge instance pool by ID +*/ +func (a *Client) GetForgeInstancePool(params *GetForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstancePoolOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetForgeInstancePoolParams() + } + op := &runtime.ClientOperation{ + ID: "GetForgeInstancePool", + Method: "GET", + PathPattern: "/forge-instances/{forgeInstanceID}/pools/{poolID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &GetForgeInstancePoolReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*GetForgeInstancePoolOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetForgeInstancePoolDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetForgeInstanceWebhookInfo gets information about the g a r m installed webhook on a forge instance +*/ +func (a *Client) GetForgeInstanceWebhookInfo(params *GetForgeInstanceWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetForgeInstanceWebhookInfoOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetForgeInstanceWebhookInfoParams() + } + op := &runtime.ClientOperation{ + ID: "GetForgeInstanceWebhookInfo", + Method: "GET", + PathPattern: "/forge-instances/{forgeInstanceID}/webhook", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &GetForgeInstanceWebhookInfoReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*GetForgeInstanceWebhookInfoOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetForgeInstanceWebhookInfoDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* + InstallForgeInstanceWebhook Install the GARM webhook for a forge instance. The secret configured on the forge instance will + +be used to validate the requests. +*/ +func (a *Client) InstallForgeInstanceWebhook(params *InstallForgeInstanceWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InstallForgeInstanceWebhookOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewInstallForgeInstanceWebhookParams() + } + op := &runtime.ClientOperation{ + ID: "InstallForgeInstanceWebhook", + Method: "POST", + PathPattern: "/forge-instances/{forgeInstanceID}/webhook", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &InstallForgeInstanceWebhookReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*InstallForgeInstanceWebhookOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*InstallForgeInstanceWebhookDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListForgeInstanceInstances lists forge instance runner instances +*/ +func (a *Client) ListForgeInstanceInstances(params *ListForgeInstanceInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstanceInstancesOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListForgeInstanceInstancesParams() + } + op := &runtime.ClientOperation{ + ID: "ListForgeInstanceInstances", + Method: "GET", + PathPattern: "/forge-instances/{forgeInstanceID}/instances", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ListForgeInstanceInstancesReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*ListForgeInstanceInstancesOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListForgeInstanceInstancesDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListForgeInstancePools lists forge instance pools +*/ +func (a *Client) ListForgeInstancePools(params *ListForgeInstancePoolsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstancePoolsOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListForgeInstancePoolsParams() + } + op := &runtime.ClientOperation{ + ID: "ListForgeInstancePools", + Method: "GET", + PathPattern: "/forge-instances/{forgeInstanceID}/pools", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ListForgeInstancePoolsReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*ListForgeInstancePoolsOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListForgeInstancePoolsDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListForgeInstances lists all forge instances +*/ +func (a *Client) ListForgeInstances(params *ListForgeInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListForgeInstancesOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListForgeInstancesParams() + } + op := &runtime.ClientOperation{ + ID: "ListForgeInstances", + Method: "GET", + PathPattern: "/forge-instances", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ListForgeInstancesReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*ListForgeInstancesOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListForgeInstancesDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +UninstallForgeInstanceWebhook uninstalls forge instance webhook +*/ +func (a *Client) UninstallForgeInstanceWebhook(params *UninstallForgeInstanceWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUninstallForgeInstanceWebhookParams() + } + op := &runtime.ClientOperation{ + ID: "UninstallForgeInstanceWebhook", + Method: "DELETE", + PathPattern: "/forge-instances/{forgeInstanceID}/webhook", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &UninstallForgeInstanceWebhookReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + _, err := a.transport.Submit(op) + if err != nil { + return err + } + // no success response is defined: return nil + + return nil +} + +/* +UpdateForgeInstance updates forge instance with the given parameters +*/ +func (a *Client) UpdateForgeInstance(params *UpdateForgeInstanceParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateForgeInstanceOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUpdateForgeInstanceParams() + } + op := &runtime.ClientOperation{ + ID: "UpdateForgeInstance", + Method: "PUT", + PathPattern: "/forge-instances/{forgeInstanceID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &UpdateForgeInstanceReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*UpdateForgeInstanceOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*UpdateForgeInstanceDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +UpdateForgeInstancePool updates forge instance pool with the parameters given +*/ +func (a *Client) UpdateForgeInstancePool(params *UpdateForgeInstancePoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateForgeInstancePoolOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUpdateForgeInstancePoolParams() + } + op := &runtime.ClientOperation{ + ID: "UpdateForgeInstancePool", + Method: "PUT", + PathPattern: "/forge-instances/{forgeInstanceID}/pools/{poolID}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &UpdateForgeInstancePoolReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*UpdateForgeInstancePoolOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*UpdateForgeInstancePoolDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +// SetTransport changes the transport on the client +func (a *Client) SetTransport(transport runtime.ClientTransport) { + a.transport = transport +} diff --git a/client/forge_instances/get_forge_instance_parameters.go b/client/forge_instances/get_forge_instance_parameters.go new file mode 100644 index 000000000..9fd848861 --- /dev/null +++ b/client/forge_instances/get_forge_instance_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetForgeInstanceParams creates a new GetForgeInstanceParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewGetForgeInstanceParams() *GetForgeInstanceParams { + return &GetForgeInstanceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetForgeInstanceParamsWithTimeout creates a new GetForgeInstanceParams object +// with the ability to set a timeout on a request. +func NewGetForgeInstanceParamsWithTimeout(timeout time.Duration) *GetForgeInstanceParams { + return &GetForgeInstanceParams{ + timeout: timeout, + } +} + +// NewGetForgeInstanceParamsWithContext creates a new GetForgeInstanceParams object +// with the ability to set a context for a request. +func NewGetForgeInstanceParamsWithContext(ctx context.Context) *GetForgeInstanceParams { + return &GetForgeInstanceParams{ + Context: ctx, + } +} + +// NewGetForgeInstanceParamsWithHTTPClient creates a new GetForgeInstanceParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetForgeInstanceParamsWithHTTPClient(client *http.Client) *GetForgeInstanceParams { + return &GetForgeInstanceParams{ + HTTPClient: client, + } +} + +/* +GetForgeInstanceParams contains all the parameters to send to the API endpoint + + for the get forge instance operation. + + Typically these are written to a http.Request. +*/ +type GetForgeInstanceParams struct { + + /* ForgeInstanceID. + + The ID of the forge instance to fetch. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstanceParams) WithDefaults() *GetForgeInstanceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstanceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get forge instance params +func (o *GetForgeInstanceParams) WithTimeout(timeout time.Duration) *GetForgeInstanceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get forge instance params +func (o *GetForgeInstanceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get forge instance params +func (o *GetForgeInstanceParams) WithContext(ctx context.Context) *GetForgeInstanceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get forge instance params +func (o *GetForgeInstanceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get forge instance params +func (o *GetForgeInstanceParams) WithHTTPClient(client *http.Client) *GetForgeInstanceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get forge instance params +func (o *GetForgeInstanceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the get forge instance params +func (o *GetForgeInstanceParams) WithForgeInstanceID(forgeInstanceID string) *GetForgeInstanceParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the get forge instance params +func (o *GetForgeInstanceParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetForgeInstanceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/get_forge_instance_pool_parameters.go b/client/forge_instances/get_forge_instance_pool_parameters.go new file mode 100644 index 000000000..72ac11564 --- /dev/null +++ b/client/forge_instances/get_forge_instance_pool_parameters.go @@ -0,0 +1,173 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetForgeInstancePoolParams creates a new GetForgeInstancePoolParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewGetForgeInstancePoolParams() *GetForgeInstancePoolParams { + return &GetForgeInstancePoolParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetForgeInstancePoolParamsWithTimeout creates a new GetForgeInstancePoolParams object +// with the ability to set a timeout on a request. +func NewGetForgeInstancePoolParamsWithTimeout(timeout time.Duration) *GetForgeInstancePoolParams { + return &GetForgeInstancePoolParams{ + timeout: timeout, + } +} + +// NewGetForgeInstancePoolParamsWithContext creates a new GetForgeInstancePoolParams object +// with the ability to set a context for a request. +func NewGetForgeInstancePoolParamsWithContext(ctx context.Context) *GetForgeInstancePoolParams { + return &GetForgeInstancePoolParams{ + Context: ctx, + } +} + +// NewGetForgeInstancePoolParamsWithHTTPClient creates a new GetForgeInstancePoolParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetForgeInstancePoolParamsWithHTTPClient(client *http.Client) *GetForgeInstancePoolParams { + return &GetForgeInstancePoolParams{ + HTTPClient: client, + } +} + +/* +GetForgeInstancePoolParams contains all the parameters to send to the API endpoint + + for the get forge instance pool operation. + + Typically these are written to a http.Request. +*/ +type GetForgeInstancePoolParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + /* PoolID. + + Pool ID. + */ + PoolID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstancePoolParams) WithDefaults() *GetForgeInstancePoolParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstancePoolParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get forge instance pool params +func (o *GetForgeInstancePoolParams) WithTimeout(timeout time.Duration) *GetForgeInstancePoolParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get forge instance pool params +func (o *GetForgeInstancePoolParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get forge instance pool params +func (o *GetForgeInstancePoolParams) WithContext(ctx context.Context) *GetForgeInstancePoolParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get forge instance pool params +func (o *GetForgeInstancePoolParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get forge instance pool params +func (o *GetForgeInstancePoolParams) WithHTTPClient(client *http.Client) *GetForgeInstancePoolParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get forge instance pool params +func (o *GetForgeInstancePoolParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the get forge instance pool params +func (o *GetForgeInstancePoolParams) WithForgeInstanceID(forgeInstanceID string) *GetForgeInstancePoolParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the get forge instance pool params +func (o *GetForgeInstancePoolParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WithPoolID adds the poolID to the get forge instance pool params +func (o *GetForgeInstancePoolParams) WithPoolID(poolID string) *GetForgeInstancePoolParams { + o.SetPoolID(poolID) + return o +} + +// SetPoolID adds the poolId to the get forge instance pool params +func (o *GetForgeInstancePoolParams) SetPoolID(poolID string) { + o.PoolID = poolID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetForgeInstancePoolParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + // path param poolID + if err := r.SetPathParam("poolID", o.PoolID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/get_forge_instance_pool_responses.go b/client/forge_instances/get_forge_instance_pool_responses.go new file mode 100644 index 000000000..d7083ae7b --- /dev/null +++ b/client/forge_instances/get_forge_instance_pool_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// GetForgeInstancePoolReader is a Reader for the GetForgeInstancePool structure. +type GetForgeInstancePoolReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetForgeInstancePoolReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetForgeInstancePoolOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetForgeInstancePoolDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetForgeInstancePoolOK creates a GetForgeInstancePoolOK with default headers values +func NewGetForgeInstancePoolOK() *GetForgeInstancePoolOK { + return &GetForgeInstancePoolOK{} +} + +/* +GetForgeInstancePoolOK describes a response with status code 200, with default header values. + +Pool +*/ +type GetForgeInstancePoolOK struct { + Payload garm_params.Pool +} + +// IsSuccess returns true when this get forge instance pool o k response has a 2xx status code +func (o *GetForgeInstancePoolOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get forge instance pool o k response has a 3xx status code +func (o *GetForgeInstancePoolOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get forge instance pool o k response has a 4xx status code +func (o *GetForgeInstancePoolOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get forge instance pool o k response has a 5xx status code +func (o *GetForgeInstancePoolOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get forge instance pool o k response a status code equal to that given +func (o *GetForgeInstancePoolOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get forge instance pool o k response +func (o *GetForgeInstancePoolOK) Code() int { + return 200 +} + +func (o *GetForgeInstancePoolOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] getForgeInstancePoolOK %s", 200, payload) +} + +func (o *GetForgeInstancePoolOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] getForgeInstancePoolOK %s", 200, payload) +} + +func (o *GetForgeInstancePoolOK) GetPayload() garm_params.Pool { + return o.Payload +} + +func (o *GetForgeInstancePoolOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetForgeInstancePoolDefault creates a GetForgeInstancePoolDefault with default headers values +func NewGetForgeInstancePoolDefault(code int) *GetForgeInstancePoolDefault { + return &GetForgeInstancePoolDefault{ + _statusCode: code, + } +} + +/* +GetForgeInstancePoolDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type GetForgeInstancePoolDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this get forge instance pool default response has a 2xx status code +func (o *GetForgeInstancePoolDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get forge instance pool default response has a 3xx status code +func (o *GetForgeInstancePoolDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get forge instance pool default response has a 4xx status code +func (o *GetForgeInstancePoolDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get forge instance pool default response has a 5xx status code +func (o *GetForgeInstancePoolDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get forge instance pool default response a status code equal to that given +func (o *GetForgeInstancePoolDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get forge instance pool default response +func (o *GetForgeInstancePoolDefault) Code() int { + return o._statusCode +} + +func (o *GetForgeInstancePoolDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] GetForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *GetForgeInstancePoolDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] GetForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *GetForgeInstancePoolDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *GetForgeInstancePoolDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/get_forge_instance_responses.go b/client/forge_instances/get_forge_instance_responses.go new file mode 100644 index 000000000..e602e2120 --- /dev/null +++ b/client/forge_instances/get_forge_instance_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// GetForgeInstanceReader is a Reader for the GetForgeInstance structure. +type GetForgeInstanceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetForgeInstanceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetForgeInstanceOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetForgeInstanceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetForgeInstanceOK creates a GetForgeInstanceOK with default headers values +func NewGetForgeInstanceOK() *GetForgeInstanceOK { + return &GetForgeInstanceOK{} +} + +/* +GetForgeInstanceOK describes a response with status code 200, with default header values. + +ForgeInstance +*/ +type GetForgeInstanceOK struct { + Payload garm_params.ForgeInstance +} + +// IsSuccess returns true when this get forge instance o k response has a 2xx status code +func (o *GetForgeInstanceOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get forge instance o k response has a 3xx status code +func (o *GetForgeInstanceOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get forge instance o k response has a 4xx status code +func (o *GetForgeInstanceOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get forge instance o k response has a 5xx status code +func (o *GetForgeInstanceOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get forge instance o k response a status code equal to that given +func (o *GetForgeInstanceOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get forge instance o k response +func (o *GetForgeInstanceOK) Code() int { + return 200 +} + +func (o *GetForgeInstanceOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}][%d] getForgeInstanceOK %s", 200, payload) +} + +func (o *GetForgeInstanceOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}][%d] getForgeInstanceOK %s", 200, payload) +} + +func (o *GetForgeInstanceOK) GetPayload() garm_params.ForgeInstance { + return o.Payload +} + +func (o *GetForgeInstanceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetForgeInstanceDefault creates a GetForgeInstanceDefault with default headers values +func NewGetForgeInstanceDefault(code int) *GetForgeInstanceDefault { + return &GetForgeInstanceDefault{ + _statusCode: code, + } +} + +/* +GetForgeInstanceDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type GetForgeInstanceDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this get forge instance default response has a 2xx status code +func (o *GetForgeInstanceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get forge instance default response has a 3xx status code +func (o *GetForgeInstanceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get forge instance default response has a 4xx status code +func (o *GetForgeInstanceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get forge instance default response has a 5xx status code +func (o *GetForgeInstanceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get forge instance default response a status code equal to that given +func (o *GetForgeInstanceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get forge instance default response +func (o *GetForgeInstanceDefault) Code() int { + return o._statusCode +} + +func (o *GetForgeInstanceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}][%d] GetForgeInstance default %s", o._statusCode, payload) +} + +func (o *GetForgeInstanceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}][%d] GetForgeInstance default %s", o._statusCode, payload) +} + +func (o *GetForgeInstanceDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *GetForgeInstanceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/get_forge_instance_webhook_info_parameters.go b/client/forge_instances/get_forge_instance_webhook_info_parameters.go new file mode 100644 index 000000000..840d69ea5 --- /dev/null +++ b/client/forge_instances/get_forge_instance_webhook_info_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetForgeInstanceWebhookInfoParams creates a new GetForgeInstanceWebhookInfoParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewGetForgeInstanceWebhookInfoParams() *GetForgeInstanceWebhookInfoParams { + return &GetForgeInstanceWebhookInfoParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetForgeInstanceWebhookInfoParamsWithTimeout creates a new GetForgeInstanceWebhookInfoParams object +// with the ability to set a timeout on a request. +func NewGetForgeInstanceWebhookInfoParamsWithTimeout(timeout time.Duration) *GetForgeInstanceWebhookInfoParams { + return &GetForgeInstanceWebhookInfoParams{ + timeout: timeout, + } +} + +// NewGetForgeInstanceWebhookInfoParamsWithContext creates a new GetForgeInstanceWebhookInfoParams object +// with the ability to set a context for a request. +func NewGetForgeInstanceWebhookInfoParamsWithContext(ctx context.Context) *GetForgeInstanceWebhookInfoParams { + return &GetForgeInstanceWebhookInfoParams{ + Context: ctx, + } +} + +// NewGetForgeInstanceWebhookInfoParamsWithHTTPClient creates a new GetForgeInstanceWebhookInfoParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetForgeInstanceWebhookInfoParamsWithHTTPClient(client *http.Client) *GetForgeInstanceWebhookInfoParams { + return &GetForgeInstanceWebhookInfoParams{ + HTTPClient: client, + } +} + +/* +GetForgeInstanceWebhookInfoParams contains all the parameters to send to the API endpoint + + for the get forge instance webhook info operation. + + Typically these are written to a http.Request. +*/ +type GetForgeInstanceWebhookInfoParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get forge instance webhook info params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstanceWebhookInfoParams) WithDefaults() *GetForgeInstanceWebhookInfoParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get forge instance webhook info params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetForgeInstanceWebhookInfoParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) WithTimeout(timeout time.Duration) *GetForgeInstanceWebhookInfoParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) WithContext(ctx context.Context) *GetForgeInstanceWebhookInfoParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) WithHTTPClient(client *http.Client) *GetForgeInstanceWebhookInfoParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) WithForgeInstanceID(forgeInstanceID string) *GetForgeInstanceWebhookInfoParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the get forge instance webhook info params +func (o *GetForgeInstanceWebhookInfoParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetForgeInstanceWebhookInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/get_forge_instance_webhook_info_responses.go b/client/forge_instances/get_forge_instance_webhook_info_responses.go new file mode 100644 index 000000000..2e1cb1d27 --- /dev/null +++ b/client/forge_instances/get_forge_instance_webhook_info_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// GetForgeInstanceWebhookInfoReader is a Reader for the GetForgeInstanceWebhookInfo structure. +type GetForgeInstanceWebhookInfoReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetForgeInstanceWebhookInfoReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetForgeInstanceWebhookInfoOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetForgeInstanceWebhookInfoDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetForgeInstanceWebhookInfoOK creates a GetForgeInstanceWebhookInfoOK with default headers values +func NewGetForgeInstanceWebhookInfoOK() *GetForgeInstanceWebhookInfoOK { + return &GetForgeInstanceWebhookInfoOK{} +} + +/* +GetForgeInstanceWebhookInfoOK describes a response with status code 200, with default header values. + +HookInfo +*/ +type GetForgeInstanceWebhookInfoOK struct { + Payload garm_params.HookInfo +} + +// IsSuccess returns true when this get forge instance webhook info o k response has a 2xx status code +func (o *GetForgeInstanceWebhookInfoOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get forge instance webhook info o k response has a 3xx status code +func (o *GetForgeInstanceWebhookInfoOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get forge instance webhook info o k response has a 4xx status code +func (o *GetForgeInstanceWebhookInfoOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get forge instance webhook info o k response has a 5xx status code +func (o *GetForgeInstanceWebhookInfoOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get forge instance webhook info o k response a status code equal to that given +func (o *GetForgeInstanceWebhookInfoOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get forge instance webhook info o k response +func (o *GetForgeInstanceWebhookInfoOK) Code() int { + return 200 +} + +func (o *GetForgeInstanceWebhookInfoOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/webhook][%d] getForgeInstanceWebhookInfoOK %s", 200, payload) +} + +func (o *GetForgeInstanceWebhookInfoOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/webhook][%d] getForgeInstanceWebhookInfoOK %s", 200, payload) +} + +func (o *GetForgeInstanceWebhookInfoOK) GetPayload() garm_params.HookInfo { + return o.Payload +} + +func (o *GetForgeInstanceWebhookInfoOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetForgeInstanceWebhookInfoDefault creates a GetForgeInstanceWebhookInfoDefault with default headers values +func NewGetForgeInstanceWebhookInfoDefault(code int) *GetForgeInstanceWebhookInfoDefault { + return &GetForgeInstanceWebhookInfoDefault{ + _statusCode: code, + } +} + +/* +GetForgeInstanceWebhookInfoDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type GetForgeInstanceWebhookInfoDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this get forge instance webhook info default response has a 2xx status code +func (o *GetForgeInstanceWebhookInfoDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get forge instance webhook info default response has a 3xx status code +func (o *GetForgeInstanceWebhookInfoDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get forge instance webhook info default response has a 4xx status code +func (o *GetForgeInstanceWebhookInfoDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get forge instance webhook info default response has a 5xx status code +func (o *GetForgeInstanceWebhookInfoDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get forge instance webhook info default response a status code equal to that given +func (o *GetForgeInstanceWebhookInfoDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get forge instance webhook info default response +func (o *GetForgeInstanceWebhookInfoDefault) Code() int { + return o._statusCode +} + +func (o *GetForgeInstanceWebhookInfoDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/webhook][%d] GetForgeInstanceWebhookInfo default %s", o._statusCode, payload) +} + +func (o *GetForgeInstanceWebhookInfoDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/webhook][%d] GetForgeInstanceWebhookInfo default %s", o._statusCode, payload) +} + +func (o *GetForgeInstanceWebhookInfoDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *GetForgeInstanceWebhookInfoDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/install_forge_instance_webhook_parameters.go b/client/forge_instances/install_forge_instance_webhook_parameters.go new file mode 100644 index 000000000..d9922b255 --- /dev/null +++ b/client/forge_instances/install_forge_instance_webhook_parameters.go @@ -0,0 +1,173 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + garm_params "github.com/cloudbase/garm/params" +) + +// NewInstallForgeInstanceWebhookParams creates a new InstallForgeInstanceWebhookParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewInstallForgeInstanceWebhookParams() *InstallForgeInstanceWebhookParams { + return &InstallForgeInstanceWebhookParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewInstallForgeInstanceWebhookParamsWithTimeout creates a new InstallForgeInstanceWebhookParams object +// with the ability to set a timeout on a request. +func NewInstallForgeInstanceWebhookParamsWithTimeout(timeout time.Duration) *InstallForgeInstanceWebhookParams { + return &InstallForgeInstanceWebhookParams{ + timeout: timeout, + } +} + +// NewInstallForgeInstanceWebhookParamsWithContext creates a new InstallForgeInstanceWebhookParams object +// with the ability to set a context for a request. +func NewInstallForgeInstanceWebhookParamsWithContext(ctx context.Context) *InstallForgeInstanceWebhookParams { + return &InstallForgeInstanceWebhookParams{ + Context: ctx, + } +} + +// NewInstallForgeInstanceWebhookParamsWithHTTPClient creates a new InstallForgeInstanceWebhookParams object +// with the ability to set a custom HTTPClient for a request. +func NewInstallForgeInstanceWebhookParamsWithHTTPClient(client *http.Client) *InstallForgeInstanceWebhookParams { + return &InstallForgeInstanceWebhookParams{ + HTTPClient: client, + } +} + +/* +InstallForgeInstanceWebhookParams contains all the parameters to send to the API endpoint + + for the install forge instance webhook operation. + + Typically these are written to a http.Request. +*/ +type InstallForgeInstanceWebhookParams struct { + + /* Body. + + Parameters used when creating the forge instance webhook. + */ + Body garm_params.InstallWebhookParams + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the install forge instance webhook params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *InstallForgeInstanceWebhookParams) WithDefaults() *InstallForgeInstanceWebhookParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the install forge instance webhook params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *InstallForgeInstanceWebhookParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) WithTimeout(timeout time.Duration) *InstallForgeInstanceWebhookParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) WithContext(ctx context.Context) *InstallForgeInstanceWebhookParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) WithHTTPClient(client *http.Client) *InstallForgeInstanceWebhookParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) WithBody(body garm_params.InstallWebhookParams) *InstallForgeInstanceWebhookParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) SetBody(body garm_params.InstallWebhookParams) { + o.Body = body +} + +// WithForgeInstanceID adds the forgeInstanceID to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) WithForgeInstanceID(forgeInstanceID string) *InstallForgeInstanceWebhookParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the install forge instance webhook params +func (o *InstallForgeInstanceWebhookParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *InstallForgeInstanceWebhookParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/install_forge_instance_webhook_responses.go b/client/forge_instances/install_forge_instance_webhook_responses.go new file mode 100644 index 000000000..dc22389d8 --- /dev/null +++ b/client/forge_instances/install_forge_instance_webhook_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// InstallForgeInstanceWebhookReader is a Reader for the InstallForgeInstanceWebhook structure. +type InstallForgeInstanceWebhookReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *InstallForgeInstanceWebhookReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewInstallForgeInstanceWebhookOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewInstallForgeInstanceWebhookDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewInstallForgeInstanceWebhookOK creates a InstallForgeInstanceWebhookOK with default headers values +func NewInstallForgeInstanceWebhookOK() *InstallForgeInstanceWebhookOK { + return &InstallForgeInstanceWebhookOK{} +} + +/* +InstallForgeInstanceWebhookOK describes a response with status code 200, with default header values. + +HookInfo +*/ +type InstallForgeInstanceWebhookOK struct { + Payload garm_params.HookInfo +} + +// IsSuccess returns true when this install forge instance webhook o k response has a 2xx status code +func (o *InstallForgeInstanceWebhookOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this install forge instance webhook o k response has a 3xx status code +func (o *InstallForgeInstanceWebhookOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this install forge instance webhook o k response has a 4xx status code +func (o *InstallForgeInstanceWebhookOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this install forge instance webhook o k response has a 5xx status code +func (o *InstallForgeInstanceWebhookOK) IsServerError() bool { + return false +} + +// IsCode returns true when this install forge instance webhook o k response a status code equal to that given +func (o *InstallForgeInstanceWebhookOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the install forge instance webhook o k response +func (o *InstallForgeInstanceWebhookOK) Code() int { + return 200 +} + +func (o *InstallForgeInstanceWebhookOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/webhook][%d] installForgeInstanceWebhookOK %s", 200, payload) +} + +func (o *InstallForgeInstanceWebhookOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/webhook][%d] installForgeInstanceWebhookOK %s", 200, payload) +} + +func (o *InstallForgeInstanceWebhookOK) GetPayload() garm_params.HookInfo { + return o.Payload +} + +func (o *InstallForgeInstanceWebhookOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewInstallForgeInstanceWebhookDefault creates a InstallForgeInstanceWebhookDefault with default headers values +func NewInstallForgeInstanceWebhookDefault(code int) *InstallForgeInstanceWebhookDefault { + return &InstallForgeInstanceWebhookDefault{ + _statusCode: code, + } +} + +/* +InstallForgeInstanceWebhookDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type InstallForgeInstanceWebhookDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this install forge instance webhook default response has a 2xx status code +func (o *InstallForgeInstanceWebhookDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this install forge instance webhook default response has a 3xx status code +func (o *InstallForgeInstanceWebhookDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this install forge instance webhook default response has a 4xx status code +func (o *InstallForgeInstanceWebhookDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this install forge instance webhook default response has a 5xx status code +func (o *InstallForgeInstanceWebhookDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this install forge instance webhook default response a status code equal to that given +func (o *InstallForgeInstanceWebhookDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the install forge instance webhook default response +func (o *InstallForgeInstanceWebhookDefault) Code() int { + return o._statusCode +} + +func (o *InstallForgeInstanceWebhookDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/webhook][%d] InstallForgeInstanceWebhook default %s", o._statusCode, payload) +} + +func (o *InstallForgeInstanceWebhookDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /forge-instances/{forgeInstanceID}/webhook][%d] InstallForgeInstanceWebhook default %s", o._statusCode, payload) +} + +func (o *InstallForgeInstanceWebhookDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *InstallForgeInstanceWebhookDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/list_forge_instance_instances_parameters.go b/client/forge_instances/list_forge_instance_instances_parameters.go new file mode 100644 index 000000000..89cebb14d --- /dev/null +++ b/client/forge_instances/list_forge_instance_instances_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListForgeInstanceInstancesParams creates a new ListForgeInstanceInstancesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListForgeInstanceInstancesParams() *ListForgeInstanceInstancesParams { + return &ListForgeInstanceInstancesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListForgeInstanceInstancesParamsWithTimeout creates a new ListForgeInstanceInstancesParams object +// with the ability to set a timeout on a request. +func NewListForgeInstanceInstancesParamsWithTimeout(timeout time.Duration) *ListForgeInstanceInstancesParams { + return &ListForgeInstanceInstancesParams{ + timeout: timeout, + } +} + +// NewListForgeInstanceInstancesParamsWithContext creates a new ListForgeInstanceInstancesParams object +// with the ability to set a context for a request. +func NewListForgeInstanceInstancesParamsWithContext(ctx context.Context) *ListForgeInstanceInstancesParams { + return &ListForgeInstanceInstancesParams{ + Context: ctx, + } +} + +// NewListForgeInstanceInstancesParamsWithHTTPClient creates a new ListForgeInstanceInstancesParams object +// with the ability to set a custom HTTPClient for a request. +func NewListForgeInstanceInstancesParamsWithHTTPClient(client *http.Client) *ListForgeInstanceInstancesParams { + return &ListForgeInstanceInstancesParams{ + HTTPClient: client, + } +} + +/* +ListForgeInstanceInstancesParams contains all the parameters to send to the API endpoint + + for the list forge instance instances operation. + + Typically these are written to a http.Request. +*/ +type ListForgeInstanceInstancesParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list forge instance instances params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstanceInstancesParams) WithDefaults() *ListForgeInstanceInstancesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list forge instance instances params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstanceInstancesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) WithTimeout(timeout time.Duration) *ListForgeInstanceInstancesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) WithContext(ctx context.Context) *ListForgeInstanceInstancesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) WithHTTPClient(client *http.Client) *ListForgeInstanceInstancesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) WithForgeInstanceID(forgeInstanceID string) *ListForgeInstanceInstancesParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the list forge instance instances params +func (o *ListForgeInstanceInstancesParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *ListForgeInstanceInstancesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/list_forge_instance_instances_responses.go b/client/forge_instances/list_forge_instance_instances_responses.go new file mode 100644 index 000000000..2fab50456 --- /dev/null +++ b/client/forge_instances/list_forge_instance_instances_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// ListForgeInstanceInstancesReader is a Reader for the ListForgeInstanceInstances structure. +type ListForgeInstanceInstancesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListForgeInstanceInstancesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListForgeInstanceInstancesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListForgeInstanceInstancesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListForgeInstanceInstancesOK creates a ListForgeInstanceInstancesOK with default headers values +func NewListForgeInstanceInstancesOK() *ListForgeInstanceInstancesOK { + return &ListForgeInstanceInstancesOK{} +} + +/* +ListForgeInstanceInstancesOK describes a response with status code 200, with default header values. + +Instances +*/ +type ListForgeInstanceInstancesOK struct { + Payload garm_params.Instances +} + +// IsSuccess returns true when this list forge instance instances o k response has a 2xx status code +func (o *ListForgeInstanceInstancesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list forge instance instances o k response has a 3xx status code +func (o *ListForgeInstanceInstancesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list forge instance instances o k response has a 4xx status code +func (o *ListForgeInstanceInstancesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list forge instance instances o k response has a 5xx status code +func (o *ListForgeInstanceInstancesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list forge instance instances o k response a status code equal to that given +func (o *ListForgeInstanceInstancesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list forge instance instances o k response +func (o *ListForgeInstanceInstancesOK) Code() int { + return 200 +} + +func (o *ListForgeInstanceInstancesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/instances][%d] listForgeInstanceInstancesOK %s", 200, payload) +} + +func (o *ListForgeInstanceInstancesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/instances][%d] listForgeInstanceInstancesOK %s", 200, payload) +} + +func (o *ListForgeInstanceInstancesOK) GetPayload() garm_params.Instances { + return o.Payload +} + +func (o *ListForgeInstanceInstancesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListForgeInstanceInstancesDefault creates a ListForgeInstanceInstancesDefault with default headers values +func NewListForgeInstanceInstancesDefault(code int) *ListForgeInstanceInstancesDefault { + return &ListForgeInstanceInstancesDefault{ + _statusCode: code, + } +} + +/* +ListForgeInstanceInstancesDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type ListForgeInstanceInstancesDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this list forge instance instances default response has a 2xx status code +func (o *ListForgeInstanceInstancesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list forge instance instances default response has a 3xx status code +func (o *ListForgeInstanceInstancesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list forge instance instances default response has a 4xx status code +func (o *ListForgeInstanceInstancesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list forge instance instances default response has a 5xx status code +func (o *ListForgeInstanceInstancesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list forge instance instances default response a status code equal to that given +func (o *ListForgeInstanceInstancesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list forge instance instances default response +func (o *ListForgeInstanceInstancesDefault) Code() int { + return o._statusCode +} + +func (o *ListForgeInstanceInstancesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/instances][%d] ListForgeInstanceInstances default %s", o._statusCode, payload) +} + +func (o *ListForgeInstanceInstancesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/instances][%d] ListForgeInstanceInstances default %s", o._statusCode, payload) +} + +func (o *ListForgeInstanceInstancesDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *ListForgeInstanceInstancesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/list_forge_instance_pools_parameters.go b/client/forge_instances/list_forge_instance_pools_parameters.go new file mode 100644 index 000000000..d51670785 --- /dev/null +++ b/client/forge_instances/list_forge_instance_pools_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListForgeInstancePoolsParams creates a new ListForgeInstancePoolsParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListForgeInstancePoolsParams() *ListForgeInstancePoolsParams { + return &ListForgeInstancePoolsParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListForgeInstancePoolsParamsWithTimeout creates a new ListForgeInstancePoolsParams object +// with the ability to set a timeout on a request. +func NewListForgeInstancePoolsParamsWithTimeout(timeout time.Duration) *ListForgeInstancePoolsParams { + return &ListForgeInstancePoolsParams{ + timeout: timeout, + } +} + +// NewListForgeInstancePoolsParamsWithContext creates a new ListForgeInstancePoolsParams object +// with the ability to set a context for a request. +func NewListForgeInstancePoolsParamsWithContext(ctx context.Context) *ListForgeInstancePoolsParams { + return &ListForgeInstancePoolsParams{ + Context: ctx, + } +} + +// NewListForgeInstancePoolsParamsWithHTTPClient creates a new ListForgeInstancePoolsParams object +// with the ability to set a custom HTTPClient for a request. +func NewListForgeInstancePoolsParamsWithHTTPClient(client *http.Client) *ListForgeInstancePoolsParams { + return &ListForgeInstancePoolsParams{ + HTTPClient: client, + } +} + +/* +ListForgeInstancePoolsParams contains all the parameters to send to the API endpoint + + for the list forge instance pools operation. + + Typically these are written to a http.Request. +*/ +type ListForgeInstancePoolsParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list forge instance pools params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstancePoolsParams) WithDefaults() *ListForgeInstancePoolsParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list forge instance pools params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstancePoolsParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) WithTimeout(timeout time.Duration) *ListForgeInstancePoolsParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) WithContext(ctx context.Context) *ListForgeInstancePoolsParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) WithHTTPClient(client *http.Client) *ListForgeInstancePoolsParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) WithForgeInstanceID(forgeInstanceID string) *ListForgeInstancePoolsParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the list forge instance pools params +func (o *ListForgeInstancePoolsParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *ListForgeInstancePoolsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/list_forge_instance_pools_responses.go b/client/forge_instances/list_forge_instance_pools_responses.go new file mode 100644 index 000000000..b77236047 --- /dev/null +++ b/client/forge_instances/list_forge_instance_pools_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// ListForgeInstancePoolsReader is a Reader for the ListForgeInstancePools structure. +type ListForgeInstancePoolsReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListForgeInstancePoolsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListForgeInstancePoolsOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListForgeInstancePoolsDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListForgeInstancePoolsOK creates a ListForgeInstancePoolsOK with default headers values +func NewListForgeInstancePoolsOK() *ListForgeInstancePoolsOK { + return &ListForgeInstancePoolsOK{} +} + +/* +ListForgeInstancePoolsOK describes a response with status code 200, with default header values. + +Pools +*/ +type ListForgeInstancePoolsOK struct { + Payload garm_params.Pools +} + +// IsSuccess returns true when this list forge instance pools o k response has a 2xx status code +func (o *ListForgeInstancePoolsOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list forge instance pools o k response has a 3xx status code +func (o *ListForgeInstancePoolsOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list forge instance pools o k response has a 4xx status code +func (o *ListForgeInstancePoolsOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list forge instance pools o k response has a 5xx status code +func (o *ListForgeInstancePoolsOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list forge instance pools o k response a status code equal to that given +func (o *ListForgeInstancePoolsOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list forge instance pools o k response +func (o *ListForgeInstancePoolsOK) Code() int { + return 200 +} + +func (o *ListForgeInstancePoolsOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools][%d] listForgeInstancePoolsOK %s", 200, payload) +} + +func (o *ListForgeInstancePoolsOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools][%d] listForgeInstancePoolsOK %s", 200, payload) +} + +func (o *ListForgeInstancePoolsOK) GetPayload() garm_params.Pools { + return o.Payload +} + +func (o *ListForgeInstancePoolsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListForgeInstancePoolsDefault creates a ListForgeInstancePoolsDefault with default headers values +func NewListForgeInstancePoolsDefault(code int) *ListForgeInstancePoolsDefault { + return &ListForgeInstancePoolsDefault{ + _statusCode: code, + } +} + +/* +ListForgeInstancePoolsDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type ListForgeInstancePoolsDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this list forge instance pools default response has a 2xx status code +func (o *ListForgeInstancePoolsDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list forge instance pools default response has a 3xx status code +func (o *ListForgeInstancePoolsDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list forge instance pools default response has a 4xx status code +func (o *ListForgeInstancePoolsDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list forge instance pools default response has a 5xx status code +func (o *ListForgeInstancePoolsDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list forge instance pools default response a status code equal to that given +func (o *ListForgeInstancePoolsDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list forge instance pools default response +func (o *ListForgeInstancePoolsDefault) Code() int { + return o._statusCode +} + +func (o *ListForgeInstancePoolsDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools][%d] ListForgeInstancePools default %s", o._statusCode, payload) +} + +func (o *ListForgeInstancePoolsDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances/{forgeInstanceID}/pools][%d] ListForgeInstancePools default %s", o._statusCode, payload) +} + +func (o *ListForgeInstancePoolsDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *ListForgeInstancePoolsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/list_forge_instances_parameters.go b/client/forge_instances/list_forge_instances_parameters.go new file mode 100644 index 000000000..6fa055764 --- /dev/null +++ b/client/forge_instances/list_forge_instances_parameters.go @@ -0,0 +1,163 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListForgeInstancesParams creates a new ListForgeInstancesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListForgeInstancesParams() *ListForgeInstancesParams { + return &ListForgeInstancesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListForgeInstancesParamsWithTimeout creates a new ListForgeInstancesParams object +// with the ability to set a timeout on a request. +func NewListForgeInstancesParamsWithTimeout(timeout time.Duration) *ListForgeInstancesParams { + return &ListForgeInstancesParams{ + timeout: timeout, + } +} + +// NewListForgeInstancesParamsWithContext creates a new ListForgeInstancesParams object +// with the ability to set a context for a request. +func NewListForgeInstancesParamsWithContext(ctx context.Context) *ListForgeInstancesParams { + return &ListForgeInstancesParams{ + Context: ctx, + } +} + +// NewListForgeInstancesParamsWithHTTPClient creates a new ListForgeInstancesParams object +// with the ability to set a custom HTTPClient for a request. +func NewListForgeInstancesParamsWithHTTPClient(client *http.Client) *ListForgeInstancesParams { + return &ListForgeInstancesParams{ + HTTPClient: client, + } +} + +/* +ListForgeInstancesParams contains all the parameters to send to the API endpoint + + for the list forge instances operation. + + Typically these are written to a http.Request. +*/ +type ListForgeInstancesParams struct { + + /* Endpoint. + + Exact endpoint name to filter by + */ + Endpoint *string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list forge instances params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstancesParams) WithDefaults() *ListForgeInstancesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list forge instances params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListForgeInstancesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list forge instances params +func (o *ListForgeInstancesParams) WithTimeout(timeout time.Duration) *ListForgeInstancesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list forge instances params +func (o *ListForgeInstancesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list forge instances params +func (o *ListForgeInstancesParams) WithContext(ctx context.Context) *ListForgeInstancesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list forge instances params +func (o *ListForgeInstancesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list forge instances params +func (o *ListForgeInstancesParams) WithHTTPClient(client *http.Client) *ListForgeInstancesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list forge instances params +func (o *ListForgeInstancesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithEndpoint adds the endpoint to the list forge instances params +func (o *ListForgeInstancesParams) WithEndpoint(endpoint *string) *ListForgeInstancesParams { + o.SetEndpoint(endpoint) + return o +} + +// SetEndpoint adds the endpoint to the list forge instances params +func (o *ListForgeInstancesParams) SetEndpoint(endpoint *string) { + o.Endpoint = endpoint +} + +// WriteToRequest writes these params to a swagger request +func (o *ListForgeInstancesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Endpoint != nil { + + // query param endpoint + var qrEndpoint string + + if o.Endpoint != nil { + qrEndpoint = *o.Endpoint + } + qEndpoint := qrEndpoint + if qEndpoint != "" { + + if err := r.SetQueryParam("endpoint", qEndpoint); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/list_forge_instances_responses.go b/client/forge_instances/list_forge_instances_responses.go new file mode 100644 index 000000000..11cf8a34b --- /dev/null +++ b/client/forge_instances/list_forge_instances_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// ListForgeInstancesReader is a Reader for the ListForgeInstances structure. +type ListForgeInstancesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListForgeInstancesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListForgeInstancesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListForgeInstancesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListForgeInstancesOK creates a ListForgeInstancesOK with default headers values +func NewListForgeInstancesOK() *ListForgeInstancesOK { + return &ListForgeInstancesOK{} +} + +/* +ListForgeInstancesOK describes a response with status code 200, with default header values. + +ForgeInstances +*/ +type ListForgeInstancesOK struct { + Payload garm_params.ForgeInstances +} + +// IsSuccess returns true when this list forge instances o k response has a 2xx status code +func (o *ListForgeInstancesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list forge instances o k response has a 3xx status code +func (o *ListForgeInstancesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list forge instances o k response has a 4xx status code +func (o *ListForgeInstancesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list forge instances o k response has a 5xx status code +func (o *ListForgeInstancesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list forge instances o k response a status code equal to that given +func (o *ListForgeInstancesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list forge instances o k response +func (o *ListForgeInstancesOK) Code() int { + return 200 +} + +func (o *ListForgeInstancesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances][%d] listForgeInstancesOK %s", 200, payload) +} + +func (o *ListForgeInstancesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances][%d] listForgeInstancesOK %s", 200, payload) +} + +func (o *ListForgeInstancesOK) GetPayload() garm_params.ForgeInstances { + return o.Payload +} + +func (o *ListForgeInstancesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListForgeInstancesDefault creates a ListForgeInstancesDefault with default headers values +func NewListForgeInstancesDefault(code int) *ListForgeInstancesDefault { + return &ListForgeInstancesDefault{ + _statusCode: code, + } +} + +/* +ListForgeInstancesDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type ListForgeInstancesDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this list forge instances default response has a 2xx status code +func (o *ListForgeInstancesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list forge instances default response has a 3xx status code +func (o *ListForgeInstancesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list forge instances default response has a 4xx status code +func (o *ListForgeInstancesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list forge instances default response has a 5xx status code +func (o *ListForgeInstancesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list forge instances default response a status code equal to that given +func (o *ListForgeInstancesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list forge instances default response +func (o *ListForgeInstancesDefault) Code() int { + return o._statusCode +} + +func (o *ListForgeInstancesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances][%d] ListForgeInstances default %s", o._statusCode, payload) +} + +func (o *ListForgeInstancesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /forge-instances][%d] ListForgeInstances default %s", o._statusCode, payload) +} + +func (o *ListForgeInstancesDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *ListForgeInstancesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/uninstall_forge_instance_webhook_parameters.go b/client/forge_instances/uninstall_forge_instance_webhook_parameters.go new file mode 100644 index 000000000..5fc200876 --- /dev/null +++ b/client/forge_instances/uninstall_forge_instance_webhook_parameters.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewUninstallForgeInstanceWebhookParams creates a new UninstallForgeInstanceWebhookParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewUninstallForgeInstanceWebhookParams() *UninstallForgeInstanceWebhookParams { + return &UninstallForgeInstanceWebhookParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUninstallForgeInstanceWebhookParamsWithTimeout creates a new UninstallForgeInstanceWebhookParams object +// with the ability to set a timeout on a request. +func NewUninstallForgeInstanceWebhookParamsWithTimeout(timeout time.Duration) *UninstallForgeInstanceWebhookParams { + return &UninstallForgeInstanceWebhookParams{ + timeout: timeout, + } +} + +// NewUninstallForgeInstanceWebhookParamsWithContext creates a new UninstallForgeInstanceWebhookParams object +// with the ability to set a context for a request. +func NewUninstallForgeInstanceWebhookParamsWithContext(ctx context.Context) *UninstallForgeInstanceWebhookParams { + return &UninstallForgeInstanceWebhookParams{ + Context: ctx, + } +} + +// NewUninstallForgeInstanceWebhookParamsWithHTTPClient creates a new UninstallForgeInstanceWebhookParams object +// with the ability to set a custom HTTPClient for a request. +func NewUninstallForgeInstanceWebhookParamsWithHTTPClient(client *http.Client) *UninstallForgeInstanceWebhookParams { + return &UninstallForgeInstanceWebhookParams{ + HTTPClient: client, + } +} + +/* +UninstallForgeInstanceWebhookParams contains all the parameters to send to the API endpoint + + for the uninstall forge instance webhook operation. + + Typically these are written to a http.Request. +*/ +type UninstallForgeInstanceWebhookParams struct { + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the uninstall forge instance webhook params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UninstallForgeInstanceWebhookParams) WithDefaults() *UninstallForgeInstanceWebhookParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the uninstall forge instance webhook params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UninstallForgeInstanceWebhookParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) WithTimeout(timeout time.Duration) *UninstallForgeInstanceWebhookParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) WithContext(ctx context.Context) *UninstallForgeInstanceWebhookParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) WithHTTPClient(client *http.Client) *UninstallForgeInstanceWebhookParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithForgeInstanceID adds the forgeInstanceID to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) WithForgeInstanceID(forgeInstanceID string) *UninstallForgeInstanceWebhookParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the uninstall forge instance webhook params +func (o *UninstallForgeInstanceWebhookParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *UninstallForgeInstanceWebhookParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/uninstall_forge_instance_webhook_responses.go b/client/forge_instances/uninstall_forge_instance_webhook_responses.go new file mode 100644 index 000000000..f0beb8837 --- /dev/null +++ b/client/forge_instances/uninstall_forge_instance_webhook_responses.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" +) + +// UninstallForgeInstanceWebhookReader is a Reader for the UninstallForgeInstanceWebhook structure. +type UninstallForgeInstanceWebhookReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UninstallForgeInstanceWebhookReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + result := NewUninstallForgeInstanceWebhookDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result +} + +// NewUninstallForgeInstanceWebhookDefault creates a UninstallForgeInstanceWebhookDefault with default headers values +func NewUninstallForgeInstanceWebhookDefault(code int) *UninstallForgeInstanceWebhookDefault { + return &UninstallForgeInstanceWebhookDefault{ + _statusCode: code, + } +} + +/* +UninstallForgeInstanceWebhookDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type UninstallForgeInstanceWebhookDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this uninstall forge instance webhook default response has a 2xx status code +func (o *UninstallForgeInstanceWebhookDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this uninstall forge instance webhook default response has a 3xx status code +func (o *UninstallForgeInstanceWebhookDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this uninstall forge instance webhook default response has a 4xx status code +func (o *UninstallForgeInstanceWebhookDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this uninstall forge instance webhook default response has a 5xx status code +func (o *UninstallForgeInstanceWebhookDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this uninstall forge instance webhook default response a status code equal to that given +func (o *UninstallForgeInstanceWebhookDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the uninstall forge instance webhook default response +func (o *UninstallForgeInstanceWebhookDefault) Code() int { + return o._statusCode +} + +func (o *UninstallForgeInstanceWebhookDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}/webhook][%d] UninstallForgeInstanceWebhook default %s", o._statusCode, payload) +} + +func (o *UninstallForgeInstanceWebhookDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /forge-instances/{forgeInstanceID}/webhook][%d] UninstallForgeInstanceWebhook default %s", o._statusCode, payload) +} + +func (o *UninstallForgeInstanceWebhookDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *UninstallForgeInstanceWebhookDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/update_forge_instance_parameters.go b/client/forge_instances/update_forge_instance_parameters.go new file mode 100644 index 000000000..16afc137b --- /dev/null +++ b/client/forge_instances/update_forge_instance_parameters.go @@ -0,0 +1,173 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + garm_params "github.com/cloudbase/garm/params" +) + +// NewUpdateForgeInstanceParams creates a new UpdateForgeInstanceParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewUpdateForgeInstanceParams() *UpdateForgeInstanceParams { + return &UpdateForgeInstanceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUpdateForgeInstanceParamsWithTimeout creates a new UpdateForgeInstanceParams object +// with the ability to set a timeout on a request. +func NewUpdateForgeInstanceParamsWithTimeout(timeout time.Duration) *UpdateForgeInstanceParams { + return &UpdateForgeInstanceParams{ + timeout: timeout, + } +} + +// NewUpdateForgeInstanceParamsWithContext creates a new UpdateForgeInstanceParams object +// with the ability to set a context for a request. +func NewUpdateForgeInstanceParamsWithContext(ctx context.Context) *UpdateForgeInstanceParams { + return &UpdateForgeInstanceParams{ + Context: ctx, + } +} + +// NewUpdateForgeInstanceParamsWithHTTPClient creates a new UpdateForgeInstanceParams object +// with the ability to set a custom HTTPClient for a request. +func NewUpdateForgeInstanceParamsWithHTTPClient(client *http.Client) *UpdateForgeInstanceParams { + return &UpdateForgeInstanceParams{ + HTTPClient: client, + } +} + +/* +UpdateForgeInstanceParams contains all the parameters to send to the API endpoint + + for the update forge instance operation. + + Typically these are written to a http.Request. +*/ +type UpdateForgeInstanceParams struct { + + /* Body. + + Parameters used when updating the forge instance. + */ + Body garm_params.UpdateEntityParams + + /* ForgeInstanceID. + + The ID of the forge instance to update. + */ + ForgeInstanceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the update forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateForgeInstanceParams) WithDefaults() *UpdateForgeInstanceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the update forge instance params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateForgeInstanceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the update forge instance params +func (o *UpdateForgeInstanceParams) WithTimeout(timeout time.Duration) *UpdateForgeInstanceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the update forge instance params +func (o *UpdateForgeInstanceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the update forge instance params +func (o *UpdateForgeInstanceParams) WithContext(ctx context.Context) *UpdateForgeInstanceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the update forge instance params +func (o *UpdateForgeInstanceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the update forge instance params +func (o *UpdateForgeInstanceParams) WithHTTPClient(client *http.Client) *UpdateForgeInstanceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the update forge instance params +func (o *UpdateForgeInstanceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the update forge instance params +func (o *UpdateForgeInstanceParams) WithBody(body garm_params.UpdateEntityParams) *UpdateForgeInstanceParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the update forge instance params +func (o *UpdateForgeInstanceParams) SetBody(body garm_params.UpdateEntityParams) { + o.Body = body +} + +// WithForgeInstanceID adds the forgeInstanceID to the update forge instance params +func (o *UpdateForgeInstanceParams) WithForgeInstanceID(forgeInstanceID string) *UpdateForgeInstanceParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the update forge instance params +func (o *UpdateForgeInstanceParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WriteToRequest writes these params to a swagger request +func (o *UpdateForgeInstanceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/update_forge_instance_pool_parameters.go b/client/forge_instances/update_forge_instance_pool_parameters.go new file mode 100644 index 000000000..cdb0a8d47 --- /dev/null +++ b/client/forge_instances/update_forge_instance_pool_parameters.go @@ -0,0 +1,195 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + garm_params "github.com/cloudbase/garm/params" +) + +// NewUpdateForgeInstancePoolParams creates a new UpdateForgeInstancePoolParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewUpdateForgeInstancePoolParams() *UpdateForgeInstancePoolParams { + return &UpdateForgeInstancePoolParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUpdateForgeInstancePoolParamsWithTimeout creates a new UpdateForgeInstancePoolParams object +// with the ability to set a timeout on a request. +func NewUpdateForgeInstancePoolParamsWithTimeout(timeout time.Duration) *UpdateForgeInstancePoolParams { + return &UpdateForgeInstancePoolParams{ + timeout: timeout, + } +} + +// NewUpdateForgeInstancePoolParamsWithContext creates a new UpdateForgeInstancePoolParams object +// with the ability to set a context for a request. +func NewUpdateForgeInstancePoolParamsWithContext(ctx context.Context) *UpdateForgeInstancePoolParams { + return &UpdateForgeInstancePoolParams{ + Context: ctx, + } +} + +// NewUpdateForgeInstancePoolParamsWithHTTPClient creates a new UpdateForgeInstancePoolParams object +// with the ability to set a custom HTTPClient for a request. +func NewUpdateForgeInstancePoolParamsWithHTTPClient(client *http.Client) *UpdateForgeInstancePoolParams { + return &UpdateForgeInstancePoolParams{ + HTTPClient: client, + } +} + +/* +UpdateForgeInstancePoolParams contains all the parameters to send to the API endpoint + + for the update forge instance pool operation. + + Typically these are written to a http.Request. +*/ +type UpdateForgeInstancePoolParams struct { + + /* Body. + + Parameters used when updating the forge instance pool. + */ + Body garm_params.UpdatePoolParams + + /* ForgeInstanceID. + + Forge instance ID. + */ + ForgeInstanceID string + + /* PoolID. + + ID of the forge instance pool to update. + */ + PoolID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the update forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateForgeInstancePoolParams) WithDefaults() *UpdateForgeInstancePoolParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the update forge instance pool params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateForgeInstancePoolParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithTimeout(timeout time.Duration) *UpdateForgeInstancePoolParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithContext(ctx context.Context) *UpdateForgeInstancePoolParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithHTTPClient(client *http.Client) *UpdateForgeInstancePoolParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithBody(body garm_params.UpdatePoolParams) *UpdateForgeInstancePoolParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetBody(body garm_params.UpdatePoolParams) { + o.Body = body +} + +// WithForgeInstanceID adds the forgeInstanceID to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithForgeInstanceID(forgeInstanceID string) *UpdateForgeInstancePoolParams { + o.SetForgeInstanceID(forgeInstanceID) + return o +} + +// SetForgeInstanceID adds the forgeInstanceId to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetForgeInstanceID(forgeInstanceID string) { + o.ForgeInstanceID = forgeInstanceID +} + +// WithPoolID adds the poolID to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) WithPoolID(poolID string) *UpdateForgeInstancePoolParams { + o.SetPoolID(poolID) + return o +} + +// SetPoolID adds the poolId to the update forge instance pool params +func (o *UpdateForgeInstancePoolParams) SetPoolID(poolID string) { + o.PoolID = poolID +} + +// WriteToRequest writes these params to a swagger request +func (o *UpdateForgeInstancePoolParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + // path param forgeInstanceID + if err := r.SetPathParam("forgeInstanceID", o.ForgeInstanceID); err != nil { + return err + } + + // path param poolID + if err := r.SetPathParam("poolID", o.PoolID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/forge_instances/update_forge_instance_pool_responses.go b/client/forge_instances/update_forge_instance_pool_responses.go new file mode 100644 index 000000000..bf22701af --- /dev/null +++ b/client/forge_instances/update_forge_instance_pool_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// UpdateForgeInstancePoolReader is a Reader for the UpdateForgeInstancePool structure. +type UpdateForgeInstancePoolReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UpdateForgeInstancePoolReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewUpdateForgeInstancePoolOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUpdateForgeInstancePoolDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUpdateForgeInstancePoolOK creates a UpdateForgeInstancePoolOK with default headers values +func NewUpdateForgeInstancePoolOK() *UpdateForgeInstancePoolOK { + return &UpdateForgeInstancePoolOK{} +} + +/* +UpdateForgeInstancePoolOK describes a response with status code 200, with default header values. + +Pool +*/ +type UpdateForgeInstancePoolOK struct { + Payload garm_params.Pool +} + +// IsSuccess returns true when this update forge instance pool o k response has a 2xx status code +func (o *UpdateForgeInstancePoolOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this update forge instance pool o k response has a 3xx status code +func (o *UpdateForgeInstancePoolOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this update forge instance pool o k response has a 4xx status code +func (o *UpdateForgeInstancePoolOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this update forge instance pool o k response has a 5xx status code +func (o *UpdateForgeInstancePoolOK) IsServerError() bool { + return false +} + +// IsCode returns true when this update forge instance pool o k response a status code equal to that given +func (o *UpdateForgeInstancePoolOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the update forge instance pool o k response +func (o *UpdateForgeInstancePoolOK) Code() int { + return 200 +} + +func (o *UpdateForgeInstancePoolOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] updateForgeInstancePoolOK %s", 200, payload) +} + +func (o *UpdateForgeInstancePoolOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] updateForgeInstancePoolOK %s", 200, payload) +} + +func (o *UpdateForgeInstancePoolOK) GetPayload() garm_params.Pool { + return o.Payload +} + +func (o *UpdateForgeInstancePoolOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewUpdateForgeInstancePoolDefault creates a UpdateForgeInstancePoolDefault with default headers values +func NewUpdateForgeInstancePoolDefault(code int) *UpdateForgeInstancePoolDefault { + return &UpdateForgeInstancePoolDefault{ + _statusCode: code, + } +} + +/* +UpdateForgeInstancePoolDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type UpdateForgeInstancePoolDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this update forge instance pool default response has a 2xx status code +func (o *UpdateForgeInstancePoolDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this update forge instance pool default response has a 3xx status code +func (o *UpdateForgeInstancePoolDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this update forge instance pool default response has a 4xx status code +func (o *UpdateForgeInstancePoolDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this update forge instance pool default response has a 5xx status code +func (o *UpdateForgeInstancePoolDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this update forge instance pool default response a status code equal to that given +func (o *UpdateForgeInstancePoolDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the update forge instance pool default response +func (o *UpdateForgeInstancePoolDefault) Code() int { + return o._statusCode +} + +func (o *UpdateForgeInstancePoolDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] UpdateForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *UpdateForgeInstancePoolDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}/pools/{poolID}][%d] UpdateForgeInstancePool default %s", o._statusCode, payload) +} + +func (o *UpdateForgeInstancePoolDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *UpdateForgeInstancePoolDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/forge_instances/update_forge_instance_responses.go b/client/forge_instances/update_forge_instance_responses.go new file mode 100644 index 000000000..bc44bbfa0 --- /dev/null +++ b/client/forge_instances/update_forge_instance_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package forge_instances + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + stderrors "errors" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + apiserver_params "github.com/cloudbase/garm/apiserver/params" + garm_params "github.com/cloudbase/garm/params" +) + +// UpdateForgeInstanceReader is a Reader for the UpdateForgeInstance structure. +type UpdateForgeInstanceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UpdateForgeInstanceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewUpdateForgeInstanceOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUpdateForgeInstanceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUpdateForgeInstanceOK creates a UpdateForgeInstanceOK with default headers values +func NewUpdateForgeInstanceOK() *UpdateForgeInstanceOK { + return &UpdateForgeInstanceOK{} +} + +/* +UpdateForgeInstanceOK describes a response with status code 200, with default header values. + +ForgeInstance +*/ +type UpdateForgeInstanceOK struct { + Payload garm_params.ForgeInstance +} + +// IsSuccess returns true when this update forge instance o k response has a 2xx status code +func (o *UpdateForgeInstanceOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this update forge instance o k response has a 3xx status code +func (o *UpdateForgeInstanceOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this update forge instance o k response has a 4xx status code +func (o *UpdateForgeInstanceOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this update forge instance o k response has a 5xx status code +func (o *UpdateForgeInstanceOK) IsServerError() bool { + return false +} + +// IsCode returns true when this update forge instance o k response a status code equal to that given +func (o *UpdateForgeInstanceOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the update forge instance o k response +func (o *UpdateForgeInstanceOK) Code() int { + return 200 +} + +func (o *UpdateForgeInstanceOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}][%d] updateForgeInstanceOK %s", 200, payload) +} + +func (o *UpdateForgeInstanceOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}][%d] updateForgeInstanceOK %s", 200, payload) +} + +func (o *UpdateForgeInstanceOK) GetPayload() garm_params.ForgeInstance { + return o.Payload +} + +func (o *UpdateForgeInstanceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewUpdateForgeInstanceDefault creates a UpdateForgeInstanceDefault with default headers values +func NewUpdateForgeInstanceDefault(code int) *UpdateForgeInstanceDefault { + return &UpdateForgeInstanceDefault{ + _statusCode: code, + } +} + +/* +UpdateForgeInstanceDefault describes a response with status code -1, with default header values. + +APIErrorResponse +*/ +type UpdateForgeInstanceDefault struct { + _statusCode int + + Payload apiserver_params.APIErrorResponse +} + +// IsSuccess returns true when this update forge instance default response has a 2xx status code +func (o *UpdateForgeInstanceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this update forge instance default response has a 3xx status code +func (o *UpdateForgeInstanceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this update forge instance default response has a 4xx status code +func (o *UpdateForgeInstanceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this update forge instance default response has a 5xx status code +func (o *UpdateForgeInstanceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this update forge instance default response a status code equal to that given +func (o *UpdateForgeInstanceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the update forge instance default response +func (o *UpdateForgeInstanceDefault) Code() int { + return o._statusCode +} + +func (o *UpdateForgeInstanceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}][%d] UpdateForgeInstance default %s", o._statusCode, payload) +} + +func (o *UpdateForgeInstanceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /forge-instances/{forgeInstanceID}][%d] UpdateForgeInstance default %s", o._statusCode, payload) +} + +func (o *UpdateForgeInstanceDefault) GetPayload() apiserver_params.APIErrorResponse { + return o.Payload +} + +func (o *UpdateForgeInstanceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} diff --git a/client/garm_api_client.go b/client/garm_api_client.go index d8c88f133..fb4de8621 100644 --- a/client/garm_api_client.go +++ b/client/garm_api_client.go @@ -16,6 +16,7 @@ import ( "github.com/cloudbase/garm/client/endpoints" "github.com/cloudbase/garm/client/enterprises" "github.com/cloudbase/garm/client/first_run" + "github.com/cloudbase/garm/client/forge_instances" "github.com/cloudbase/garm/client/instances" "github.com/cloudbase/garm/client/jobs" "github.com/cloudbase/garm/client/login" @@ -78,6 +79,7 @@ func New(transport runtime.ClientTransport, formats strfmt.Registry) *GarmAPI { cli.Endpoints = endpoints.New(transport, formats) cli.Enterprises = enterprises.New(transport, formats) cli.FirstRun = first_run.New(transport, formats) + cli.ForgeInstances = forge_instances.New(transport, formats) cli.Instances = instances.New(transport, formats) cli.Jobs = jobs.New(transport, formats) cli.Login = login.New(transport, formats) @@ -146,6 +148,8 @@ type GarmAPI struct { FirstRun first_run.ClientService + ForgeInstances forge_instances.ClientService + Instances instances.ClientService Jobs jobs.ClientService @@ -182,6 +186,7 @@ func (c *GarmAPI) SetTransport(transport runtime.ClientTransport) { c.Endpoints.SetTransport(transport) c.Enterprises.SetTransport(transport) c.FirstRun.SetTransport(transport) + c.ForgeInstances.SetTransport(transport) c.Instances.SetTransport(transport) c.Jobs.SetTransport(transport) c.Login.SetTransport(transport) diff --git a/cmd/garm-cli/cmd/forge_instance.go b/cmd/garm-cli/cmd/forge_instance.go new file mode 100644 index 000000000..a682dd82e --- /dev/null +++ b/cmd/garm-cli/cmd/forge_instance.go @@ -0,0 +1,482 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 cmd + +import ( + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" + + "github.com/cloudbase/garm-provider-common/util" + apiClientForgeInstances "github.com/cloudbase/garm/client/forge_instances" + "github.com/cloudbase/garm/cmd/garm-cli/common" + "github.com/cloudbase/garm/params" +) + +var ( + forgeInstanceEndpoint string + forgeInstanceWebhookSecret string + forgeInstanceRandomSecret bool + forgeInstanceCreds string + forgeInstanceForgeType string + forgeInstanceAgentMode bool + installForgeInstanceWebhook bool + insecureForgeInstanceWebhook bool + keepForgeInstanceWebhook bool +) + +var forgeInstanceCmd = &cobra.Command{ + Use: "forge-instance", + Aliases: []string{"fi"}, + SilenceUsage: true, + Short: "Manage forge instances", + Long: `Add, remove or update forge instances for which we manage +self hosted runners. + +A forge instance represents a Gitea (or compatible) server +for which garm manages instance-level runner pools.`, + Run: nil, +} + +var forgeInstanceAddCmd = &cobra.Command{ + Use: "add", + Aliases: []string{"create"}, + Short: "Add forge instance", + Long: `Add a new forge instance to the manager.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, _ []string) error { + if needsInit { + return errNeedsInitError + } + + if forgeInstanceRandomSecret { + secret, err := util.GetRandomString(32) + if err != nil { + return err + } + forgeInstanceWebhookSecret = secret + } + + newReq := apiClientForgeInstances.NewCreateForgeInstanceParams() + newReq.Body = params.CreateForgeInstanceParams{ + EndpointName: forgeInstanceEndpoint, + WebhookSecret: forgeInstanceWebhookSecret, + CredentialsName: forgeInstanceCreds, + ForgeType: params.EndpointType(forgeInstanceForgeType), + PoolBalancerType: params.PoolBalancerType(poolBalancerType), + AgentMode: forgeInstanceAgentMode, + } + response, err := apiCli.ForgeInstances.CreateForgeInstance(newReq, authToken) + if err != nil { + return err + } + + if installForgeInstanceWebhook { + installWebhookReq := apiClientForgeInstances.NewInstallForgeInstanceWebhookParams() + installWebhookReq.ForgeInstanceID = response.Payload.ID + installWebhookReq.Body.WebhookEndpointType = params.WebhookEndpointDirect + + _, err = apiCli.ForgeInstances.InstallForgeInstanceWebhook(installWebhookReq, authToken) + if err != nil { + return err + } + } + + // Re-fetch to include updated webhook status. + getReq := apiClientForgeInstances.NewGetForgeInstanceParams() + getReq.ForgeInstanceID = response.Payload.ID + fi, err := apiCli.ForgeInstances.GetForgeInstance(getReq, authToken) + if err != nil { + return err + } + formatOneForgeInstance(fi.Payload) + return nil + }, +} + +var forgeInstanceListCmd = &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + Short: "List forge instances", + Long: `List all configured forge instances that are currently managed.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, _ []string) error { + if needsInit { + return errNeedsInitError + } + + listReq := apiClientForgeInstances.NewListForgeInstancesParams() + if forgeInstanceEndpoint != "" { + listReq.Endpoint = &forgeInstanceEndpoint + } + response, err := apiCli.ForgeInstances.ListForgeInstances(listReq, authToken) + if err != nil { + return err + } + formatForgeInstances(response.Payload) + return nil + }, +} + +var forgeInstanceShowCmd = &cobra.Command{ + Use: "show", + Short: "Show details for one forge instance", + Long: `Displays detailed information about a single forge instance.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + if len(args) == 0 { + return fmt.Errorf("requires a forge instance ID or endpoint name") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + + showReq := apiClientForgeInstances.NewGetForgeInstanceParams() + showReq.ForgeInstanceID = forgeInstanceID + response, err := apiCli.ForgeInstances.GetForgeInstance(showReq, authToken) + if err != nil { + return err + } + formatOneForgeInstance(response.Payload) + return nil + }, +} + +var forgeInstanceDeleteCmd = &cobra.Command{ + Use: "delete", + Aliases: []string{"remove", "rm", "del"}, + Short: "Removes one forge instance", + Long: `Delete one forge instance from the manager.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + if len(args) == 0 { + return fmt.Errorf("requires a forge instance ID or endpoint name") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + + deleteReq := apiClientForgeInstances.NewDeleteForgeInstanceParams() + deleteReq.ForgeInstanceID = forgeInstanceID + deleteReq.KeepWebhook = &keepForgeInstanceWebhook + if err := apiCli.ForgeInstances.DeleteForgeInstance(deleteReq, authToken); err != nil { + return err + } + return nil + }, +} + +var forgeInstanceUpdateCmd = &cobra.Command{ + Use: "update", + Short: "Update forge instance", + Long: `Update forge instance credentials or webhook secret.`, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + + if len(args) == 0 { + return fmt.Errorf("command requires a forge instance ID or endpoint name") + } + + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + + updateReq := apiClientForgeInstances.NewUpdateForgeInstanceParams() + updateReq.Body = params.UpdateEntityParams{ + WebhookSecret: forgeInstanceWebhookSecret, + CredentialsName: forgeInstanceCreds, + PoolBalancerType: params.PoolBalancerType(poolBalancerType), + } + if cmd.Flags().Changed("agent-mode") { + updateReq.Body.AgentMode = &forgeInstanceAgentMode + } + updateReq.ForgeInstanceID = forgeInstanceID + response, err := apiCli.ForgeInstances.UpdateForgeInstance(updateReq, authToken) + if err != nil { + return err + } + formatOneForgeInstance(response.Payload) + return nil + }, +} + +var forgeInstanceWebhookCmd = &cobra.Command{ + Use: "webhook", + Short: "Manage forge instance webhooks", + Long: `Manage forge instance webhooks.`, + SilenceUsage: true, + Run: nil, +} + +var forgeInstanceWebhookInstallCmd = &cobra.Command{ + Use: "install", + Short: "Install webhook", + Long: `Install webhook for a forge instance.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + if len(args) == 0 { + return fmt.Errorf("requires a forge instance ID or endpoint name") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + + installWebhookReq := apiClientForgeInstances.NewInstallForgeInstanceWebhookParams() + installWebhookReq.ForgeInstanceID = forgeInstanceID + installWebhookReq.Body.InsecureSSL = insecureForgeInstanceWebhook + installWebhookReq.Body.WebhookEndpointType = params.WebhookEndpointDirect + + response, err := apiCli.ForgeInstances.InstallForgeInstanceWebhook(installWebhookReq, authToken) + if err != nil { + return err + } + formatOneHookInfo(response.Payload) + return nil + }, +} + +var forgeInstanceWebhookShowCmd = &cobra.Command{ + Use: "show", + Short: "Show webhook info", + Long: `Show webhook info for a forge instance.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + if len(args) == 0 { + return fmt.Errorf("requires a forge instance ID or endpoint name") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + showWebhookInfoReq := apiClientForgeInstances.NewGetForgeInstanceWebhookInfoParams() + showWebhookInfoReq.ForgeInstanceID = forgeInstanceID + + response, err := apiCli.ForgeInstances.GetForgeInstanceWebhookInfo(showWebhookInfoReq, authToken) + if err != nil { + return err + } + formatOneHookInfo(response.Payload) + return nil + }, +} + +var forgeInstanceWebhookUninstallCmd = &cobra.Command{ + Use: "uninstall", + Short: "Uninstall webhook", + Long: `Uninstall webhook for a forge instance.`, + SilenceUsage: true, + RunE: func(_ *cobra.Command, args []string) error { + if needsInit { + return errNeedsInitError + } + if len(args) == 0 { + return fmt.Errorf("requires a forge instance ID or endpoint name") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + + forgeInstanceID, err := resolveForgeInstance(args[0]) + if err != nil { + return err + } + + uninstallWebhookReq := apiClientForgeInstances.NewUninstallForgeInstanceWebhookParams() + uninstallWebhookReq.ForgeInstanceID = forgeInstanceID + + err = apiCli.ForgeInstances.UninstallForgeInstanceWebhook(uninstallWebhookReq, authToken) + if err != nil { + return err + } + return nil + }, +} + +func init() { + forgeInstanceAddCmd.Flags().StringVar(&forgeInstanceEndpoint, "endpoint", "", "The endpoint name for this forge instance") + forgeInstanceAddCmd.Flags().StringVar(&forgeInstanceWebhookSecret, "webhook-secret", "", "The webhook secret for this forge instance.") + forgeInstanceAddCmd.Flags().BoolVar(&forgeInstanceRandomSecret, "random-webhook-secret", false, "Generate a random webhook secret for this forge instance.") + forgeInstanceAddCmd.Flags().StringVar(&forgeInstanceCreds, "credentials", "", "Credentials name. See credentials list.") + forgeInstanceAddCmd.Flags().StringVar(&forgeInstanceForgeType, "forge-type", string(params.GiteaEndpointType), "The forge type (e.g. gitea).") + forgeInstanceAddCmd.Flags().StringVar(&poolBalancerType, "pool-balancer-type", string(params.PoolBalancerTypeRoundRobin), "The balancing strategy to use when creating runners in pools matching requested labels.") + forgeInstanceAddCmd.Flags().BoolVar(&forgeInstanceAgentMode, "agent-mode", false, "Enable agent mode for runners in this forge instance.") + forgeInstanceAddCmd.Flags().BoolVar(&installForgeInstanceWebhook, "install-webhook", false, "Install the webhook as part of the add operation.") + + forgeInstanceAddCmd.MarkFlagRequired("credentials") //nolint + forgeInstanceAddCmd.MarkFlagRequired("endpoint") //nolint + forgeInstanceAddCmd.MarkFlagsMutuallyExclusive("webhook-secret", "random-webhook-secret") //nolint + forgeInstanceAddCmd.MarkFlagsOneRequired("webhook-secret", "random-webhook-secret") //nolint + + forgeInstanceListCmd.Flags().BoolVarP(&long, "long", "l", false, "Include additional info.") + forgeInstanceListCmd.Flags().StringVarP(&forgeInstanceEndpoint, "endpoint", "e", "", "Exact endpoint name to filter by.") + + forgeInstanceDeleteCmd.Flags().BoolVar(&keepForgeInstanceWebhook, "keep-webhook", false, "Do not delete any existing webhook when removing the forge instance from GARM.") + + forgeInstanceUpdateCmd.Flags().StringVar(&forgeInstanceWebhookSecret, "webhook-secret", "", "The webhook secret for this forge instance") + forgeInstanceUpdateCmd.Flags().StringVar(&forgeInstanceCreds, "credentials", "", "Credentials name. See credentials list.") + forgeInstanceUpdateCmd.Flags().StringVar(&poolBalancerType, "pool-balancer-type", "", "The balancing strategy to use when creating runners in pools matching requested labels.") + forgeInstanceUpdateCmd.Flags().BoolVar(&forgeInstanceAgentMode, "agent-mode", false, "Enable agent mode for runners in this forge instance.") + + forgeInstanceWebhookInstallCmd.Flags().BoolVar(&insecureForgeInstanceWebhook, "insecure", false, "Ignore self signed certificate errors.") + + forgeInstanceWebhookCmd.AddCommand( + forgeInstanceWebhookInstallCmd, + forgeInstanceWebhookUninstallCmd, + forgeInstanceWebhookShowCmd, + ) + + forgeInstanceCmd.AddCommand( + forgeInstanceListCmd, + forgeInstanceAddCmd, + forgeInstanceShowCmd, + forgeInstanceDeleteCmd, + forgeInstanceUpdateCmd, + forgeInstanceWebhookCmd, + ) + + rootCmd.AddCommand(forgeInstanceCmd) +} + +func resolveForgeInstance(nameOrID string) (string, error) { + if nameOrID == "" { + return "", fmt.Errorf("missing forge instance endpoint name or ID") + } + _, err := uuid.Parse(nameOrID) + if err == nil { + // It's a valid UUID, use it directly. + return nameOrID, nil + } + + // Not a UUID — treat as endpoint name and look it up. + listReq := apiClientForgeInstances.NewListForgeInstancesParams() + listReq.Endpoint = &nameOrID + response, err := apiCli.ForgeInstances.ListForgeInstances(listReq, authToken) + if err != nil { + return "", err + } + + if len(response.Payload) == 0 { + return "", fmt.Errorf("forge instance with endpoint %s was not found", nameOrID) + } + + if len(response.Payload) > 1 { + return "", fmt.Errorf("multiple forge instances with endpoint %s exist, please use the forge instance ID", nameOrID) + } + + return response.Payload[0].ID, nil +} + +func formatForgeInstances(forgeInstances []params.ForgeInstance) { + if outputFormat == common.OutputFormatJSON { + printAsJSON(forgeInstances) + return + } + t := table.NewWriter() + header := table.Row{"Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"} + if long { + header = append(header, "ID", "Created At", "Updated At") + } + t.AppendHeader(header) + for _, val := range forgeInstances { + row := table.Row{val.Endpoint.Name, val.Credentials.Name, val.GetBalancerType(), val.PoolManagerStatus.IsRunning} + if long { + row = append(row, val.ID, val.CreatedAt, val.UpdatedAt) + } + t.AppendRow(row) + t.AppendSeparator() + } + fmt.Println(t.Render()) +} + +func formatOneForgeInstance(fi params.ForgeInstance) { + if outputFormat == common.OutputFormatJSON { + printAsJSON(fi) + return + } + t := table.NewWriter() + rowConfigAutoMerge := table.RowConfig{AutoMerge: true} + header := table.Row{"Field", "Value"} + t.AppendHeader(header) + t.AppendRow(table.Row{"ID", fi.ID}) + t.AppendRow(table.Row{"Created At", fi.CreatedAt}) + t.AppendRow(table.Row{"Updated At", fi.UpdatedAt}) + t.AppendRow(table.Row{"Endpoint", fi.Endpoint.Name}) + t.AppendRow(table.Row{"Pool balancer type", fi.GetBalancerType()}) + t.AppendRow(table.Row{"Credentials", fi.Credentials.Name}) + t.AppendRow(table.Row{"Agent Mode", fi.AgentMode}) + t.AppendRow(table.Row{"Pool manager running", fi.PoolManagerStatus.IsRunning}) + if !fi.PoolManagerStatus.IsRunning { + t.AppendRow(table.Row{"Failure reason", fi.PoolManagerStatus.FailureReason}) + } + + if len(fi.Pools) > 0 { + for _, pool := range fi.Pools { + t.AppendRow(table.Row{"Pools", pool.ID}, rowConfigAutoMerge) + } + } + + if len(fi.Events) > 0 { + for _, event := range fi.Events { + t.AppendRow(table.Row{"Events", fmt.Sprintf("%s %s: %s", event.CreatedAt.Format("2006-01-02T15:04:05"), strings.ToUpper(string(event.EventLevel)), event.Message)}, rowConfigAutoMerge) + } + } + t.SetColumnConfigs([]table.ColumnConfig{ + {Number: 1, AutoMerge: true}, + {Number: 2, AutoMerge: false, WidthMax: 100}, + }) + + fmt.Println(t.Render()) +} diff --git a/cmd/garm-cli/cmd/pool.go b/cmd/garm-cli/cmd/pool.go index abcf3e551..502b1e94c 100644 --- a/cmd/garm-cli/cmd/pool.go +++ b/cmd/garm-cli/cmd/pool.go @@ -26,6 +26,7 @@ import ( commonParams "github.com/cloudbase/garm-provider-common/params" apiClientEnterprises "github.com/cloudbase/garm/client/enterprises" + apiClientForgeInstances "github.com/cloudbase/garm/client/forge_instances" apiClientInstances "github.com/cloudbase/garm/client/instances" apiClientOrgs "github.com/cloudbase/garm/client/organizations" apiClientPools "github.com/cloudbase/garm/client/pools" @@ -49,6 +50,7 @@ var ( poolRepository string poolOrganization string poolEnterprise string + poolForgeInstance string poolExtraSpecsFile string poolExtraSpecs string poolAll bool @@ -131,6 +133,14 @@ Example: listEnterprisePoolsReq := apiClientEnterprises.NewListEnterprisePoolsParams() listEnterprisePoolsReq.EnterpriseID = poolEnterprise response, err = apiCli.Enterprises.ListEnterprisePools(listEnterprisePoolsReq, authToken) + } else if cmd.Flags().Changed("forge-instance") { + poolForgeInstance, err = resolveForgeInstance(poolForgeInstance) + if err != nil { + return err + } + listFIPoolsReq := apiClientForgeInstances.NewListForgeInstancePoolsParams() + listFIPoolsReq.ForgeInstanceID = poolForgeInstance + response, err = apiCli.ForgeInstances.ListForgeInstancePools(listFIPoolsReq, authToken) } else { listPoolsReq := apiClientPools.NewListPoolsParams() response, err = apiCli.Pools.ListPools(listPoolsReq, authToken) @@ -297,6 +307,15 @@ var poolAddCmd = &cobra.Command{ newEnterprisePoolReq.EnterpriseID = poolEnterprise newEnterprisePoolReq.Body = newPoolParams response, err = apiCli.Enterprises.CreateEnterprisePool(newEnterprisePoolReq, authToken) + } else if cmd.Flags().Changed("forge-instance") { + poolForgeInstance, err = resolveForgeInstance(poolForgeInstance) + if err != nil { + return err + } + newFIPoolReq := apiClientForgeInstances.NewCreateForgeInstancePoolParams() + newFIPoolReq.ForgeInstanceID = poolForgeInstance + newFIPoolReq.Body = newPoolParams + response, err = apiCli.ForgeInstances.CreateForgeInstancePool(newFIPoolReq, authToken) } else { cmd.Help() //nolint os.Exit(0) @@ -552,12 +571,13 @@ func init() { poolListCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "List all pools within this repository.") poolListCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "List all pools within this organization.") poolListCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "List all pools within this enterprise.") + poolListCmd.Flags().StringVarP(&poolForgeInstance, "forge-instance", "f", "", "List all pools within this forge instance.") poolListCmd.Flags().BoolVarP(&poolAll, "all", "a", true, "List all pools, regardless of org or repo.") poolListCmd.Flags().BoolVarP(&long, "long", "l", false, "Include additional info.") poolListCmd.Flags().StringVar(&endpointName, "endpoint", "", "When using the name of an entity, the endpoint must be specified when multiple entities with the same name exist.") - poolListCmd.Flags().MarkDeprecated("all", "all pools are listed by default in the absence of --repo, --org or --enterprise.") - poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "all") + poolListCmd.Flags().MarkDeprecated("all", "all pools are listed by default in the absence of --repo, --org, --enterprise or --forge-instance.") + poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "forge-instance", "all") poolUpdateCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.") poolUpdateCmd.Flags().UintVar(&priority, "priority", 0, "When multiple pools match the same labels, priority dictates the order by which they are returned, in descending order.") @@ -604,7 +624,8 @@ func init() { poolAddCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "Add the new pool within this repository.") poolAddCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "Add the new pool within this organization.") poolAddCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "Add the new pool within this enterprise.") - poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise") + poolAddCmd.Flags().StringVarP(&poolForgeInstance, "forge-instance", "f", "", "Add the new pool within this forge instance.") + poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "forge-instance") poolAddCmd.MarkFlagsMutuallyExclusive("extra-specs-file", "extra-specs") poolRunnerListCmd.Flags().BoolVar(&poolRunnerOutdated, "outdated", false, "List only runners with a generation older than the pool.") @@ -690,6 +711,9 @@ func formatPools(pools []params.Pool) { case pool.EnterpriseID != "" && pool.EnterpriseName != "": belongsTo = pool.EnterpriseName level = entityTypeEnterprise + case pool.ForgeInstanceID != "": + belongsTo = pool.Endpoint.Name + level = "forge-instance" } row := table.Row{pool.ID, pool.Image, pool.Flavor, strings.Join(tags, " "), belongsTo, pool.Endpoint.Name, pool.Endpoint.EndpointType, pool.Enabled} if long { @@ -729,6 +753,9 @@ func formatOnePool(pool params.Pool) { case pool.EnterpriseID != "" && pool.EnterpriseName != "": belongsTo = pool.EnterpriseName level = entityTypeEnterprise + case pool.ForgeInstanceID != "": + belongsTo = pool.Endpoint.Name + level = "forge-instance" } t.AppendHeader(header) diff --git a/database/common/mocks/Store.go b/database/common/mocks/Store.go index 1456b39b9..0aa55eccd 100644 --- a/database/common/mocks/Store.go +++ b/database/common/mocks/Store.go @@ -466,6 +466,67 @@ func (_c *Store_CreateFileObject_Call) RunAndReturn(run func(context.Context, pa return _c } +// CreateForgeInstance provides a mock function with given fields: ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode +func (_m *Store) CreateForgeInstance(ctx context.Context, endpointName string, credentials params.ForgeCredentials, webhookSecret string, poolBalancerType params.PoolBalancerType, agentMode bool) (params.ForgeInstance, error) { + ret := _m.Called(ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode) + + if len(ret) == 0 { + panic("no return value specified for CreateForgeInstance") + } + + var r0 params.ForgeInstance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, params.ForgeCredentials, string, params.PoolBalancerType, bool) (params.ForgeInstance, error)); ok { + return rf(ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode) + } + if rf, ok := ret.Get(0).(func(context.Context, string, params.ForgeCredentials, string, params.PoolBalancerType, bool) params.ForgeInstance); ok { + r0 = rf(ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode) + } else { + r0 = ret.Get(0).(params.ForgeInstance) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, params.ForgeCredentials, string, params.PoolBalancerType, bool) error); ok { + r1 = rf(ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Store_CreateForgeInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateForgeInstance' +type Store_CreateForgeInstance_Call struct { + *mock.Call +} + +// CreateForgeInstance is a helper method to define mock.On call +// - ctx context.Context +// - endpointName string +// - credentials params.ForgeCredentials +// - webhookSecret string +// - poolBalancerType params.PoolBalancerType +// - agentMode bool +func (_e *Store_Expecter) CreateForgeInstance(ctx interface{}, endpointName interface{}, credentials interface{}, webhookSecret interface{}, poolBalancerType interface{}, agentMode interface{}) *Store_CreateForgeInstance_Call { + return &Store_CreateForgeInstance_Call{Call: _e.mock.On("CreateForgeInstance", ctx, endpointName, credentials, webhookSecret, poolBalancerType, agentMode)} +} + +func (_c *Store_CreateForgeInstance_Call) Run(run func(ctx context.Context, endpointName string, credentials params.ForgeCredentials, webhookSecret string, poolBalancerType params.PoolBalancerType, agentMode bool)) *Store_CreateForgeInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(params.ForgeCredentials), args[3].(string), args[4].(params.PoolBalancerType), args[5].(bool)) + }) + return _c +} + +func (_c *Store_CreateForgeInstance_Call) Return(_a0 params.ForgeInstance, _a1 error) *Store_CreateForgeInstance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Store_CreateForgeInstance_Call) RunAndReturn(run func(context.Context, string, params.ForgeCredentials, string, params.PoolBalancerType, bool) (params.ForgeInstance, error)) *Store_CreateForgeInstance_Call { + _c.Call.Return(run) + return _c +} + // CreateGiteaCredentials provides a mock function with given fields: ctx, param func (_m *Store) CreateGiteaCredentials(ctx context.Context, param params.CreateGiteaCredentialsParams) (params.ForgeCredentials, error) { ret := _m.Called(ctx, param) @@ -1303,6 +1364,53 @@ func (_c *Store_DeleteFileObjectsByTags_Call) RunAndReturn(run func(context.Cont return _c } +// DeleteForgeInstance provides a mock function with given fields: ctx, forgeInstanceID +func (_m *Store) DeleteForgeInstance(ctx context.Context, forgeInstanceID string) error { + ret := _m.Called(ctx, forgeInstanceID) + + if len(ret) == 0 { + panic("no return value specified for DeleteForgeInstance") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, forgeInstanceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Store_DeleteForgeInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteForgeInstance' +type Store_DeleteForgeInstance_Call struct { + *mock.Call +} + +// DeleteForgeInstance is a helper method to define mock.On call +// - ctx context.Context +// - forgeInstanceID string +func (_e *Store_Expecter) DeleteForgeInstance(ctx interface{}, forgeInstanceID interface{}) *Store_DeleteForgeInstance_Call { + return &Store_DeleteForgeInstance_Call{Call: _e.mock.On("DeleteForgeInstance", ctx, forgeInstanceID)} +} + +func (_c *Store_DeleteForgeInstance_Call) Run(run func(ctx context.Context, forgeInstanceID string)) *Store_DeleteForgeInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *Store_DeleteForgeInstance_Call) Return(_a0 error) *Store_DeleteForgeInstance_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Store_DeleteForgeInstance_Call) RunAndReturn(run func(context.Context, string) error) *Store_DeleteForgeInstance_Call { + _c.Call.Return(run) + return _c +} + // DeleteGiteaCredentials provides a mock function with given fields: ctx, id func (_m *Store) DeleteGiteaCredentials(ctx context.Context, id uint) error { ret := _m.Called(ctx, id) @@ -2378,6 +2486,120 @@ func (_c *Store_GetForgeEntity_Call) RunAndReturn(run func(context.Context, para return _c } +// GetForgeInstance provides a mock function with given fields: ctx, endpointName +func (_m *Store) GetForgeInstance(ctx context.Context, endpointName string) (params.ForgeInstance, error) { + ret := _m.Called(ctx, endpointName) + + if len(ret) == 0 { + panic("no return value specified for GetForgeInstance") + } + + var r0 params.ForgeInstance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (params.ForgeInstance, error)); ok { + return rf(ctx, endpointName) + } + if rf, ok := ret.Get(0).(func(context.Context, string) params.ForgeInstance); ok { + r0 = rf(ctx, endpointName) + } else { + r0 = ret.Get(0).(params.ForgeInstance) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, endpointName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Store_GetForgeInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForgeInstance' +type Store_GetForgeInstance_Call struct { + *mock.Call +} + +// GetForgeInstance is a helper method to define mock.On call +// - ctx context.Context +// - endpointName string +func (_e *Store_Expecter) GetForgeInstance(ctx interface{}, endpointName interface{}) *Store_GetForgeInstance_Call { + return &Store_GetForgeInstance_Call{Call: _e.mock.On("GetForgeInstance", ctx, endpointName)} +} + +func (_c *Store_GetForgeInstance_Call) Run(run func(ctx context.Context, endpointName string)) *Store_GetForgeInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *Store_GetForgeInstance_Call) Return(_a0 params.ForgeInstance, _a1 error) *Store_GetForgeInstance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Store_GetForgeInstance_Call) RunAndReturn(run func(context.Context, string) (params.ForgeInstance, error)) *Store_GetForgeInstance_Call { + _c.Call.Return(run) + return _c +} + +// GetForgeInstanceByID provides a mock function with given fields: ctx, forgeInstanceID +func (_m *Store) GetForgeInstanceByID(ctx context.Context, forgeInstanceID string) (params.ForgeInstance, error) { + ret := _m.Called(ctx, forgeInstanceID) + + if len(ret) == 0 { + panic("no return value specified for GetForgeInstanceByID") + } + + var r0 params.ForgeInstance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (params.ForgeInstance, error)); ok { + return rf(ctx, forgeInstanceID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) params.ForgeInstance); ok { + r0 = rf(ctx, forgeInstanceID) + } else { + r0 = ret.Get(0).(params.ForgeInstance) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, forgeInstanceID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Store_GetForgeInstanceByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForgeInstanceByID' +type Store_GetForgeInstanceByID_Call struct { + *mock.Call +} + +// GetForgeInstanceByID is a helper method to define mock.On call +// - ctx context.Context +// - forgeInstanceID string +func (_e *Store_Expecter) GetForgeInstanceByID(ctx interface{}, forgeInstanceID interface{}) *Store_GetForgeInstanceByID_Call { + return &Store_GetForgeInstanceByID_Call{Call: _e.mock.On("GetForgeInstanceByID", ctx, forgeInstanceID)} +} + +func (_c *Store_GetForgeInstanceByID_Call) Run(run func(ctx context.Context, forgeInstanceID string)) *Store_GetForgeInstanceByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *Store_GetForgeInstanceByID_Call) Return(_a0 params.ForgeInstance, _a1 error) *Store_GetForgeInstanceByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Store_GetForgeInstanceByID_Call) RunAndReturn(run func(context.Context, string) (params.ForgeInstance, error)) *Store_GetForgeInstanceByID_Call { + _c.Call.Return(run) + return _c +} + // GetGiteaCredentials provides a mock function with given fields: ctx, id, detailed func (_m *Store) GetGiteaCredentials(ctx context.Context, id uint, detailed bool) (params.ForgeCredentials, error) { ret := _m.Called(ctx, id, detailed) @@ -4154,6 +4376,65 @@ func (_c *Store_ListFileObjects_Call) RunAndReturn(run func(context.Context, uin return _c } +// ListForgeInstances provides a mock function with given fields: ctx, filter +func (_m *Store) ListForgeInstances(ctx context.Context, filter params.ForgeInstanceFilter) ([]params.ForgeInstance, error) { + ret := _m.Called(ctx, filter) + + if len(ret) == 0 { + panic("no return value specified for ListForgeInstances") + } + + var r0 []params.ForgeInstance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, params.ForgeInstanceFilter) ([]params.ForgeInstance, error)); ok { + return rf(ctx, filter) + } + if rf, ok := ret.Get(0).(func(context.Context, params.ForgeInstanceFilter) []params.ForgeInstance); ok { + r0 = rf(ctx, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]params.ForgeInstance) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, params.ForgeInstanceFilter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Store_ListForgeInstances_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListForgeInstances' +type Store_ListForgeInstances_Call struct { + *mock.Call +} + +// ListForgeInstances is a helper method to define mock.On call +// - ctx context.Context +// - filter params.ForgeInstanceFilter +func (_e *Store_Expecter) ListForgeInstances(ctx interface{}, filter interface{}) *Store_ListForgeInstances_Call { + return &Store_ListForgeInstances_Call{Call: _e.mock.On("ListForgeInstances", ctx, filter)} +} + +func (_c *Store_ListForgeInstances_Call) Run(run func(ctx context.Context, filter params.ForgeInstanceFilter)) *Store_ListForgeInstances_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(params.ForgeInstanceFilter)) + }) + return _c +} + +func (_c *Store_ListForgeInstances_Call) Return(_a0 []params.ForgeInstance, _a1 error) *Store_ListForgeInstances_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Store_ListForgeInstances_Call) RunAndReturn(run func(context.Context, params.ForgeInstanceFilter) ([]params.ForgeInstance, error)) *Store_ListForgeInstances_Call { + _c.Call.Return(run) + return _c +} + // ListGiteaCredentials provides a mock function with given fields: ctx func (_m *Store) ListGiteaCredentials(ctx context.Context) ([]params.ForgeCredentials, error) { ret := _m.Called(ctx) @@ -5497,6 +5778,64 @@ func (_c *Store_UpdateFileObject_Call) RunAndReturn(run func(context.Context, ui return _c } +// UpdateForgeInstance provides a mock function with given fields: ctx, forgeInstanceID, param +func (_m *Store) UpdateForgeInstance(ctx context.Context, forgeInstanceID string, param params.UpdateEntityParams) (params.ForgeInstance, error) { + ret := _m.Called(ctx, forgeInstanceID, param) + + if len(ret) == 0 { + panic("no return value specified for UpdateForgeInstance") + } + + var r0 params.ForgeInstance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, params.UpdateEntityParams) (params.ForgeInstance, error)); ok { + return rf(ctx, forgeInstanceID, param) + } + if rf, ok := ret.Get(0).(func(context.Context, string, params.UpdateEntityParams) params.ForgeInstance); ok { + r0 = rf(ctx, forgeInstanceID, param) + } else { + r0 = ret.Get(0).(params.ForgeInstance) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, params.UpdateEntityParams) error); ok { + r1 = rf(ctx, forgeInstanceID, param) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Store_UpdateForgeInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateForgeInstance' +type Store_UpdateForgeInstance_Call struct { + *mock.Call +} + +// UpdateForgeInstance is a helper method to define mock.On call +// - ctx context.Context +// - forgeInstanceID string +// - param params.UpdateEntityParams +func (_e *Store_Expecter) UpdateForgeInstance(ctx interface{}, forgeInstanceID interface{}, param interface{}) *Store_UpdateForgeInstance_Call { + return &Store_UpdateForgeInstance_Call{Call: _e.mock.On("UpdateForgeInstance", ctx, forgeInstanceID, param)} +} + +func (_c *Store_UpdateForgeInstance_Call) Run(run func(ctx context.Context, forgeInstanceID string, param params.UpdateEntityParams)) *Store_UpdateForgeInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(params.UpdateEntityParams)) + }) + return _c +} + +func (_c *Store_UpdateForgeInstance_Call) Return(_a0 params.ForgeInstance, _a1 error) *Store_UpdateForgeInstance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Store_UpdateForgeInstance_Call) RunAndReturn(run func(context.Context, string, params.UpdateEntityParams) (params.ForgeInstance, error)) *Store_UpdateForgeInstance_Call { + _c.Call.Return(run) + return _c +} + // UpdateGiteaCredentials provides a mock function with given fields: ctx, id, param func (_m *Store) UpdateGiteaCredentials(ctx context.Context, id uint, param params.UpdateGiteaCredentialsParams) (params.ForgeCredentials, error) { ret := _m.Called(ctx, id, param) diff --git a/database/common/store.go b/database/common/store.go index 3314b0afe..6a06d7681 100644 --- a/database/common/store.go +++ b/database/common/store.go @@ -67,6 +67,15 @@ type EnterpriseStore interface { UpdateEnterprise(ctx context.Context, enterpriseID string, param params.UpdateEntityParams) (params.Enterprise, error) } +type ForgeInstanceStore interface { + CreateForgeInstance(ctx context.Context, endpointName string, credentials params.ForgeCredentials, webhookSecret string, poolBalancerType params.PoolBalancerType, agentMode bool) (params.ForgeInstance, error) + GetForgeInstance(ctx context.Context, endpointName string) (params.ForgeInstance, error) + GetForgeInstanceByID(ctx context.Context, forgeInstanceID string) (params.ForgeInstance, error) + ListForgeInstances(ctx context.Context, filter params.ForgeInstanceFilter) ([]params.ForgeInstance, error) + DeleteForgeInstance(ctx context.Context, forgeInstanceID string) error + UpdateForgeInstance(ctx context.Context, forgeInstanceID string, param params.UpdateEntityParams) (params.ForgeInstance, error) +} + type PoolStore interface { // Probably a bad idea without some king of filter or at least pagination // nolint:golangci-lint,godox @@ -207,6 +216,7 @@ type Store interface { RepoStore OrgStore EnterpriseStore + ForgeInstanceStore PoolStore UserStore InstanceStore diff --git a/database/common/watcher.go b/database/common/watcher.go index 59aff0534..d5fe15ef5 100644 --- a/database/common/watcher.go +++ b/database/common/watcher.go @@ -37,6 +37,7 @@ const ( ScaleSetEntityType DatabaseEntityType = "scaleset" TemplateEntityType DatabaseEntityType = "template" FileObjectEntityType DatabaseEntityType = "file_object" + ForgeInstanceEntityType DatabaseEntityType = "forge_instance" ) const ( diff --git a/database/sql/forge_instances.go b/database/sql/forge_instances.go new file mode 100644 index 000000000..01ced626b --- /dev/null +++ b/database/sql/forge_instances.go @@ -0,0 +1,287 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 sql + +import ( + "context" + "errors" + "fmt" + "log/slog" + + "github.com/google/uuid" + "gorm.io/gorm" + "gorm.io/gorm/clause" + + runnerErrors "github.com/cloudbase/garm-provider-common/errors" + "github.com/cloudbase/garm-provider-common/util" + "github.com/cloudbase/garm/database/common" + "github.com/cloudbase/garm/params" +) + +func (s *sqlDatabase) CreateForgeInstance(ctx context.Context, endpointName string, credentials params.ForgeCredentials, webhookSecret string, poolBalancerType params.PoolBalancerType, agentMode bool) (paramFI params.ForgeInstance, err error) { + if webhookSecret == "" { + return params.ForgeInstance{}, errors.New("creating forge instance: missing secret") + } + if credentials.ForgeType != params.GiteaEndpointType { + return params.ForgeInstance{}, fmt.Errorf("forge instances are only supported for gitea endpoints: %w", runnerErrors.ErrBadRequest) + } + if credentials.Endpoint.Name != endpointName { + return params.ForgeInstance{}, fmt.Errorf("credentials endpoint %q does not match requested endpoint %q: %w", credentials.Endpoint.Name, endpointName, runnerErrors.ErrBadRequest) + } + + secret, err := util.Seal([]byte(webhookSecret), []byte(s.cfg.Passphrase)) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error encoding secret: %w", err) + } + + defer func() { + if err == nil { + s.sendNotify(common.ForgeInstanceEntityType, common.CreateOperation, paramFI) + } + }() + newForgeInstance := ForgeInstance{ + WebhookSecret: secret, + PoolBalancerType: poolBalancerType, + AgentMode: agentMode, + } + err = s.conn.Transaction(func(tx *gorm.DB) error { + newForgeInstance.GiteaCredentialsID = &credentials.ID + newForgeInstance.EndpointName = &endpointName + + q := tx.Create(&newForgeInstance) + if q.Error != nil { + return fmt.Errorf("error creating forge instance: %w", q.Error) + } + return nil + }) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error creating forge instance: %w", err) + } + + ret, err := s.GetForgeInstanceByID(ctx, newForgeInstance.ID.String()) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error creating forge instance: %w", err) + } + + return ret, nil +} + +func (s *sqlDatabase) GetForgeInstance(ctx context.Context, endpointName string) (params.ForgeInstance, error) { + fi, err := s.getForgeInstanceByName(ctx, s.conn, endpointName, "GiteaCredentials", "GiteaCredentials.Endpoint", "Endpoint") + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + + param, err := s.sqlToCommonForgeInstance(fi, true) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + return param, nil +} + +func (s *sqlDatabase) GetForgeInstanceByID(ctx context.Context, forgeInstanceID string) (params.ForgeInstance, error) { + preloadList := []string{ + "Pools", + "GiteaCredentials", + "GiteaCredentials.Endpoint", + "Endpoint", + "Events", + } + fi, err := s.getForgeInstanceByID(ctx, s.conn, forgeInstanceID, preloadList...) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + + param, err := s.sqlToCommonForgeInstance(fi, true) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + return param, nil +} + +func (s *sqlDatabase) ListForgeInstances(_ context.Context, filter params.ForgeInstanceFilter) ([]params.ForgeInstance, error) { + var forgeInstances []ForgeInstance + q := s.conn. + Preload("GiteaCredentials"). + Preload("GiteaCredentials.Endpoint"). + Preload("Endpoint") + if filter.Endpoint != "" { + q = q.Where("endpoint_name = ?", filter.Endpoint) + } + q = q.Find(&forgeInstances) + if q.Error != nil { + return []params.ForgeInstance{}, fmt.Errorf("error fetching forge instances: %w", q.Error) + } + + ret := make([]params.ForgeInstance, len(forgeInstances)) + for idx, val := range forgeInstances { + var err error + ret[idx], err = s.sqlToCommonForgeInstance(val, true) + if err != nil { + return nil, fmt.Errorf("error fetching forge instances: %w", err) + } + } + + return ret, nil +} + +func (s *sqlDatabase) DeleteForgeInstance(ctx context.Context, forgeInstanceID string) error { + fi, err := s.getForgeInstanceByID(ctx, s.conn, forgeInstanceID, "Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") + if err != nil { + return fmt.Errorf("error fetching forge instance: %w", err) + } + + defer func(inst ForgeInstance) { + if err == nil { + asParams, innerErr := s.sqlToCommonForgeInstance(inst, true) + if innerErr == nil { + s.sendNotify(common.ForgeInstanceEntityType, common.DeleteOperation, asParams) + } else { + slog.With(slog.Any("error", innerErr)).ErrorContext(ctx, "error sending delete notification", "forge_instance", forgeInstanceID) + } + } + }(fi) + + q := s.conn.Unscoped().Delete(&fi) + if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) { + return fmt.Errorf("error deleting forge instance: %w", q.Error) + } + + return nil +} + +func (s *sqlDatabase) UpdateForgeInstance(ctx context.Context, forgeInstanceID string, param params.UpdateEntityParams) (newParams params.ForgeInstance, err error) { + var rowsAffected int64 + defer func() { + if err == nil && rowsAffected > 0 { + s.sendNotify(common.ForgeInstanceEntityType, common.UpdateOperation, newParams) + } + }() + var fi ForgeInstance + err = s.conn.Transaction(func(tx *gorm.DB) error { + var err error + fi, err = s.getForgeInstanceByID(ctx, tx.Clauses(clause.Locking{Strength: "UPDATE"}), forgeInstanceID, "Endpoint") + if err != nil { + return fmt.Errorf("error fetching forge instance: %w", err) + } + + if fi.EndpointName == nil { + return fmt.Errorf("forge instance has no endpoint: %w", runnerErrors.ErrUnprocessable) + } + + updates := make(map[string]any) + + if err := s.updateEntityCredentials(ctx, tx, &fi, param.CredentialsName, updates); err != nil { + return err + } + + if param.WebhookSecret != "" { + existingSecret, err := util.Unseal(fi.WebhookSecret, []byte(s.cfg.Passphrase)) + if err != nil { + return fmt.Errorf("failed to decrypt existing webhook secret: %w", err) + } + if string(existingSecret) != param.WebhookSecret { + secret, err := util.Seal([]byte(param.WebhookSecret), []byte(s.cfg.Passphrase)) + if err != nil { + return fmt.Errorf("error encoding secret: %w", err) + } + updates["webhook_secret"] = secret + } + } + + if param.PoolManagerStatus != nil { + if param.PoolManagerStatus.IsRunning != fi.PoolManagerRunning { + updates["pool_manager_running"] = param.PoolManagerStatus.IsRunning + } + if param.PoolManagerStatus.FailureReason != fi.PoolManagerFailureReason { + updates["pool_manager_failure_reason"] = param.PoolManagerStatus.FailureReason + } + } + + if param.PoolBalancerType != "" && param.PoolBalancerType != fi.PoolBalancerType { + updates["pool_balancer_type"] = param.PoolBalancerType + } + + if param.AgentMode != nil && *param.AgentMode != fi.AgentMode { + updates["agent_mode"] = *param.AgentMode + } + + if len(updates) > 0 { + q := tx.Model(&fi).Omit("Endpoint").Updates(updates) + if q.Error != nil { + return fmt.Errorf("error saving forge instance: %w", q.Error) + } + rowsAffected = q.RowsAffected + } + + return nil + }) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error updating forge instance: %w", err) + } + + fi, err = s.getForgeInstanceByID(ctx, s.conn, forgeInstanceID, "Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error updating forge instance: %w", err) + } + newParams, err = s.sqlToCommonForgeInstance(fi, true) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error updating forge instance: %w", err) + } + return newParams, nil +} + +func (s *sqlDatabase) getForgeInstanceByName(_ context.Context, tx *gorm.DB, name string, preload ...string) (ForgeInstance, error) { + if name == "" { + return ForgeInstance{}, fmt.Errorf("missing forge instance name: %w", runnerErrors.ErrBadRequest) + } + var fi ForgeInstance + + q := tx + for _, field := range preload { + q = q.Preload(field) + } + q = q.Where("LOWER(endpoint_name) = LOWER(?)", name).First(&fi) + + if q.Error != nil { + if errors.Is(q.Error, gorm.ErrRecordNotFound) { + return ForgeInstance{}, runnerErrors.ErrNotFound + } + return ForgeInstance{}, fmt.Errorf("error fetching forge instance from database: %w", q.Error) + } + return fi, nil +} + +func (s *sqlDatabase) getForgeInstanceByID(_ context.Context, tx *gorm.DB, id string, preload ...string) (ForgeInstance, error) { + u, err := uuid.Parse(id) + if err != nil { + return ForgeInstance{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest) + } + var fi ForgeInstance + + q := tx + for _, field := range preload { + q = q.Preload(field) + } + q = q.Where("id = ?", u).First(&fi) + + if q.Error != nil { + if errors.Is(q.Error, gorm.ErrRecordNotFound) { + return ForgeInstance{}, runnerErrors.ErrNotFound + } + return ForgeInstance{}, fmt.Errorf("error fetching forge instance from database: %w", q.Error) + } + return fi, nil +} diff --git a/database/sql/forge_instances_test.go b/database/sql/forge_instances_test.go new file mode 100644 index 000000000..249fa3b08 --- /dev/null +++ b/database/sql/forge_instances_test.go @@ -0,0 +1,488 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 sql + +import ( + "context" + "fmt" + "sort" + "testing" + + "github.com/stretchr/testify/suite" + + commonParams "github.com/cloudbase/garm-provider-common/params" + "github.com/cloudbase/garm/auth" + dbCommon "github.com/cloudbase/garm/database/common" + "github.com/cloudbase/garm/database/watcher" + garmTesting "github.com/cloudbase/garm/internal/testing" + "github.com/cloudbase/garm/params" +) + +type ForgeInstanceTestFixtures struct { + ForgeInstances []params.ForgeInstance + CreatePoolParams params.CreatePoolParams + CreateInstanceParams params.CreateInstanceParams + UpdateEntityParams params.UpdateEntityParams + UpdatePoolParams params.UpdatePoolParams +} + +type ForgeInstanceTestSuite struct { + suite.Suite + Store dbCommon.Store + Fixtures *ForgeInstanceTestFixtures + + adminCtx context.Context + adminUserID string + giteaEndpoint params.ForgeEndpoint + giteaCreds params.ForgeCredentials + giteaCreds2 params.ForgeCredentials +} + +func (s *ForgeInstanceTestSuite) equalInstancesByName(expected, actual []params.Instance) { + s.Require().Equal(len(expected), len(actual)) + sort.Slice(expected, func(i, j int) bool { return expected[i].Name > expected[j].Name }) + sort.Slice(actual, func(i, j int) bool { return actual[i].Name > actual[j].Name }) + for i := 0; i < len(expected); i++ { + s.Require().Equal(expected[i].Name, actual[i].Name) + } +} + +func (s *ForgeInstanceTestSuite) TearDownTest() { + watcher.CloseWatcher() +} + +func (s *ForgeInstanceTestSuite) SetupTest() { + ctx := context.Background() + watcher.InitWatcher(ctx) + + db := newTestDB(s.T()) + s.Store = db + + adminCtx := garmTesting.ImpersonateAdminContext(ctx, db, s.T()) + s.adminCtx = adminCtx + s.adminUserID = auth.UserID(adminCtx) + s.Require().NotEmpty(s.adminUserID) + + s.giteaEndpoint = garmTesting.CreateDefaultGiteaEndpoint(adminCtx, db, s.T()) + s.giteaCreds = garmTesting.CreateTestGiteaCredentials(adminCtx, "gitea-creds", db, s.T(), s.giteaEndpoint) + s.giteaCreds2 = garmTesting.CreateTestGiteaCredentials(adminCtx, "gitea-creds-2", db, s.T(), s.giteaEndpoint) + + // Create test forge instances + forgeInstances := []params.ForgeInstance{} + fi, err := db.CreateForgeInstance( + adminCtx, + s.giteaEndpoint.Name, + s.giteaCreds, + "test-webhook-secret-1", + params.PoolBalancerTypeRoundRobin, + false, + ) + if err != nil { + s.FailNow(fmt.Sprintf("failed to create forge instance: %q", err)) + } + forgeInstances = append(forgeInstances, fi) + + var maxRunners uint = 30 + var minIdleRunners uint = 10 + s.Fixtures = &ForgeInstanceTestFixtures{ + ForgeInstances: forgeInstances, + CreatePoolParams: params.CreatePoolParams{ + ProviderName: "test-provider", + MaxRunners: 3, + MinIdleRunners: 1, + Enabled: true, + Image: "test-image", + Flavor: "test-flavor", + OSType: "linux", + OSArch: "amd64", + Tags: []string{"amd64-linux-runner"}, + }, + CreateInstanceParams: params.CreateInstanceParams{ + Name: "test-instance-name", + OSType: "linux", + }, + UpdateEntityParams: params.UpdateEntityParams{ + CredentialsName: s.giteaCreds2.Name, + WebhookSecret: "updated-webhook-secret", + }, + UpdatePoolParams: params.UpdatePoolParams{ + MaxRunners: &maxRunners, + MinIdleRunners: &minIdleRunners, + Image: "test-update-image", + Flavor: "test-update-flavor", + }, + } +} + +func TestForgeInstanceTestSuite(t *testing.T) { + suite.Run(t, new(ForgeInstanceTestSuite)) +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstance() { + // Use a second endpoint to avoid unique constraint collision + ep2, err := s.Store.CreateGiteaEndpoint(s.adminCtx, params.CreateGiteaEndpointParams{ + Name: "second-gitea", + APIBaseURL: "https://gitea2.example.com/api/v1", + BaseURL: "https://gitea2.example.com", + }) + s.Require().Nil(err) + creds2 := garmTesting.CreateTestGiteaCredentials(s.adminCtx, "creds-for-ep2", s.Store, s.T(), ep2) + + fi, err := s.Store.CreateForgeInstance( + s.adminCtx, + ep2.Name, + creds2, + "new-webhook-secret", + params.PoolBalancerTypeRoundRobin, + true, + ) + s.Require().Nil(err) + s.Require().NotEmpty(fi.ID) + s.Require().Equal(ep2.Name, fi.Endpoint.Name) + s.Require().Equal(creds2.Name, fi.Credentials.Name) + s.Require().Equal("new-webhook-secret", fi.WebhookSecret) + s.Require().True(fi.AgentMode) +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceMissingSecret() { + _, err := s.Store.CreateForgeInstance( + s.adminCtx, + s.giteaEndpoint.Name, + s.giteaCreds, + "", + params.PoolBalancerTypeRoundRobin, + false, + ) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "missing secret") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceGithubNotSupported() { + ghEndpoint := garmTesting.CreateDefaultGithubEndpoint(s.adminCtx, s.Store, s.T()) + ghCreds := garmTesting.CreateTestGithubCredentials(s.adminCtx, "gh-creds", s.Store, s.T(), ghEndpoint) + + _, err := s.Store.CreateForgeInstance( + s.adminCtx, + ghEndpoint.Name, + ghCreds, + "test-secret", + params.PoolBalancerTypeRoundRobin, + false, + ) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "only supported for gitea") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceEndpointMismatch() { + ep2, err := s.Store.CreateGiteaEndpoint(s.adminCtx, params.CreateGiteaEndpointParams{ + Name: "mismatch-gitea", + APIBaseURL: "https://other-gitea.example.com/api/v1", + BaseURL: "https://other-gitea.example.com", + }) + s.Require().Nil(err) + + // Credentials are for s.giteaEndpoint, but we pass ep2.Name + _, err = s.Store.CreateForgeInstance( + s.adminCtx, + ep2.Name, + s.giteaCreds, + "test-secret", + params.PoolBalancerTypeRoundRobin, + false, + ) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "does not match") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceDuplicateEndpoint() { + // First one already exists from SetupTest; creating another should fail + _, err := s.Store.CreateForgeInstance( + s.adminCtx, + s.giteaEndpoint.Name, + s.giteaCreds, + "another-secret", + params.PoolBalancerTypeRoundRobin, + false, + ) + s.Require().NotNil(err) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstance() { + fi, err := s.Store.GetForgeInstance(s.adminCtx, s.giteaEndpoint.Name) + + s.Require().Nil(err) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, fi.ID) + s.Require().Equal(s.giteaEndpoint.Name, fi.Endpoint.Name) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstanceNotFound() { + _, err := s.Store.GetForgeInstance(s.adminCtx, "nonexistent-endpoint") + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "not found") +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstanceByID() { + fi, err := s.Store.GetForgeInstanceByID(s.adminCtx, s.Fixtures.ForgeInstances[0].ID) + + s.Require().Nil(err) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, fi.ID) + s.Require().Equal(s.giteaEndpoint.Name, fi.Endpoint.Name) + s.Require().Equal(s.giteaCreds.Name, fi.Credentials.Name) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstanceByIDInvalidID() { + _, err := s.Store.GetForgeInstanceByID(s.adminCtx, "not-a-uuid") + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "invalid request") +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstances() { + instances, err := s.Store.ListForgeInstances(s.adminCtx, params.ForgeInstanceFilter{}) + + s.Require().Nil(err) + s.Require().Len(instances, 1) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, instances[0].ID) +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstancesWithFilter() { + instances, err := s.Store.ListForgeInstances(s.adminCtx, params.ForgeInstanceFilter{ + Endpoint: s.giteaEndpoint.Name, + }) + s.Require().Nil(err) + s.Require().Len(instances, 1) + + instances, err = s.Store.ListForgeInstances(s.adminCtx, params.ForgeInstanceFilter{ + Endpoint: "nonexistent", + }) + s.Require().Nil(err) + s.Require().Len(instances, 0) +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstance() { + err := s.Store.DeleteForgeInstance(s.adminCtx, s.Fixtures.ForgeInstances[0].ID) + s.Require().Nil(err) + + _, err = s.Store.GetForgeInstanceByID(s.adminCtx, s.Fixtures.ForgeInstances[0].ID) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "not found") +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstanceInvalidID() { + err := s.Store.DeleteForgeInstance(s.adminCtx, "not-a-uuid") + s.Require().NotNil(err) +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstance() { + fi, err := s.Store.UpdateForgeInstance( + s.adminCtx, + s.Fixtures.ForgeInstances[0].ID, + s.Fixtures.UpdateEntityParams, + ) + s.Require().Nil(err) + s.Require().Equal(s.giteaCreds2.Name, fi.Credentials.Name) + s.Require().Equal("updated-webhook-secret", fi.WebhookSecret) +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstanceInvalidID() { + _, err := s.Store.UpdateForgeInstance(s.adminCtx, "not-a-uuid", s.Fixtures.UpdateEntityParams) + s.Require().NotNil(err) +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstancePool() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + s.Require().NotEmpty(pool.ID) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, pool.ForgeInstanceID) + + fi, err := s.Store.GetForgeInstanceByID(s.adminCtx, s.Fixtures.ForgeInstances[0].ID) + s.Require().Nil(err) + s.Require().Len(fi.Pools, 1) + s.Require().Equal(pool.ID, fi.Pools[0].ID) +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstancePools() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + _, err = s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + pools, err := s.Store.ListEntityPools(s.adminCtx, entity) + s.Require().Nil(err) + s.Require().Len(pools, 1) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstancePool() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + fetchedPool, err := s.Store.GetEntityPool(s.adminCtx, entity, pool.ID) + s.Require().Nil(err) + s.Require().Equal(pool.ID, fetchedPool.ID) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, fetchedPool.ForgeInstanceID) +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstancePool() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + err = s.Store.DeleteEntityPool(s.adminCtx, entity, pool.ID) + s.Require().Nil(err) + + pools, err := s.Store.ListEntityPools(s.adminCtx, entity) + s.Require().Nil(err) + s.Require().Len(pools, 0) +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstancePool() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + updatedPool, err := s.Store.UpdateEntityPool(s.adminCtx, entity, pool.ID, s.Fixtures.UpdatePoolParams) + s.Require().Nil(err) + s.Require().Equal(*s.Fixtures.UpdatePoolParams.MaxRunners, updatedPool.MaxRunners) + s.Require().Equal(*s.Fixtures.UpdatePoolParams.MinIdleRunners, updatedPool.MinIdleRunners) + s.Require().Equal(s.Fixtures.UpdatePoolParams.Image, updatedPool.Image) +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstanceInstances() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + createParams := []params.CreateInstanceParams{} + for i := 0; i < 3; i++ { + createParams = append(createParams, params.CreateInstanceParams{ + Name: fmt.Sprintf("test-fi-instance-%d", i), + OSType: "linux", + OSArch: "amd64", + Status: commonParams.InstanceRunning, + RunnerStatus: params.RunnerIdle, + }) + } + + expectedInstances := []params.Instance{} + for _, cp := range createParams { + inst, err := s.Store.CreateInstance(s.adminCtx, pool.ID, cp) + s.Require().Nil(err) + expectedInstances = append(expectedInstances, inst) + } + + instances, err := s.Store.ListEntityInstances(s.adminCtx, entity) + s.Require().Nil(err) + s.equalInstancesByName(expectedInstances, instances) +} + +func (s *ForgeInstanceTestSuite) TestJobRecordsForgeInstanceID() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + entityUUID, err := entity.GetIDAsUUID() + s.Require().Nil(err) + + job := params.Job{ + WorkflowJobID: 12345, + Action: "queued", + Status: "queued", + Name: "test-job", + Labels: []string{"ubuntu"}, + RepositoryName: "test-repo", + RepositoryOwner: "test-owner", + ForgeInstanceID: &entityUUID, + } + + createdJob, err := s.Store.CreateOrUpdateJob(s.adminCtx, job) + s.Require().Nil(err) + s.Require().NotNil(createdJob.ForgeInstanceID) + s.Require().Equal(entityUUID.String(), createdJob.ForgeInstanceID.String()) + + // Verify it appears in entity job listing + jobs, err := s.Store.ListEntityJobsByStatus(s.adminCtx, params.ForgeEntityTypeInstance, entity.ID, params.JobStatusQueued) + s.Require().Nil(err) + s.Require().Len(jobs, 1) + s.Require().Equal(int64(12345), jobs[0].WorkflowJobID) +} + +func (s *ForgeInstanceTestSuite) TestJobBelongsToForgeInstance() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + entityUUID, err := entity.GetIDAsUUID() + s.Require().Nil(err) + + job := params.Job{ + ForgeInstanceID: &entityUUID, + } + s.Require().True(job.BelongsTo(entity)) + + otherEntity := params.ForgeEntity{ + ID: "00000000-0000-0000-0000-000000000000", + EntityType: params.ForgeEntityTypeInstance, + } + s.Require().False(job.BelongsTo(otherEntity)) +} + +func (s *ForgeInstanceTestSuite) TestAddForgeInstanceEvent() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + err = s.Store.AddEntityEvent(s.adminCtx, entity, params.StatusEvent, params.EventInfo, "test event message", 10) + s.Require().Nil(err) + + fi, err := s.Store.GetForgeInstanceByID(s.adminCtx, s.Fixtures.ForgeInstances[0].ID) + s.Require().Nil(err) + s.Require().Len(fi.Events, 1) + s.Require().Equal("test event message", fi.Events[0].Message) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeEntity() { + entity, err := s.Store.GetForgeEntity(s.adminCtx, params.ForgeEntityTypeInstance, s.Fixtures.ForgeInstances[0].ID) + s.Require().Nil(err) + s.Require().Equal(params.ForgeEntityTypeInstance, entity.EntityType) + s.Require().Equal(s.Fixtures.ForgeInstances[0].ID, entity.ID) +} + +func (s *ForgeInstanceTestSuite) TestPoolBelongsToForgeInstance() { + entity, err := s.Fixtures.ForgeInstances[0].GetEntity() + s.Require().Nil(err) + + pool, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + s.Require().Equal(params.ForgeEntityTypeInstance, pool.PoolType()) + s.Require().True(pool.BelongsTo(entity)) + + otherEntity := params.ForgeEntity{ + ID: "00000000-0000-0000-0000-000000000000", + EntityType: params.ForgeEntityTypeInstance, + } + s.Require().False(pool.BelongsTo(otherEntity)) +} diff --git a/database/sql/jobs.go b/database/sql/jobs.go index aabfa3925..ac1709427 100644 --- a/database/sql/jobs.go +++ b/database/sql/jobs.go @@ -60,6 +60,7 @@ func sqlWorkflowJobToParamsJob(job WorkflowJob) (params.Job, error) { RepoID: job.RepoID, OrgID: job.OrgID, EnterpriseID: job.EnterpriseID, + ForgeInstanceID: job.ForgeInstanceID, Labels: labels, CreatedAt: job.CreatedAt, UpdatedAt: job.UpdatedAt, @@ -98,6 +99,7 @@ func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, conn *gorm.DB, RepoID: job.RepoID, OrgID: job.OrgID, EnterpriseID: job.EnterpriseID, + ForgeInstanceID: job.ForgeInstanceID, Labels: asJSON, LockedBy: job.LockedBy, } @@ -355,6 +357,9 @@ func (s *sqlDatabase) CreateOrUpdateJob(ctx context.Context, job params.Job) (pa if job.EnterpriseID != nil { workflowJob.EnterpriseID = job.EnterpriseID } + if job.ForgeInstanceID != nil { + workflowJob.ForgeInstanceID = job.ForgeInstanceID + } if err := tx.Save(&workflowJob).Error; err != nil { return fmt.Errorf("error saving job: %w", err) } @@ -429,6 +434,8 @@ func (s *sqlDatabase) ListEntityJobsByStatus(_ context.Context, entityType param query = query.Where("repo_id = ?", u) case params.ForgeEntityTypeEnterprise: query = query.Where("enterprise_id = ?", u) + case params.ForgeEntityTypeInstance: + query = query.Where("forge_instance_id = ?", u) } if err := query.Find(&jobs); err.Error != nil { diff --git a/database/sql/migrations/0003_forge_instances.go b/database/sql/migrations/0003_forge_instances.go new file mode 100644 index 000000000..f013859ea --- /dev/null +++ b/database/sql/migrations/0003_forge_instances.go @@ -0,0 +1,88 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 migrations + +import ( + "time" + + "github.com/go-gormigrate/gormigrate/v2" + "github.com/google/uuid" + "gorm.io/gorm" + + "github.com/cloudbase/garm/params" +) + +// Minimal model copies for the migration. These are intentionally decoupled +// from the main models so that future model changes don't break this migration. + +type forgeInstance0003 struct { + ID uuid.UUID `gorm:"type:uuid;primary_key;"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` + + GiteaCredentialsID *uint `gorm:"index"` + EndpointName *string `gorm:"uniqueIndex:idx_forgeinstance_endpoint_nocase,expression:LOWER(endpoint_name)"` + + PoolManagerRunning bool + PoolManagerFailureReason string + + WebhookSecret []byte + PoolBalancerType params.PoolBalancerType `gorm:"type:varchar(64)"` + AgentMode bool `gorm:"index:forgeinstance_agent_idx"` +} + +func (forgeInstance0003) TableName() string { return "forge_instances" } + +type forgeInstanceEvent0003 struct { + gorm.Model + + EventType params.EventType + EventLevel params.EventLevel + Message string `gorm:"type:text"` + + ForgeInstanceID uuid.UUID `gorm:"index:idx_forgeinstance_event"` +} + +func (forgeInstanceEvent0003) TableName() string { return "forge_instance_events" } + +// pool0003 and workflowJob0003 are minimal stubs that only declare the new +// column. AutoMigrate will add the column without touching existing ones. + +type pool0003 struct { + ForgeInstanceID *uuid.UUID `gorm:"index"` +} + +func (pool0003) TableName() string { return "pools" } + +type workflowJob0003 struct { + ForgeInstanceID *uuid.UUID `gorm:"index"` +} + +func (workflowJob0003) TableName() string { return "workflow_jobs" } + +func init() { + Register(&gormigrate.Migration{ + ID: "0003_forge_instances", + Migrate: func(tx *gorm.DB) error { + return tx.AutoMigrate( + &forgeInstance0003{}, + &forgeInstanceEvent0003{}, + &pool0003{}, + &workflowJob0003{}, + ) + }, + }) +} diff --git a/database/sql/models.go b/database/sql/models.go index 87776fb0c..661124221 100644 --- a/database/sql/models.go +++ b/database/sql/models.go @@ -144,6 +144,9 @@ type Pool struct { EnterpriseID *uuid.UUID `gorm:"index"` Enterprise Enterprise `gorm:"foreignKey:EnterpriseID"` + ForgeInstanceID *uuid.UUID `gorm:"index"` + ForgeInstance ForgeInstance `gorm:"foreignKey:ForgeInstanceID"` + TemplateID *uint `gorm:"index"` Template Template `gorm:"foreignKey:TemplateID"` @@ -320,6 +323,38 @@ type Enterprise struct { Events []EnterpriseEvent `gorm:"foreignKey:EnterpriseID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"` } +type ForgeInstanceEvent struct { + gorm.Model + + EventType params.EventType + EventLevel params.EventLevel + Message string `gorm:"type:text"` + + ForgeInstanceID uuid.UUID `gorm:"index:idx_forgeinstance_event"` + ForgeInstance ForgeInstance `gorm:"foreignKey:ForgeInstanceID"` +} + +type ForgeInstance struct { + Base + + GiteaCredentialsID *uint `gorm:"index"` + GiteaCredentials GiteaCredentials `gorm:"foreignKey:GiteaCredentialsID;constraint:OnDelete:SET NULL"` + + PoolManagerRunning bool + PoolManagerFailureReason string + + WebhookSecret []byte + Pools []Pool `gorm:"foreignKey:ForgeInstanceID"` + Jobs []WorkflowJob `gorm:"foreignKey:ForgeInstanceID;constraint:OnDelete:SET NULL"` + PoolBalancerType params.PoolBalancerType `gorm:"type:varchar(64)"` + AgentMode bool `gorm:"index:forgeinstance_agent_idx"` + + EndpointName *string `gorm:"uniqueIndex:idx_forgeinstance_endpoint_nocase,expression:LOWER(endpoint_name)"` + Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName;constraint:OnDelete:SET NULL"` + + Events []ForgeInstanceEvent `gorm:"foreignKey:ForgeInstanceID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"` +} + type Address struct { Base @@ -453,6 +488,9 @@ type WorkflowJob struct { EnterpriseID *uuid.UUID `gorm:"index"` Enterprise Enterprise `gorm:"foreignKey:EnterpriseID"` + ForgeInstanceID *uuid.UUID `gorm:"index"` + ForgeInstance ForgeInstance `gorm:"foreignKey:ForgeInstanceID"` + LockedBy uuid.UUID CreatedAt time.Time @@ -518,8 +556,9 @@ type GiteaCredentials struct { Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName"` EndpointName *string `gorm:"index"` - Repositories []Repository `gorm:"foreignKey:GiteaCredentialsID"` - Organizations []Organization `gorm:"foreignKey:GiteaCredentialsID"` + Repositories []Repository `gorm:"foreignKey:GiteaCredentialsID"` + Organizations []Organization `gorm:"foreignKey:GiteaCredentialsID"` + ForgeInstances []ForgeInstance `gorm:"foreignKey:GiteaCredentialsID"` } func (g GiteaCredentials) GetEndpointName() *string { @@ -563,6 +602,15 @@ func (e *Enterprise) GetEndpointName() *string { return e.EndpointName } +// ForgeInstance implements ForgeEntity +func (f *ForgeInstance) GetEndpoint() GithubEndpoint { + return f.Endpoint +} + +func (f *ForgeInstance) GetEndpointName() *string { + return f.EndpointName +} + // FileObject represents the table that holds files. This can be used to store // GARM agent binaries, runner binary downloads that may be cached, etc. type FileObject struct { diff --git a/database/sql/pools.go b/database/sql/pools.go index ba404ff24..f99ab4f6b 100644 --- a/database/sql/pools.go +++ b/database/sql/pools.go @@ -31,9 +31,10 @@ import ( ) const ( - entityTypeEnterpriseName = "enterprise_id" - entityTypeOrgName = "org_id" - entityTypeRepoName = "repo_id" + entityTypeEnterpriseName = "enterprise_id" + entityTypeOrgName = "org_id" + entityTypeRepoName = "repo_id" + entityTypeForgeInstanceName = "forge_instance_id" ) func (s *sqlDatabase) ListAllPools(_ context.Context) ([]params.Pool, error) { @@ -47,6 +48,8 @@ func (s *sqlDatabase) ListAllPools(_ context.Context) ([]params.Pool, error) { Preload("Repository.Endpoint"). Preload("Enterprise"). Preload("Enterprise.Endpoint"). + Preload("ForgeInstance"). + Preload("ForgeInstance.Endpoint"). Omit("extra_specs"). Find(&pools) if q.Error != nil { @@ -74,6 +77,8 @@ func (s *sqlDatabase) GetPoolByID(_ context.Context, poolID string) (params.Pool "Organization.Endpoint", "Repository", "Repository.Endpoint", + "ForgeInstance", + "ForgeInstance.Endpoint", "Template", } pool, err := s.getPoolByID(s.conn, poolID, preloadList...) @@ -124,6 +129,9 @@ func (s *sqlDatabase) getEntityPool(tx *gorm.DB, entityType params.ForgeEntityTy case params.ForgeEntityTypeEnterprise: fieldName = entityTypeEnterpriseName entityField = enterpriseFieldName + case params.ForgeEntityTypeInstance: + fieldName = entityTypeForgeInstanceName + entityField = forgeInstanceFieldName default: return Pool{}, fmt.Errorf("invalid entityType: %v", entityType) } @@ -172,12 +180,15 @@ func (s *sqlDatabase) listEntityPools(tx *gorm.DB, entityType params.ForgeEntity case params.ForgeEntityTypeEnterprise: fieldName = entityTypeEnterpriseName preloadEntity = "Enterprise" + case params.ForgeEntityTypeInstance: + fieldName = entityTypeForgeInstanceName + preloadEntity = "ForgeInstance" default: return nil, fmt.Errorf("invalid entityType: %v", entityType) } q := tx - q = q.Preload(preloadEntity) + q = q.Preload(preloadEntity).Preload(preloadEntity + ".Endpoint") if len(preload) > 0 { for _, item := range preload { q = q.Preload(item) @@ -217,6 +228,8 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.ForgeEntityType, fieldName = entityTypeOrgName case params.ForgeEntityTypeEnterprise: fieldName = entityTypeEnterpriseName + case params.ForgeEntityTypeInstance: + fieldName = entityTypeForgeInstanceName default: return nil, fmt.Errorf("invalid poolType: %v", poolType) } @@ -318,6 +331,8 @@ func (s *sqlDatabase) CreateEntityPool(ctx context.Context, entity params.ForgeE newPool.OrgID = &entityID case params.ForgeEntityTypeEnterprise: newPool.EnterpriseID = &entityID + case params.ForgeEntityTypeInstance: + newPool.ForgeInstanceID = &entityID } err = s.conn.Transaction(func(tx *gorm.DB) error { if err := s.hasGithubEntity(tx, entity.EntityType, entity.ID); err != nil { @@ -363,6 +378,8 @@ func (s *sqlDatabase) GetEntityPool(_ context.Context, entity params.ForgeEntity "Organization.Endpoint", "Repository", "Repository.Endpoint", + "ForgeInstance", + "ForgeInstance.Endpoint", "Template", } pool, err := s.getEntityPool(s.conn, entity.EntityType, entity.ID, poolID, preloadList...) @@ -399,6 +416,8 @@ func (s *sqlDatabase) DeleteEntityPool(_ context.Context, entity params.ForgeEnt fieldName = entityTypeOrgName case params.ForgeEntityTypeEnterprise: fieldName = entityTypeEnterpriseName + case params.ForgeEntityTypeInstance: + fieldName = entityTypeForgeInstanceName default: return fmt.Errorf("invalid entityType: %v", entity.EntityType) } diff --git a/database/sql/pools_test.go b/database/sql/pools_test.go index cb33e80a2..2fb77f210 100644 --- a/database/sql/pools_test.go +++ b/database/sql/pools_test.go @@ -144,7 +144,7 @@ func (s *PoolsTestSuite) TestListAllPools() { func (s *PoolsTestSuite) TestListAllPoolsDBFetchErr() { s.Fixtures.SQLMock. - ExpectQuery(regexp.QuoteMeta("SELECT `pools`.`id`,`pools`.`created_at`,`pools`.`updated_at`,`pools`.`deleted_at`,`pools`.`provider_name`,`pools`.`runner_prefix`,`pools`.`max_runners`,`pools`.`min_idle_runners`,`pools`.`runner_bootstrap_timeout`,`pools`.`image`,`pools`.`flavor`,`pools`.`os_type`,`pools`.`os_arch`,`pools`.`enabled`,`pools`.`git_hub_runner_group`,`pools`.`enable_shell`,`pools`.`generation`,`pools`.`repo_id`,`pools`.`org_id`,`pools`.`enterprise_id`,`pools`.`template_id`,`pools`.`priority` FROM `pools` WHERE `pools`.`deleted_at` IS NULL")). + ExpectQuery(regexp.QuoteMeta("SELECT `pools`.`id`,`pools`.`created_at`,`pools`.`updated_at`,`pools`.`deleted_at`,`pools`.`provider_name`,`pools`.`runner_prefix`,`pools`.`max_runners`,`pools`.`min_idle_runners`,`pools`.`runner_bootstrap_timeout`,`pools`.`image`,`pools`.`flavor`,`pools`.`os_type`,`pools`.`os_arch`,`pools`.`enabled`,`pools`.`git_hub_runner_group`,`pools`.`enable_shell`,`pools`.`generation`,`pools`.`repo_id`,`pools`.`org_id`,`pools`.`enterprise_id`,`pools`.`forge_instance_id`,`pools`.`template_id`,`pools`.`priority` FROM `pools` WHERE `pools`.`deleted_at` IS NULL")). WillReturnError(fmt.Errorf("mocked fetching all pools error")) _, err := s.StoreSQLMocked.ListAllPools(s.adminCtx) diff --git a/database/sql/sql.go b/database/sql/sql.go index c7d28166e..347a80b5b 100644 --- a/database/sql/sql.go +++ b/database/sql/sql.go @@ -47,9 +47,10 @@ import ( ) const ( - repositoryFieldName string = "Repository" - organizationFieldName string = "Organization" - enterpriseFieldName string = "Enterprise" + repositoryFieldName string = "Repository" + organizationFieldName string = "Organization" + enterpriseFieldName string = "Enterprise" + forgeInstanceFieldName string = "ForgeInstance" ) // newDBConn returns a new gorm db connection, given the config @@ -376,9 +377,11 @@ func (s *sqlDatabase) initSchema(tx *gorm.DB) error { &Repository{}, &Organization{}, &Enterprise{}, + &ForgeInstance{}, &EnterpriseEvent{}, &OrganizationEvent{}, &RepositoryEvent{}, + &ForgeInstanceEvent{}, &Address{}, &InstanceStatusUpdate{}, &Instance{}, diff --git a/database/sql/util.go b/database/sql/util.go index 32630fa42..6d5572cb7 100644 --- a/database/sql/util.go +++ b/database/sql/util.go @@ -294,6 +294,76 @@ func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise, detailed bool return ret, nil } +func (s *sqlDatabase) sqlToCommonForgeInstance(fi ForgeInstance, detailed bool) (params.ForgeInstance, error) { + if len(fi.WebhookSecret) == 0 { + return params.ForgeInstance{}, errors.New("missing secret") + } + secret, err := util.Unseal(fi.WebhookSecret, []byte(s.cfg.Passphrase)) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error decrypting secret: %w", err) + } + + endpoint, err := s.sqlToCommonGithubEndpoint(fi.Endpoint) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error converting endpoint: %w", err) + } + + ret := params.ForgeInstance{ + ID: fi.ID.String(), + CredentialsName: fi.GiteaCredentials.Name, + Pools: make([]params.Pool, len(fi.Pools)), + WebhookSecret: string(secret), + PoolBalancerType: fi.PoolBalancerType, + CreatedAt: fi.CreatedAt, + UpdatedAt: fi.UpdatedAt, + Endpoint: endpoint, + AgentMode: fi.AgentMode, + PoolManagerStatus: params.PoolManagerStatus{ + IsRunning: fi.PoolManagerRunning, + FailureReason: fi.PoolManagerFailureReason, + }, + } + + if fi.GiteaCredentialsID != nil { + ret.CredentialsID = *fi.GiteaCredentialsID + } + + if len(fi.Events) > 0 { + ret.Events = make([]params.EntityEvent, len(fi.Events)) + for idx, event := range fi.Events { + ret.Events[idx] = params.EntityEvent{ + ID: event.ID, + Message: event.Message, + EventType: event.EventType, + EventLevel: event.EventLevel, + CreatedAt: event.CreatedAt, + } + } + } + + if detailed { + creds, err := s.sqlGiteaToCommonForgeCredentials(fi.GiteaCredentials) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error converting credentials: %w", err) + } + ret.Credentials = creds + ret.CredentialsName = creds.Name + } + + if ret.PoolBalancerType == "" { + ret.PoolBalancerType = params.PoolBalancerTypeRoundRobin + } + + for idx, pool := range fi.Pools { + ret.Pools[idx], err = s.sqlToCommonPool(pool) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error converting pool: %w", err) + } + } + + return ret, nil +} + func (s *sqlDatabase) sqlToCommonPool(pool Pool) (params.Pool, error) { ret := params.Pool{ ID: pool.ID.String(), @@ -346,6 +416,11 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) (params.Pool, error) { ep = pool.Enterprise.Endpoint } + if pool.ForgeInstanceID != nil && pool.ForgeInstance.EndpointName != nil { + ret.ForgeInstanceID = pool.ForgeInstanceID.String() + ep = pool.ForgeInstance.Endpoint + } + endpoint, err := s.sqlToCommonGithubEndpoint(ep) if err != nil { return params.Pool{}, fmt.Errorf("error converting endpoint: %w", err) @@ -745,6 +820,8 @@ func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.ForgeEntity q = tx.Model(&Organization{}).Where("id = ?", u) case params.ForgeEntityTypeEnterprise: q = tx.Model(&Enterprise{}).Where("id = ?", u) + case params.ForgeEntityTypeInstance: + q = tx.Model(&ForgeInstance{}).Where("id = ?", u) default: return fmt.Errorf("error invalid entity type: %w", runnerErrors.ErrBadRequest) } @@ -804,6 +881,8 @@ func (s *sqlDatabase) GetForgeEntity(_ context.Context, entityType params.ForgeE ghEntity, err = s.GetOrganizationByID(s.ctx, entityID) case params.ForgeEntityTypeRepository: ghEntity, err = s.GetRepositoryByID(s.ctx, entityID) + case params.ForgeEntityTypeInstance: + ghEntity, err = s.GetForgeInstanceByID(s.ctx, entityID) default: return params.ForgeEntity{}, fmt.Errorf("error invalid entity type: %w", runnerErrors.ErrBadRequest) } @@ -957,6 +1036,50 @@ func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, even return nil } +func (s *sqlDatabase) addForgeInstanceEvent(ctx context.Context, fiID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { + fi, err := s.getForgeInstanceByID(ctx, s.conn, fiID) + if err != nil { + return fmt.Errorf("error fetching forge instance: %w", err) + } + + msg := ForgeInstanceEvent{ + Message: statusMessage, + EventType: event, + EventLevel: eventLevel, + ForgeInstanceID: fi.ID, + } + + if err := s.conn.Create(&msg).Error; err != nil { + return fmt.Errorf("error adding status message: %w", err) + } + + if maxEvents > 0 { + var count int64 + if err := s.conn.Model(&ForgeInstanceEvent{}).Where("forge_instance_id = ?", fi.ID).Count(&count).Error; err != nil { + return fmt.Errorf("error counting events: %w", err) + } + + if count > int64(maxEvents) { + var cutoffEvent ForgeInstanceEvent + if err := s.conn.Model(&ForgeInstanceEvent{}). + Select("id"). + Where("forge_instance_id = ?", fi.ID). + Order("id desc"). + Offset(maxEvents - 1). + Limit(1). + First(&cutoffEvent).Error; err != nil { + return fmt.Errorf("error finding cutoff event: %w", err) + } + + if err := s.conn.Where("forge_instance_id = ? and id < ?", fi.ID, cutoffEvent.ID).Unscoped().Delete(&ForgeInstanceEvent{}).Error; err != nil { + return fmt.Errorf("error deleting old events: %w", err) + } + } + } + + return nil +} + func (s *sqlDatabase) AddEntityEvent(ctx context.Context, entity params.ForgeEntity, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { if maxEvents == 0 { return fmt.Errorf("max events cannot be 0: %w", runnerErrors.ErrBadRequest) @@ -969,6 +1092,8 @@ func (s *sqlDatabase) AddEntityEvent(ctx context.Context, entity params.ForgeEnt return s.addOrgEvent(ctx, entity.ID, event, eventLevel, statusMessage, maxEvents) case params.ForgeEntityTypeEnterprise: return s.addEnterpriseEvent(ctx, entity.ID, event, eventLevel, statusMessage, maxEvents) + case params.ForgeEntityTypeInstance: + return s.addForgeInstanceEvent(ctx, entity.ID, event, eventLevel, statusMessage, maxEvents) default: return fmt.Errorf("invalid entity type: %w", runnerErrors.ErrBadRequest) } @@ -1215,6 +1340,10 @@ func (s *sqlDatabase) updateEntityCredentials(ctx context.Context, tx *gorm.DB, if e.GiteaCredentialsID == nil || *e.GiteaCredentialsID != credID { updates["gitea_credentials_id"] = credID } + case *ForgeInstance: + if e.GiteaCredentialsID == nil || *e.GiteaCredentialsID != credID { + updates["gitea_credentials_id"] = credID + } } default: return runnerErrors.NewBadRequestError("unsupported endpoint type: %s", forgeType) @@ -1234,6 +1363,8 @@ func (s *sqlDatabase) SetEntityPoolManagerStatus(ctx context.Context, entity par _, err = s.UpdateOrganization(ctx, entity.ID, updateEntityParams) case params.ForgeEntityTypeRepository: _, err = s.UpdateRepository(ctx, entity.ID, updateEntityParams) + case params.ForgeEntityTypeInstance: + _, err = s.UpdateForgeInstance(ctx, entity.ID, updateEntityParams) } return err } diff --git a/database/watcher/filters.go b/database/watcher/filters.go index fbfab5444..28cc47755 100644 --- a/database/watcher/filters.go +++ b/database/watcher/filters.go @@ -92,6 +92,8 @@ func WithEntityPoolFilter(ghEntity params.ForgeEntity) dbCommon.PayloadFilterFun return pool.OrgID == ghEntity.ID case params.ForgeEntityTypeEnterprise: return pool.EnterpriseID == ghEntity.ID + case params.ForgeEntityTypeInstance: + return pool.ForgeInstanceID == ghEntity.ID default: return false } @@ -162,6 +164,11 @@ func WithEntityFilter(entity params.ForgeEntity) dbCommon.PayloadFilterFunc { return false } ent, ok = payload.Payload.(params.Enterprise) + case dbCommon.ForgeInstanceEntityType: + if entity.EntityType != params.ForgeEntityTypeInstance { + return false + } + ent, ok = payload.Payload.(params.ForgeInstance) default: return false } @@ -194,6 +201,10 @@ func WithEntityJobFilter(ghEntity params.ForgeEntity) dbCommon.PayloadFilterFunc if job.EnterpriseID != nil && job.EnterpriseID.String() == ghEntity.ID { return true } + case params.ForgeEntityTypeInstance: + if job.ForgeInstanceID != nil && job.ForgeInstanceID.String() == ghEntity.ID { + return true + } } default: return false diff --git a/database/watcher/watcher_store_test.go b/database/watcher/watcher_store_test.go index 708b130da..9e3ab750b 100644 --- a/database/watcher/watcher_store_test.go +++ b/database/watcher/watcher_store_test.go @@ -1092,6 +1092,73 @@ func (s *WatcherStoreTestSuite) TestGithubEndpointWatcher() { } } +func (s *WatcherStoreTestSuite) TestForgeInstanceWatcher() { + consumer, err := watcher.RegisterConsumer( + s.ctx, "forge-instance-test", + watcher.WithEntityTypeFilter(common.ForgeInstanceEntityType), + watcher.WithAny( + watcher.WithOperationTypeFilter(common.CreateOperation), + watcher.WithOperationTypeFilter(common.UpdateOperation), + watcher.WithOperationTypeFilter(common.DeleteOperation)), + ) + s.Require().NoError(err) + s.Require().NotNil(consumer) + s.T().Cleanup(func() { consumer.Close() }) + consumeEvents(consumer) + + giteaEp := garmTesting.CreateDefaultGiteaEndpoint(s.ctx, s.store, s.T()) + giteaCreds := garmTesting.CreateTestGiteaCredentials(s.ctx, "test-gitea-creds", s.store, s.T(), giteaEp) + s.T().Cleanup(func() { s.store.DeleteGiteaCredentials(s.ctx, giteaCreds.ID) }) + + fi, err := s.store.CreateForgeInstance(s.ctx, giteaEp.Name, giteaCreds, "test-secret", params.PoolBalancerTypeRoundRobin, false) + s.Require().NoError(err) + s.Require().NotEmpty(fi.ID) + + select { + case event := <-consumer.Watch(): + s.Require().Equal(common.ChangePayload{ + EntityType: common.ForgeInstanceEntityType, + Operation: common.CreateOperation, + Payload: fi, + }, event) + case <-time.After(1 * time.Second): + s.T().Fatal("expected payload not received") + } + + updateParams := params.UpdateEntityParams{ + WebhookSecret: "updated", + } + + updatedFI, err := s.store.UpdateForgeInstance(s.ctx, fi.ID, updateParams) + s.Require().NoError(err) + s.Require().Equal("updated", updatedFI.WebhookSecret) + + select { + case event := <-consumer.Watch(): + s.Require().Equal(common.ChangePayload{ + EntityType: common.ForgeInstanceEntityType, + Operation: common.UpdateOperation, + Payload: updatedFI, + }, event) + case <-time.After(1 * time.Second): + s.T().Fatal("expected payload not received") + } + + err = s.store.DeleteForgeInstance(s.ctx, fi.ID) + s.Require().NoError(err) + + select { + case event := <-consumer.Watch(): + s.Require().Equal(common.ChangePayload{ + EntityType: common.ForgeInstanceEntityType, + Operation: common.DeleteOperation, + Payload: updatedFI, + }, event) + case <-time.After(1 * time.Second): + s.T().Fatal("expected payload not received") + } +} + func consumeEvents(consumer common.Consumer) { consume: for { diff --git a/go.mod b/go.mod index 40d4b7872..8ee6fe0f3 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/go-gormigrate/gormigrate/v2 v2.1.6 github.com/go-openapi/errors v0.22.8 github.com/go-openapi/runtime v0.32.4 - github.com/go-openapi/strfmt v0.26.3 - github.com/go-openapi/swag v0.26.1 + github.com/go-openapi/strfmt v0.26.4 + github.com/go-openapi/swag v0.27.0 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/go-github/v84 v84.0.0 github.com/google/uuid v1.6.0 @@ -22,9 +22,9 @@ require ( github.com/gorilla/websocket v1.5.4-0.20240702125206-a62d9d2a8413 github.com/h2non/filetype v1.1.3 github.com/jackc/pgx/v5 v5.10.0 - github.com/jedib0t/go-pretty/v6 v6.8.1 + github.com/jedib0t/go-pretty/v6 v6.8.2 github.com/manifoldco/promptui v0.9.0 - github.com/mattn/go-sqlite3 v1.14.45 + github.com/mattn/go-sqlite3 v1.14.47 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 github.com/prometheus/client_golang v1.23.2 github.com/rivo/tview v0.42.0 @@ -42,7 +42,7 @@ require ( gorm.io/driver/mysql v1.6.0 gorm.io/driver/postgres v1.6.0 gorm.io/driver/sqlite v1.6.0 - gorm.io/gorm v1.31.1 + gorm.io/gorm v1.31.2 ) replace github.com/mattn/go-sqlite3 => github.com/gabriel-samfira/go-sqlite3 v0.0.0-20251005121134-bc61ecf9b4c7 @@ -54,27 +54,27 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2/v2 v2.2.1 // indirect + github.com/dlclark/regexp2/v2 v2.2.2 // indirect github.com/gdamore/encoding v1.0.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.25.2 // indirect - github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/analysis v0.25.3 // indirect + github.com/go-openapi/jsonpointer v0.24.0 // indirect github.com/go-openapi/jsonreference v0.21.6 // indirect github.com/go-openapi/loads v0.24.0 // indirect - github.com/go-openapi/runtime/server-middleware v0.32.3 // indirect + github.com/go-openapi/runtime/server-middleware v0.32.4 // indirect github.com/go-openapi/spec v0.22.6 // indirect - github.com/go-openapi/swag/cmdutils v0.26.1 // indirect - github.com/go-openapi/swag/conv v0.26.1 // indirect - github.com/go-openapi/swag/fileutils v0.26.1 // indirect - github.com/go-openapi/swag/jsonname v0.26.1 // indirect - github.com/go-openapi/swag/jsonutils v0.26.1 // indirect - github.com/go-openapi/swag/loading v0.26.1 // indirect - github.com/go-openapi/swag/mangling v0.26.1 // indirect - github.com/go-openapi/swag/netutils v0.26.1 // indirect - github.com/go-openapi/swag/stringutils v0.26.1 // indirect - github.com/go-openapi/swag/typeutils v0.26.1 // indirect - github.com/go-openapi/swag/yamlutils v0.26.1 // indirect + github.com/go-openapi/swag/cmdutils v0.27.0 // indirect + github.com/go-openapi/swag/conv v0.27.0 // indirect + github.com/go-openapi/swag/fileutils v0.27.0 // indirect + github.com/go-openapi/swag/jsonname v0.27.0 // indirect + github.com/go-openapi/swag/jsonutils v0.27.0 // indirect + github.com/go-openapi/swag/loading v0.27.0 // indirect + github.com/go-openapi/swag/mangling v0.27.0 // indirect + github.com/go-openapi/swag/netutils v0.27.0 // indirect + github.com/go-openapi/swag/stringutils v0.27.0 // indirect + github.com/go-openapi/swag/typeutils v0.27.0 // indirect + github.com/go-openapi/swag/yamlutils v0.27.0 // indirect github.com/go-openapi/validate v0.26.0 // indirect github.com/go-sql-driver/mysql v1.10.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect @@ -96,8 +96,8 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.68.1 // indirect - github.com/prometheus/procfs v0.20.1 // indirect + github.com/prometheus/common v0.69.0 // indirect + github.com/prometheus/procfs v0.21.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect diff --git a/go.sum b/go.sum index 7b279994a..fbd39e680 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6N github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0= -github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= +github.com/dlclark/regexp2/v2 v2.2.2 h1:MYWvNYw8okuqNhwTYO587EZMiDruVa2vhV6fsGpfya0= +github.com/dlclark/regexp2/v2 v2.2.2/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/gabriel-samfira/go-sqlite3 v0.0.0-20251005121134-bc61ecf9b4c7 h1:+r9O7HrPI4OpkdFsZ9l5sjRD99KOl9uw4XpYJiP2HV4= @@ -48,54 +48,54 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.25.2 h1:I0vy4n3alz+DHTiN1PRhCb7QZxkK6g5YmswZKv2TKuw= -github.com/go-openapi/analysis v0.25.2/go.mod h1:Uhs1t/2XR10EnwONYILGEzw8gcfGIG5Xk5K2AxnhqDo= +github.com/go-openapi/analysis v0.25.3 h1:4zlcg85pd2xq3sEgjW887n1IpwCpCqTmqeT6dP9OxDw= +github.com/go-openapi/analysis v0.25.3/go.mod h1:6PEmUIra9/rn6SPstzbrMkhFAsMB2qm7g6E+4DRFyCU= github.com/go-openapi/errors v0.22.8 h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I= github.com/go-openapi/errors v0.22.8/go.mod h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w= -github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= -github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= +github.com/go-openapi/jsonpointer v0.24.0 h1:AA6mCjHYHmZ+1RU2Js089EaOK/iwXXNwQsTgnsTha2M= +github.com/go-openapi/jsonpointer v0.24.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= github.com/go-openapi/loads v0.24.0 h1:4LLorXRPTzIN9V6ngMUZbAscsBOUBk3Oa8cClu/bFrQ= github.com/go-openapi/loads v0.24.0/go.mod h1:xQMgX+hw5xRAhGrcDXxeMw78IFqUpIzhleu3HqPhyF4= github.com/go-openapi/runtime v0.32.4 h1:8ElGj/3goG0itt0nBPP6Cm57ehcYyuHoI3O20nxgvkw= github.com/go-openapi/runtime v0.32.4/go.mod h1:Bz6keOZw1NX4T6f+m42OoT1MBPDt6Re13dbccHyGH/4= -github.com/go-openapi/runtime/server-middleware v0.32.3 h1:Y/6h9ix9NCoMG04XazRwX6eA3alh4+JZ6qXdar5yd24= -github.com/go-openapi/runtime/server-middleware v0.32.3/go.mod h1:fYPep4GdTwg/XqZUjR40uIM/8C12Ba5M+MrGCiwpTHo= +github.com/go-openapi/runtime/server-middleware v0.32.4 h1:AU6eLMq9CXwh8f6kC1pivtkz+7lfo3TmakMBbUisKME= +github.com/go-openapi/runtime/server-middleware v0.32.4/go.mod h1:fYPep4GdTwg/XqZUjR40uIM/8C12Ba5M+MrGCiwpTHo= github.com/go-openapi/spec v0.22.6 h1:Tyy1pLaNCM8GBCFLoGYLonjJi6zykqyLCjXLc19ZPic= github.com/go-openapi/spec v0.22.6/go.mod h1:HZvTHat+iH0PALQRWhrqIHtU/PEqxqd89fu0MxGlMeM= -github.com/go-openapi/strfmt v0.26.3 h1:rzmslHarJgBbf2qfGge+X3htclQfmXqBZMm0Too0HhU= -github.com/go-openapi/strfmt v0.26.3/go.mod h1:a5nsUw0oRpQzZeOwx8bi6cKbzFZslpbCKt1LEot+KnQ= -github.com/go-openapi/swag v0.26.1 h1:l5sVEyVpwj+DDYeZyo7wQI/Ebn/mKYIyGB/pFwAfGoQ= -github.com/go-openapi/swag v0.26.1/go.mod h1:yNY38BbIVthxbkDtq1UHBCGasBqjakW3lCR6ANzdBEw= -github.com/go-openapi/swag/cmdutils v0.26.1 h1:f2iE1ijYaJ3nuu5PaEMx3zpEhzhZFgivCJObWEObLIQ= -github.com/go-openapi/swag/cmdutils v0.26.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= -github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg= -github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A= -github.com/go-openapi/swag/fileutils v0.26.1 h1:K1XCM2CGhfNsc6YDt6v7Q5+1e59rftYWdcu/isZhvFw= -github.com/go-openapi/swag/fileutils v0.26.1/go.mod h1:mYUgxQAKX4ShS3qvvySx+/9yrlUnDhjiD1CalaQl8lQ= -github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= -github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= -github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY= -github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc= -github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w= -github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E= -github.com/go-openapi/swag/mangling v0.26.1 h1:gpYI4WuPKFJJVjV5cDLGlDVJhFIxYjQc7yN5eEb4CqM= -github.com/go-openapi/swag/mangling v0.26.1/go.mod h1:POETDH01hqAdASXfw7ISEd9bCOE6xBHOt8NHmGZRmYM= -github.com/go-openapi/swag/netutils v0.26.1 h1:BNctoc39WTAUMxyAs355fExOPzMZtPbZ0ZZ1Am2FR5M= -github.com/go-openapi/swag/netutils v0.26.1/go.mod h1:y02vByhZhQPAVwOX+0KipXFZ/hUbk6G/Enhf5rGaOkQ= -github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU= -github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk= -github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU= -github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= -github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= -github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk= -github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= -github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/strfmt v0.26.4 h1:yI6IAEfcWow459BD5UzFY430KUwXZwBHrYusPFkhWlc= +github.com/go-openapi/strfmt v0.26.4/go.mod h1:hNJi6nb5ETD6i7A1yRo03M9S6ZoTPPoWff1iUexmfUc= +github.com/go-openapi/swag v0.27.0 h1:8ecSuZlh4NXc3GsmAOqECIYqDTApCWaMe3gO4gjJNEE= +github.com/go-openapi/swag v0.27.0/go.mod h1:Kkgz9Ht0+ul9/aVdFmc9xSyPzUwf/aFF5KiFPBXfSY0= +github.com/go-openapi/swag/cmdutils v0.27.0 h1:aIKiqhB29AaP+7xm8/CPg3uOpeHx2SUp6TvMpu/a31Y= +github.com/go-openapi/swag/cmdutils v0.27.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= +github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= +github.com/go-openapi/swag/fileutils v0.27.0 h1:ib5jMUqGq5tY1EyO4inlrabsaeDAleFU+XD1FXQcgp8= +github.com/go-openapi/swag/fileutils v0.27.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= +github.com/go-openapi/swag/jsonname v0.27.0 h1:4QVB//CKOdE8IOiBg19JNY2wfDS48MhesIquYBy2rUE= +github.com/go-openapi/swag/jsonname v0.27.0/go.mod h1:I1YsyvvhBuZsFXSW6I7ODfdyq13p7hDil//1T9/pFFk= +github.com/go-openapi/swag/jsonutils v0.27.0 h1:VYtd9jEQYeU4j8q5vdn5KWotF4vKywhGdMBrALtAsfE= +github.com/go-openapi/swag/jsonutils v0.27.0/go.mod h1:U7pb8AGuwhok3RDicHeHwSG4L3PXSq6PAL98Aon632g= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0 h1:+d7C7Ur/SsGg/UZ9G0JEovnfRqtMNZCJQGKc2h/ojoE= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.0 h1:s8DA9aPEdFH6OluHUYUn3DnIuoTdyWs9RwffXBUfyeI= +github.com/go-openapi/swag/loading v0.27.0/go.mod h1:VOz+Jg6UGGywcmRvYsI4fvtp+bd7NfioseGEPleYdA4= +github.com/go-openapi/swag/mangling v0.27.0 h1:rpPJuqQHa6z2pDiP3iIpXOyNXlSs9cQCxnJSAxzdfOc= +github.com/go-openapi/swag/mangling v0.27.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= +github.com/go-openapi/swag/netutils v0.27.0 h1:lEUG+hHvPvLggB3A8snFk0IRKNf9uC0YKc+7WYqvAF8= +github.com/go-openapi/swag/netutils v0.27.0/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= +github.com/go-openapi/swag/stringutils v0.27.0 h1:Of7w/HljWsNZvuxsUAnw3n+hCOyI6HLJOxW2kQRAxio= +github.com/go-openapi/swag/stringutils v0.27.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.0 h1:aCf4MSGo8NLwZP8Q6t32DWLJSvl/WwNqgmEG+xJ6v2o= +github.com/go-openapi/swag/typeutils v0.27.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.0 h1:bQ6eAMil5X9tdcf7dMn4t15alzG6jddnrKPuKa/zxKM= +github.com/go-openapi/swag/yamlutils v0.27.0/go.mod h1:yRfIo7qqVkmJRQjX8exjA3AfcI8rH1KDNPsTparoCv4= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-openapi/validate v0.26.0 h1:dxWzQ3F+vb1SajqUxHjwb5T4mTpSHmdrtv5Bi7+ZNhw= github.com/go-openapi/validate v0.26.0/go.mod h1:b4o00uq7fJeJA+wWhVFCJpKTctzeFwzZImGGmHsl2JA= github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= @@ -141,8 +141,8 @@ github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0= github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jedib0t/go-pretty/v6 v6.8.1 h1:0fkCNhjrX0zPpwkWaDYU5VMrygg41Tu197mWILIJoqQ= -github.com/jedib0t/go-pretty/v6 v6.8.1/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= +github.com/jedib0t/go-pretty/v6 v6.8.2 h1:FmKNr1GOyot/zqNQplE8HLhFguJaeHJTCArntnI4uxE= +github.com/jedib0t/go-pretty/v6 v6.8.2/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -183,10 +183,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.68.1 h1:omjRRl4QP4komogpXuhfeOiisQg7xdy8VM1UY+pStaY= -github.com/prometheus/common v0.68.1/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y= -github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= -github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/prometheus/common v0.69.0 h1:OA85nJQS/T/MaYh/Q2CcgDKSGWqNIgrBDvDH85CuiNk= +github.com/prometheus/common v0.69.0/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y= +github.com/prometheus/procfs v0.21.0 h1:Qh/e6TlBjZf+XLLqNCqFGmCU6Kj/2Bu7kj3oAc0UnXc= +github.com/prometheus/procfs v0.21.0/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= @@ -296,5 +296,5 @@ gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= -gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= -gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo= +gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/params/params.go b/params/params.go index 36f7821d2..31c468824 100644 --- a/params/params.go +++ b/params/params.go @@ -84,6 +84,17 @@ const ( GiteaEndpointType EndpointType = "gitea" ) +// SupportsInstancePools reports whether this forge type supports +// instance-level (global/admin) runner pools. +func (e EndpointType) SupportsInstancePools() bool { + switch e { + case GiteaEndpointType: + return true + default: + return false + } +} + const ( // LXDProvider represents the LXD provider. LXDProvider ProviderType = "lxd" @@ -116,12 +127,14 @@ const ( ForgeEntityTypeRepository ForgeEntityType = "repository" ForgeEntityTypeOrganization ForgeEntityType = "organization" ForgeEntityTypeEnterprise ForgeEntityType = "enterprise" + ForgeEntityTypeInstance ForgeEntityType = "instance" ) const ( MetricsLabelEnterpriseScope = "Enterprise" MetricsLabelRepositoryScope = "Repository" MetricsLabelOrganizationScope = "Organization" + MetricsLabelInstanceScope = "Instance" ) const ( @@ -501,6 +514,8 @@ type Pool struct { EnterpriseID string `json:"enterprise_id,omitempty"` EnterpriseName string `json:"enterprise_name,omitempty"` + ForgeInstanceID string `json:"forge_instance_id,omitempty"` + Endpoint ForgeEndpoint `json:"endpoint,omitempty"` RunnerBootstrapTimeout uint `json:"runner_bootstrap_timeout,omitempty"` @@ -533,6 +548,8 @@ func (p Pool) BelongsTo(entity ForgeEntity) bool { return p.OrgID == entity.ID case ForgeEntityTypeEnterprise: return p.EnterpriseID == entity.ID + case ForgeEntityTypeInstance: + return p.ForgeInstanceID == entity.ID } return false } @@ -573,6 +590,11 @@ func (p Pool) GetEntity() (ForgeEntity, error) { ID: p.EnterpriseID, EntityType: ForgeEntityTypeEnterprise, }, nil + case ForgeEntityTypeInstance: + return ForgeEntity{ + ID: p.ForgeInstanceID, + EntityType: ForgeEntityTypeInstance, + }, nil } return ForgeEntity{}, fmt.Errorf("pool has no associated entity") } @@ -596,6 +618,8 @@ func (p *Pool) PoolType() ForgeEntityType { return ForgeEntityTypeOrganization case p.EnterpriseID != "": return ForgeEntityTypeEnterprise + case p.ForgeInstanceID != "": + return ForgeEntityTypeInstance } return "" } @@ -967,6 +991,64 @@ func (e Enterprise) GetBalancerType() PoolBalancerType { // swagger:model Enterprises type Enterprises []Enterprise +// swagger:model ForgeInstance +type ForgeInstance struct { + ID string `json:"id,omitempty"` + Pools []Pool `json:"pool,omitempty"` + // CredentialName is the name of the credentials associated with the forge instance. + // This field is now deprecated. Use CredentialsID instead. This field will be + // removed in v0.2.0. + CredentialsName string `json:"credentials_name,omitempty"` + Credentials ForgeCredentials `json:"credentials,omitempty"` + CredentialsID uint `json:"credentials_id,omitempty"` + PoolManagerStatus PoolManagerStatus `json:"pool_manager_status,omitempty"` + PoolBalancerType PoolBalancerType `json:"pool_balancing_type,omitempty"` + Endpoint ForgeEndpoint `json:"endpoint,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty"` + Events []EntityEvent `json:"events,omitempty"` + AgentMode bool `json:"agent_mode"` + // Do not serialize sensitive info. + WebhookSecret string `json:"-"` +} + +func (f ForgeInstance) GetCreatedAt() time.Time { + return f.CreatedAt +} + +func (f ForgeInstance) GetEntity() (ForgeEntity, error) { + if f.ID == "" { + return ForgeEntity{}, fmt.Errorf("forge instance has no ID") + } + return ForgeEntity{ + ID: f.ID, + EntityType: ForgeEntityTypeInstance, + Owner: f.Endpoint.Name, + WebhookSecret: f.WebhookSecret, + PoolBalancerType: f.PoolBalancerType, + PoolManagerStatus: f.PoolManagerStatus, + Credentials: f.Credentials, + CreatedAt: f.CreatedAt, + UpdatedAt: f.UpdatedAt, + AgentMode: f.AgentMode, + }, nil +} + +func (f ForgeInstance) GetID() string { + return f.ID +} + +func (f ForgeInstance) GetBalancerType() PoolBalancerType { + if f.PoolBalancerType == "" { + return PoolBalancerTypeRoundRobin + } + return f.PoolBalancerType +} + +// used by swagger client generated code +// swagger:model ForgeInstances +type ForgeInstances []ForgeInstance + // Users holds information about a particular user // swagger:model User type User struct { @@ -1305,9 +1387,10 @@ type Job struct { // entity type, in response to one workflow event. Thus, we will get 3 webhooks // with the same run_id and job id. Record all involved entities in the same job // if we have them configured in garm. - RepoID *uuid.UUID `json:"repo_id,omitempty"` - OrgID *uuid.UUID `json:"org_id,omitempty"` - EnterpriseID *uuid.UUID `json:"enterprise_id,omitempty"` + RepoID *uuid.UUID `json:"repo_id,omitempty"` + OrgID *uuid.UUID `json:"org_id,omitempty"` + EnterpriseID *uuid.UUID `json:"enterprise_id,omitempty"` + ForgeInstanceID *uuid.UUID `json:"forge_instance_id,omitempty"` LockedBy uuid.UUID `json:"locked_by,omitempty"` @@ -1329,6 +1412,10 @@ func (j Job) BelongsTo(entity ForgeEntity) bool { if j.OrgID != nil { return entity.ID == j.OrgID.String() } + case ForgeEntityTypeInstance: + if j.ForgeInstanceID != nil { + return entity.ID == j.ForgeInstanceID.String() + } default: return false } @@ -1366,15 +1453,16 @@ type UpdateSystemInfoParams struct { // swagger:model ForgeEntity type ForgeEntity struct { + ID string `json:"id,omitempty"` + Forge ForgeEndpoint `json:"forge"` Owner string `json:"owner,omitempty"` Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` EntityType ForgeEntityType `json:"entity_type,omitempty"` - Credentials ForgeCredentials `json:"credentials,omitempty"` - PoolBalancerType PoolBalancerType `json:"pool_balancing_type,omitempty"` - PoolManagerStatus PoolManagerStatus `json:"pool_manager_status,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - UpdatedAt time.Time `json:"updated_at,omitempty"` + Credentials ForgeCredentials `json:"credentials"` + PoolBalancerType PoolBalancerType `json:"pool_balancing_type"` + PoolManagerStatus PoolManagerStatus `json:"pool_manager_status"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` AgentMode bool `json:"agent_mode"` WebhookSecret string `json:"-"` @@ -1425,6 +1513,8 @@ func (g ForgeEntity) LabelScope() string { return MetricsLabelOrganizationScope case ForgeEntityTypeEnterprise: return MetricsLabelEnterpriseScope + case ForgeEntityTypeInstance: + return MetricsLabelInstanceScope } return "" } @@ -1435,6 +1525,8 @@ func (g ForgeEntity) String() string { return fmt.Sprintf("%s/%s", g.Owner, g.Name) case ForgeEntityTypeOrganization, ForgeEntityTypeEnterprise: return g.Owner + case ForgeEntityTypeInstance: + return g.Credentials.Endpoint.Name } return "" } @@ -1487,6 +1579,10 @@ type EnterpriseFilter struct { Endpoint string } +type ForgeInstanceFilter struct { + Endpoint string +} + // swagger:model Template type Template struct { ID uint `json:"id"` diff --git a/params/requests.go b/params/requests.go index d36773fd7..3b52e2c42 100644 --- a/params/requests.go +++ b/params/requests.go @@ -147,6 +147,39 @@ func (c *CreateEnterpriseParams) Validate() error { return nil } +// swagger:model CreateForgeInstanceParams +type CreateForgeInstanceParams struct { + EndpointName string `json:"endpoint_name,omitempty"` + CredentialsName string `json:"credentials_name,omitempty"` + WebhookSecret string `json:"webhook_secret,omitempty"` + ForgeType EndpointType `json:"forge_type,omitempty"` + PoolBalancerType PoolBalancerType `json:"pool_balancer_type,omitempty"` + AgentMode bool `json:"agent_mode,omitempty"` +} + +func (c *CreateForgeInstanceParams) Validate() error { + if c.EndpointName == "" { + return runnerErrors.NewBadRequestError("missing endpoint name") + } + if c.CredentialsName == "" { + return runnerErrors.NewBadRequestError("missing credentials name") + } + if c.WebhookSecret == "" { + return runnerErrors.NewBadRequestError("missing webhook secret") + } + + if !c.ForgeType.SupportsInstancePools() { + return runnerErrors.NewBadRequestError("forge type %q does not support instance-level pools", c.ForgeType) + } + + switch c.PoolBalancerType { + case PoolBalancerTypeRoundRobin, PoolBalancerTypePack, PoolBalancerTypeNone: + default: + return runnerErrors.NewBadRequestError("invalid pool balancer type") + } + return nil +} + // NewUserParams holds the needed information to create // a new user // swagger:model NewUserParams diff --git a/runner/forge_instances.go b/runner/forge_instances.go new file mode 100644 index 000000000..b97fbabe1 --- /dev/null +++ b/runner/forge_instances.go @@ -0,0 +1,449 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 runner + +import ( + "context" + "errors" + "fmt" + "log/slog" + "strings" + + runnerErrors "github.com/cloudbase/garm-provider-common/errors" + "github.com/cloudbase/garm/auth" + "github.com/cloudbase/garm/params" + "github.com/cloudbase/garm/runner/common" + "github.com/cloudbase/garm/util/appdefaults" +) + +func (r *Runner) CreateForgeInstance(ctx context.Context, param params.CreateForgeInstanceParams) (forgeInstance params.ForgeInstance, err error) { + if !auth.IsAdmin(ctx) { + return forgeInstance, runnerErrors.ErrUnauthorized + } + + err = param.Validate() + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error validating params: %w", err) + } + + var creds params.ForgeCredentials + switch param.ForgeType { + case params.GiteaEndpointType: + creds, err = r.store.GetGiteaCredentialsByName(ctx, param.CredentialsName, true) + default: + return params.ForgeInstance{}, runnerErrors.NewBadRequestError("unsupported forge type: %s", param.ForgeType) + } + if err != nil { + return params.ForgeInstance{}, runnerErrors.NewBadRequestError("credentials %s not defined", param.CredentialsName) + } + + if creds.Endpoint.Name != param.EndpointName { + return params.ForgeInstance{}, runnerErrors.NewBadRequestError("credentials endpoint %q does not match requested endpoint %q", creds.Endpoint.Name, param.EndpointName) + } + + _, err = r.store.GetForgeInstance(ctx, param.EndpointName) + if err != nil { + if !errors.Is(err, runnerErrors.ErrNotFound) { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + } else { + return params.ForgeInstance{}, runnerErrors.NewConflictError("forge instance for endpoint %s already exists", param.EndpointName) + } + + forgeInstance, err = r.store.CreateForgeInstance(ctx, param.EndpointName, creds, param.WebhookSecret, param.PoolBalancerType, param.AgentMode) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error creating forge instance: %w", err) + } + + defer func() { + if err != nil { + if deleteErr := r.store.DeleteForgeInstance(ctx, forgeInstance.ID); deleteErr != nil { + slog.With(slog.Any("error", deleteErr)).ErrorContext( + ctx, "failed to delete forge instance", + "forge_instance_id", forgeInstance.ID) + } + } + }() + + var poolMgr common.PoolManager + poolMgr, err = r.poolManagerCtrl.CreateForgeInstancePoolManager(r.ctx, forgeInstance, r.providers, r.store) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error creating forge instance pool manager: %w", err) + } + if err := poolMgr.Start(); err != nil { + if deleteErr := r.poolManagerCtrl.DeleteForgeInstancePoolManager(forgeInstance); deleteErr != nil { + slog.With(slog.Any("error", deleteErr)).ErrorContext( + ctx, "failed to cleanup pool manager for forge instance", + "forge_instance_id", forgeInstance.ID) + } + return params.ForgeInstance{}, fmt.Errorf("error starting forge instance pool manager: %w", err) + } + return forgeInstance, nil +} + +func (r *Runner) ListForgeInstances(ctx context.Context, filter params.ForgeInstanceFilter) ([]params.ForgeInstance, error) { + if !auth.IsAdmin(ctx) { + return nil, runnerErrors.ErrUnauthorized + } + + forgeInstances, err := r.store.ListForgeInstances(ctx, filter) + if err != nil { + return nil, fmt.Errorf("error listing forge instances: %w", err) + } + + return forgeInstances, nil +} + +func (r *Runner) GetForgeInstanceByID(ctx context.Context, forgeInstanceID string) (params.ForgeInstance, error) { + if !auth.IsAdmin(ctx) { + return params.ForgeInstance{}, runnerErrors.ErrUnauthorized + } + + forgeInstance, err := r.store.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error fetching forge instance: %w", err) + } + + return forgeInstance, nil +} + +func (r *Runner) DeleteForgeInstance(ctx context.Context, forgeInstanceID string, keepWebhook bool) error { + if !auth.IsAdmin(ctx) { + return runnerErrors.ErrUnauthorized + } + + forgeInstance, err := r.store.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + return fmt.Errorf("error fetching forge instance: %w", err) + } + + entity, err := forgeInstance.GetEntity() + if err != nil { + return fmt.Errorf("error getting entity: %w", err) + } + + pools, err := r.store.ListEntityPools(ctx, entity) + if err != nil { + return fmt.Errorf("error fetching forge instance pools: %w", err) + } + + if len(pools) > 0 { + poolIDs := []string{} + for _, pool := range pools { + poolIDs = append(poolIDs, pool.ID) + } + + return runnerErrors.NewBadRequestError("forge instance has pools defined (%s)", strings.Join(poolIDs, ", ")) + } + + if !keepWebhook && r.config.Default.EnableWebhookManagement { + poolMgr, err := r.poolManagerCtrl.GetForgeInstancePoolManager(forgeInstance) + if err != nil { + return fmt.Errorf("error fetching pool manager: %w", err) + } + + if err := poolMgr.UninstallWebhook(ctx); err != nil { + slog.With(slog.Any("error", err)).ErrorContext( + ctx, "failed to uninstall webhook", + "forge_instance_id", forgeInstance.ID) + } + } + + if err := r.poolManagerCtrl.DeleteForgeInstancePoolManager(forgeInstance); err != nil { + return fmt.Errorf("error deleting forge instance pool manager: %w", err) + } + + if err := r.store.DeleteForgeInstance(ctx, forgeInstanceID); err != nil { + return fmt.Errorf("error removing forge instance %s: %w", forgeInstanceID, err) + } + return nil +} + +func (r *Runner) UpdateForgeInstance(ctx context.Context, forgeInstanceID string, param params.UpdateEntityParams) (params.ForgeInstance, error) { + if !auth.IsAdmin(ctx) { + return params.ForgeInstance{}, runnerErrors.ErrUnauthorized + } + + r.mux.Lock() + defer r.mux.Unlock() + + switch param.PoolBalancerType { + case params.PoolBalancerTypeRoundRobin, params.PoolBalancerTypePack, params.PoolBalancerTypeNone: + default: + return params.ForgeInstance{}, runnerErrors.NewBadRequestError("invalid pool balancer type: %s", param.PoolBalancerType) + } + + forgeInstance, err := r.store.UpdateForgeInstance(ctx, forgeInstanceID, param) + if err != nil { + return params.ForgeInstance{}, fmt.Errorf("error updating forge instance: %w", err) + } + + return forgeInstance, nil +} + +func (r *Runner) CreateForgeInstancePool(ctx context.Context, forgeInstanceID string, param params.CreatePoolParams) (params.Pool, error) { + if !auth.IsAdmin(ctx) { + return params.Pool{}, runnerErrors.ErrUnauthorized + } + + createPoolParams, err := r.appendTagsToCreatePoolParams(param) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to append tags to create pool params: %w", err) + } + + if param.RunnerBootstrapTimeout == 0 { + param.RunnerBootstrapTimeout = appdefaults.DefaultRunnerBootstrapTimeout + } + + entity, err := r.store.GetForgeEntity(ctx, params.ForgeEntityTypeInstance, forgeInstanceID) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to get forge instance: %w", err) + } + + template, err := r.findTemplate(ctx, entity, param.OSType, param.TemplateID) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to find suitable template: %w", err) + } + + createPoolParams.TemplateID = &template.ID + pool, err := r.store.CreateEntityPool(ctx, entity, createPoolParams) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to create forge instance pool: %w", err) + } + + return pool, nil +} + +func (r *Runner) GetForgeInstancePoolByID(ctx context.Context, forgeInstanceID, poolID string) (params.Pool, error) { + if !auth.IsAdmin(ctx) { + return params.Pool{}, runnerErrors.ErrUnauthorized + } + entity := params.ForgeEntity{ + ID: forgeInstanceID, + EntityType: params.ForgeEntityTypeInstance, + } + pool, err := r.store.GetEntityPool(ctx, entity, poolID) + if err != nil { + return params.Pool{}, fmt.Errorf("error fetching pool: %w", err) + } + return pool, nil +} + +func (r *Runner) DeleteForgeInstancePool(ctx context.Context, forgeInstanceID, poolID string) error { + if !auth.IsAdmin(ctx) { + return runnerErrors.ErrUnauthorized + } + + entity := params.ForgeEntity{ + ID: forgeInstanceID, + EntityType: params.ForgeEntityTypeInstance, + } + + pool, err := r.store.GetEntityPool(ctx, entity, poolID) + if err != nil { + return fmt.Errorf("error fetching pool: %w", err) + } + + // nolint:golangci-lint,godox + // TODO: implement a count function + if len(pool.Instances) > 0 { + runnerIDs := []string{} + for _, run := range pool.Instances { + runnerIDs = append(runnerIDs, run.ID) + } + return runnerErrors.NewBadRequestError("pool has runners: %s", strings.Join(runnerIDs, ", ")) + } + + if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil { + return fmt.Errorf("error deleting pool: %w", err) + } + return nil +} + +func (r *Runner) ListForgeInstancePools(ctx context.Context, forgeInstanceID string) ([]params.Pool, error) { + if !auth.IsAdmin(ctx) { + return []params.Pool{}, runnerErrors.ErrUnauthorized + } + + entity := params.ForgeEntity{ + ID: forgeInstanceID, + EntityType: params.ForgeEntityTypeInstance, + } + pools, err := r.store.ListEntityPools(ctx, entity) + if err != nil { + return nil, fmt.Errorf("error fetching pools: %w", err) + } + return pools, nil +} + +func (r *Runner) UpdateForgeInstancePool(ctx context.Context, forgeInstanceID, poolID string, param params.UpdatePoolParams) (params.Pool, error) { + if !auth.IsAdmin(ctx) { + return params.Pool{}, runnerErrors.ErrUnauthorized + } + entity, err := r.store.GetForgeEntity(ctx, params.ForgeEntityTypeInstance, forgeInstanceID) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to get forge instance: %w", err) + } + + if param.TemplateID != nil { + template, err := r.findTemplate(ctx, entity, param.OSType, param.TemplateID) + if err != nil { + return params.Pool{}, fmt.Errorf("failed to find suitable template: %w", err) + } + param.TemplateID = &template.ID + } + pool, err := r.store.GetEntityPool(ctx, entity, poolID) + if err != nil { + return params.Pool{}, fmt.Errorf("error fetching pool: %w", err) + } + + maxRunners := pool.MaxRunners + minIdleRunners := pool.MinIdleRunners + + if param.MaxRunners != nil { + maxRunners = *param.MaxRunners + } + if param.MinIdleRunners != nil { + minIdleRunners = *param.MinIdleRunners + } + + if minIdleRunners > maxRunners { + return params.Pool{}, runnerErrors.NewBadRequestError("min_idle_runners cannot be larger than max_runners") + } + + newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param) + if err != nil { + return params.Pool{}, fmt.Errorf("error updating pool: %w", err) + } + return newPool, nil +} + +func (r *Runner) ListForgeInstanceInstances(ctx context.Context, forgeInstanceID string) ([]params.Instance, error) { + if !auth.IsAdmin(ctx) { + return nil, runnerErrors.ErrUnauthorized + } + entity := params.ForgeEntity{ + ID: forgeInstanceID, + EntityType: params.ForgeEntityTypeInstance, + } + instances, err := r.store.ListEntityInstances(ctx, entity) + if err != nil { + return []params.Instance{}, fmt.Errorf("error fetching instances: %w", err) + } + return instances, nil +} + +func (r *Runner) InstallForgeInstanceWebhook(ctx context.Context, forgeInstanceID string, param params.InstallWebhookParams) (params.HookInfo, error) { + if !auth.IsAdmin(ctx) { + return params.HookInfo{}, runnerErrors.ErrUnauthorized + } + + fi, err := r.store.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error fetching forge instance: %w", err) + } + + poolMgr, err := r.poolManagerCtrl.GetForgeInstancePoolManager(fi) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error fetching pool manager for forge instance: %w", err) + } + + info, err := poolMgr.InstallWebhook(ctx, param) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error installing webhook: %w", err) + } + return info, nil +} + +func (r *Runner) UninstallForgeInstanceWebhook(ctx context.Context, forgeInstanceID string) error { + if !auth.IsAdmin(ctx) { + return runnerErrors.ErrUnauthorized + } + + fi, err := r.store.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + return fmt.Errorf("error fetching forge instance: %w", err) + } + + poolMgr, err := r.poolManagerCtrl.GetForgeInstancePoolManager(fi) + if err != nil { + return fmt.Errorf("error fetching pool manager for forge instance: %w", err) + } + + if err := poolMgr.UninstallWebhook(ctx); err != nil { + return fmt.Errorf("error uninstalling webhook: %w", err) + } + return nil +} + +func (r *Runner) GetForgeInstanceWebhookInfo(ctx context.Context, forgeInstanceID string) (params.HookInfo, error) { + if !auth.IsAdmin(ctx) { + return params.HookInfo{}, runnerErrors.ErrUnauthorized + } + + fi, err := r.store.GetForgeInstanceByID(ctx, forgeInstanceID) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error fetching forge instance: %w", err) + } + + poolMgr, err := r.poolManagerCtrl.GetForgeInstancePoolManager(fi) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error fetching pool manager for forge instance: %w", err) + } + + info, err := poolMgr.GetWebhookInfo(ctx) + if err != nil { + return params.HookInfo{}, fmt.Errorf("error fetching webhook info: %w", err) + } + return info, nil +} + +func (r *Runner) findForgeInstancePoolManager(endpointName string) (common.PoolManager, error) { + r.mux.Lock() + defer r.mux.Unlock() + + forgeInstance, err := r.store.GetForgeInstance(r.ctx, endpointName) + if err != nil { + return nil, fmt.Errorf("error fetching forge instance: %w", err) + } + + poolManager, err := r.poolManagerCtrl.GetForgeInstancePoolManager(forgeInstance) + if err != nil { + return nil, fmt.Errorf("error fetching pool manager for forge instance: %w", err) + } + return poolManager, nil +} + +func (r *Runner) createAndStartForgeInstancePoolManager(forgeInstance params.ForgeInstance) { + slog.InfoContext(r.ctx, "creating pool manager for forge instance", "forge_instance_id", forgeInstance.ID, "endpoint", forgeInstance.Endpoint.Name) + poolMgr, err := r.poolManagerCtrl.CreateForgeInstancePoolManager(r.ctx, forgeInstance, r.providers, r.store) + if err != nil { + slog.ErrorContext(r.ctx, "creating forge instance pool manager", "forge_instance_id", forgeInstance.ID, "error", err) + r.failedEntities[forgeInstance.ID] = failedEntity{entityType: params.ForgeEntityTypeInstance, id: forgeInstance.ID} + r.backoff.RecordFailure(forgeInstance.ID) + return + } + if err := poolMgr.Start(); err != nil { + slog.ErrorContext(r.ctx, "starting forge instance pool manager", "forge_instance_id", forgeInstance.ID, "error", err) + if deleteErr := r.poolManagerCtrl.DeleteForgeInstancePoolManager(forgeInstance); deleteErr != nil { + slog.ErrorContext(r.ctx, "cleaning up failed forge instance pool manager", "forge_instance_id", forgeInstance.ID, "error", deleteErr) + } + r.failedEntities[forgeInstance.ID] = failedEntity{entityType: params.ForgeEntityTypeInstance, id: forgeInstance.ID} + r.backoff.RecordFailure(forgeInstance.ID) + return + } + delete(r.failedEntities, forgeInstance.ID) + r.backoff.RecordSuccess(forgeInstance.ID) +} diff --git a/runner/forge_instances_test.go b/runner/forge_instances_test.go new file mode 100644 index 000000000..63300367b --- /dev/null +++ b/runner/forge_instances_test.go @@ -0,0 +1,406 @@ +// Copyright 2026 Cloudbase Solutions SRL +// +// 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 runner + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + runnerErrors "github.com/cloudbase/garm-provider-common/errors" + "github.com/cloudbase/garm/database" + dbCommon "github.com/cloudbase/garm/database/common" + garmTesting "github.com/cloudbase/garm/internal/testing" //nolint:typecheck + "github.com/cloudbase/garm/params" + "github.com/cloudbase/garm/runner/common" + runnerCommonMocks "github.com/cloudbase/garm/runner/common/mocks" + runnerMocks "github.com/cloudbase/garm/runner/mocks" +) + +type ForgeInstanceTestFixtures struct { + AdminContext context.Context + Store dbCommon.Store + StoreForgeInstances map[string]params.ForgeInstance + Providers map[string]common.Provider + CreateForgeInstanceParams params.CreateForgeInstanceParams + CreatePoolParams params.CreatePoolParams + UpdateEntityParams params.UpdateEntityParams + UpdatePoolParams params.UpdatePoolParams + ErrMock error + ProviderMock *runnerCommonMocks.Provider + PoolMgrMock *runnerCommonMocks.PoolManager + PoolMgrCtrlMock *runnerMocks.PoolManagerController +} + +type ForgeInstanceTestSuite struct { + suite.Suite + Fixtures *ForgeInstanceTestFixtures + Runner *Runner + giteaEndpoint params.ForgeEndpoint + giteaCreds params.ForgeCredentials + giteaCreds2 params.ForgeCredentials +} + +func (s *ForgeInstanceTestSuite) SetupTest() { + dbCfg := garmTesting.GetTestSqliteDBConfig(s.T()) + db, err := database.NewDatabase(context.Background(), dbCfg) + if err != nil { + s.FailNow(fmt.Sprintf("failed to create db connection: %s", err)) + } + + adminCtx := garmTesting.ImpersonateAdminContext(context.Background(), db, s.T()) + s.giteaEndpoint = garmTesting.CreateDefaultGiteaEndpoint(adminCtx, db, s.T()) + s.giteaCreds = garmTesting.CreateTestGiteaCredentials(adminCtx, "gitea-creds", db, s.T(), s.giteaEndpoint) + s.giteaCreds2 = garmTesting.CreateTestGiteaCredentials(adminCtx, "gitea-creds-2", db, s.T(), s.giteaEndpoint) + + forgeInstances := map[string]params.ForgeInstance{} + fi, err := db.CreateForgeInstance( + adminCtx, + s.giteaEndpoint.Name, + s.giteaCreds, + "test-webhook-secret", + params.PoolBalancerTypeRoundRobin, + false, + ) + if err != nil { + s.FailNow(fmt.Sprintf("failed to create forge instance: %v", err)) + } + forgeInstances[s.giteaEndpoint.Name] = fi + + var maxRunners uint = 40 + var minIdleRunners uint = 20 + providerMock := runnerCommonMocks.NewProvider(s.T()) + fixtures := &ForgeInstanceTestFixtures{ + AdminContext: adminCtx, + Store: db, + StoreForgeInstances: forgeInstances, + Providers: map[string]common.Provider{ + "test-provider": providerMock, + }, + CreateForgeInstanceParams: params.CreateForgeInstanceParams{ + EndpointName: s.giteaEndpoint.Name, + CredentialsName: s.giteaCreds.Name, + WebhookSecret: "new-webhook-secret", + ForgeType: params.GiteaEndpointType, + PoolBalancerType: params.PoolBalancerTypeRoundRobin, + }, + CreatePoolParams: params.CreatePoolParams{ + ProviderName: "test-provider", + MaxRunners: 4, + MinIdleRunners: 2, + Image: "test", + Flavor: "test", + OSType: "linux", + OSArch: "arm64", + Tags: []string{"arm64-linux-runner"}, + RunnerBootstrapTimeout: 0, + }, + UpdateEntityParams: params.UpdateEntityParams{ + CredentialsName: s.giteaCreds2.Name, + WebhookSecret: "updated-webhook-secret", + }, + UpdatePoolParams: params.UpdatePoolParams{ + MaxRunners: &maxRunners, + MinIdleRunners: &minIdleRunners, + Image: "test-images-updated", + Flavor: "test-flavor-updated", + }, + ErrMock: fmt.Errorf("mock error"), + ProviderMock: providerMock, + PoolMgrMock: runnerCommonMocks.NewPoolManager(s.T()), + PoolMgrCtrlMock: runnerMocks.NewPoolManagerController(s.T()), + } + s.Fixtures = fixtures + + runner := &Runner{ + providers: fixtures.Providers, + ctx: fixtures.AdminContext, + store: fixtures.Store, + poolManagerCtrl: fixtures.PoolMgrCtrlMock, + } + s.Runner = runner +} + +func (s *ForgeInstanceTestSuite) createSecondEndpoint() (params.ForgeEndpoint, params.ForgeCredentials) { + ep, err := s.Fixtures.Store.CreateGiteaEndpoint(s.Fixtures.AdminContext, params.CreateGiteaEndpointParams{ + Name: "second-gitea", + APIBaseURL: "https://gitea2.example.com/api/v1", + BaseURL: "https://gitea2.example.com", + }) + s.Require().Nil(err) + creds := garmTesting.CreateTestGiteaCredentials(s.Fixtures.AdminContext, "creds-ep2", s.Fixtures.Store, s.T(), ep) + return ep, creds +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstance() { + s.Fixtures.PoolMgrMock.On("Start").Return(nil) + s.Fixtures.PoolMgrCtrlMock.On("CreateForgeInstancePoolManager", s.Fixtures.AdminContext, mock.AnythingOfType("params.ForgeInstance"), s.Fixtures.Providers, s.Fixtures.Store).Return(s.Fixtures.PoolMgrMock, nil) + + ep2, creds2 := s.createSecondEndpoint() + createParams := params.CreateForgeInstanceParams{ + EndpointName: ep2.Name, + CredentialsName: creds2.Name, + WebhookSecret: "new-secret", + ForgeType: params.GiteaEndpointType, + PoolBalancerType: params.PoolBalancerTypeRoundRobin, + } + + fi, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, createParams) + + s.Require().Nil(err) + s.Require().Equal(ep2.Name, fi.Endpoint.Name) + s.Require().Equal(creds2.Name, fi.Credentials.Name) + s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) + s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceErrUnauthorized() { + _, err := s.Runner.CreateForgeInstance(context.Background(), s.Fixtures.CreateForgeInstanceParams) + + s.Require().Equal(runnerErrors.ErrUnauthorized, err) +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceEmptyParams() { + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, params.CreateForgeInstanceParams{}) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "validating params") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceMissingCredentials() { + createParams := s.Fixtures.CreateForgeInstanceParams + createParams.CredentialsName = notExistingCredentialsName + + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, createParams) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "not defined") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceAlreadyExists() { + s.Fixtures.PoolMgrCtrlMock.On("CreateForgeInstancePoolManager", s.Fixtures.AdminContext, mock.AnythingOfType("params.ForgeInstance"), s.Fixtures.Providers, s.Fixtures.Store).Return(s.Fixtures.PoolMgrMock, nil).Maybe() + s.Fixtures.PoolMgrMock.On("Start").Return(nil).Maybe() + + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, s.Fixtures.CreateForgeInstanceParams) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "already exists") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceGithubRejected() { + ghEndpoint := garmTesting.CreateDefaultGithubEndpoint(s.Fixtures.AdminContext, s.Fixtures.Store, s.T()) + ghCreds := garmTesting.CreateTestGithubCredentials(s.Fixtures.AdminContext, "gh-creds", s.Fixtures.Store, s.T(), ghEndpoint) + + createParams := params.CreateForgeInstanceParams{ + EndpointName: ghEndpoint.Name, + CredentialsName: ghCreds.Name, + WebhookSecret: "secret", + ForgeType: params.GithubEndpointType, + PoolBalancerType: params.PoolBalancerTypeRoundRobin, + } + + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, createParams) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "does not support instance-level pools") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstancePoolMgrFailed() { + s.Fixtures.PoolMgrCtrlMock.On("CreateForgeInstancePoolManager", s.Fixtures.AdminContext, mock.AnythingOfType("params.ForgeInstance"), s.Fixtures.Providers, s.Fixtures.Store).Return(s.Fixtures.PoolMgrMock, s.Fixtures.ErrMock) + + ep2, creds := s.createSecondEndpoint() + createParams := params.CreateForgeInstanceParams{ + EndpointName: ep2.Name, + CredentialsName: creds.Name, + WebhookSecret: "secret", + ForgeType: params.GiteaEndpointType, + PoolBalancerType: params.PoolBalancerTypeRoundRobin, + } + + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, createParams) + + s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "error creating forge instance pool manager") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstanceStartPoolMgrFailed() { + s.Fixtures.PoolMgrMock.On("Start").Return(s.Fixtures.ErrMock) + s.Fixtures.PoolMgrCtrlMock.On("CreateForgeInstancePoolManager", s.Fixtures.AdminContext, mock.AnythingOfType("params.ForgeInstance"), s.Fixtures.Providers, s.Fixtures.Store).Return(s.Fixtures.PoolMgrMock, nil) + s.Fixtures.PoolMgrCtrlMock.On("DeleteForgeInstancePoolManager", mock.AnythingOfType("params.ForgeInstance")).Return(nil) + + ep2, creds := s.createSecondEndpoint() + createParams := params.CreateForgeInstanceParams{ + EndpointName: ep2.Name, + CredentialsName: creds.Name, + WebhookSecret: "secret", + ForgeType: params.GiteaEndpointType, + PoolBalancerType: params.PoolBalancerTypeRoundRobin, + } + + _, err := s.Runner.CreateForgeInstance(s.Fixtures.AdminContext, createParams) + + s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) + s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "error starting forge instance pool manager") +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstances() { + instances, err := s.Runner.ListForgeInstances(s.Fixtures.AdminContext, params.ForgeInstanceFilter{}) + + s.Require().Nil(err) + s.Require().Len(instances, 1) + s.Require().Equal(s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name].ID, instances[0].ID) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstanceByID() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + result, err := s.Runner.GetForgeInstanceByID(s.Fixtures.AdminContext, fi.ID) + + s.Require().Nil(err) + s.Require().Equal(fi.ID, result.ID) +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstance() { + s.Fixtures.PoolMgrCtrlMock.On("DeleteForgeInstancePoolManager", mock.AnythingOfType("params.ForgeInstance")).Return(nil) + + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + err := s.Runner.DeleteForgeInstance(s.Fixtures.AdminContext, fi.ID, false) + + s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) + s.Require().Nil(err) + + _, err = s.Fixtures.Store.GetForgeInstanceByID(s.Fixtures.AdminContext, fi.ID) + s.Require().Contains(err.Error(), "not found") +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstancePoolDefinedFailed() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + entity, err := fi.GetEntity() + s.Require().Nil(err) + + pool, err := s.Fixtures.Store.CreateEntityPool(s.Fixtures.AdminContext, entity, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + err = s.Runner.DeleteForgeInstance(s.Fixtures.AdminContext, fi.ID, false) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), pool.ID) +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstancePoolMgrFailed() { + s.Fixtures.PoolMgrCtrlMock.On("DeleteForgeInstancePoolManager", mock.AnythingOfType("params.ForgeInstance")).Return(s.Fixtures.ErrMock) + + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + err := s.Runner.DeleteForgeInstance(s.Fixtures.AdminContext, fi.ID, false) + + s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) + s.Require().Contains(err.Error(), "error deleting forge instance pool manager") +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstance() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + param := s.Fixtures.UpdateEntityParams + param.PoolBalancerType = params.PoolBalancerTypePack + + result, err := s.Runner.UpdateForgeInstance(s.Fixtures.AdminContext, fi.ID, param) + + s.Require().Nil(err) + s.Require().Equal(s.giteaCreds2.Name, result.Credentials.Name) + s.Require().Equal("updated-webhook-secret", result.WebhookSecret) + s.Require().Equal(params.PoolBalancerTypePack, result.PoolBalancerType) +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstanceInvalidBalancerType() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + param := params.UpdateEntityParams{ + PoolBalancerType: "invalid-balancer", + } + + _, err := s.Runner.UpdateForgeInstance(s.Fixtures.AdminContext, fi.ID, param) + + s.Require().NotNil(err) + s.Require().Contains(err.Error(), "invalid pool balancer type") +} + +func (s *ForgeInstanceTestSuite) TestCreateForgeInstancePool() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + pool, err := s.Runner.CreateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, s.Fixtures.CreatePoolParams) + + s.Require().Nil(err) + s.Require().Equal(fi.ID, pool.ForgeInstanceID) + + result, err := s.Fixtures.Store.GetForgeInstanceByID(s.Fixtures.AdminContext, fi.ID) + s.Require().Nil(err) + s.Require().Len(result.Pools, 1) + s.Require().Equal(pool.ID, result.Pools[0].ID) +} + +func (s *ForgeInstanceTestSuite) TestGetForgeInstancePoolByID() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + pool, err := s.Runner.CreateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + result, err := s.Runner.GetForgeInstancePoolByID(s.Fixtures.AdminContext, fi.ID, pool.ID) + + s.Require().Nil(err) + s.Require().Equal(pool.ID, result.ID) +} + +func (s *ForgeInstanceTestSuite) TestDeleteForgeInstancePool() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + pool, err := s.Runner.CreateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + err = s.Runner.DeleteForgeInstancePool(s.Fixtures.AdminContext, fi.ID, pool.ID) + + s.Require().Nil(err) + pools, err := s.Runner.ListForgeInstancePools(s.Fixtures.AdminContext, fi.ID) + s.Require().Nil(err) + s.Require().Len(pools, 0) +} + +func (s *ForgeInstanceTestSuite) TestUpdateForgeInstancePool() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + pool, err := s.Runner.CreateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + result, err := s.Runner.UpdateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, pool.ID, s.Fixtures.UpdatePoolParams) + + s.Require().Nil(err) + s.Require().Equal(*s.Fixtures.UpdatePoolParams.MaxRunners, result.MaxRunners) + s.Require().Equal(*s.Fixtures.UpdatePoolParams.MinIdleRunners, result.MinIdleRunners) + s.Require().Equal(s.Fixtures.UpdatePoolParams.Image, result.Image) +} + +func (s *ForgeInstanceTestSuite) TestListForgeInstancePools() { + fi := s.Fixtures.StoreForgeInstances[s.giteaEndpoint.Name] + _, err := s.Runner.CreateForgeInstancePool(s.Fixtures.AdminContext, fi.ID, s.Fixtures.CreatePoolParams) + s.Require().Nil(err) + + pools, err := s.Runner.ListForgeInstancePools(s.Fixtures.AdminContext, fi.ID) + + s.Require().Nil(err) + s.Require().Len(pools, 1) +} + +func TestForgeInstanceTestSuite(t *testing.T) { + t.Parallel() + suite.Run(t, new(ForgeInstanceTestSuite)) +} diff --git a/runner/interfaces.go b/runner/interfaces.go index 9a8181dcc..9d16b2485 100644 --- a/runner/interfaces.go +++ b/runner/interfaces.go @@ -43,11 +43,19 @@ type EnterprisePoolManager interface { GetEnterprisePoolManagers() (map[string]common.PoolManager, error) } +type ForgeInstancePoolManager interface { + CreateForgeInstancePoolManager(ctx context.Context, forgeInstance params.ForgeInstance, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) + GetForgeInstancePoolManager(forgeInstance params.ForgeInstance) (common.PoolManager, error) + DeleteForgeInstancePoolManager(forgeInstance params.ForgeInstance) error + GetForgeInstancePoolManagers() (map[string]common.PoolManager, error) +} + //go:generate go run github.com/vektra/mockery/v2@latest type PoolManagerController interface { RepoPoolManager OrgPoolManager EnterprisePoolManager + ForgeInstancePoolManager } type AgentStoreOps interface { diff --git a/runner/metadata.go b/runner/metadata.go index 36177ce23..7fb686350 100644 --- a/runner/metadata.go +++ b/runner/metadata.go @@ -99,6 +99,8 @@ func (r *Runner) getServiceNameForEntity(entity params.ForgeEntity) (string, err return fmt.Sprintf("actions.runner.%s", entity.Owner), nil case params.ForgeEntityTypeRepository: return fmt.Sprintf("actions.runner.%s.%s", entity.Owner, entity.Name), nil + case params.ForgeEntityTypeInstance: + return fmt.Sprintf("actions.runner.%s", entity.Credentials.Endpoint.Name), nil default: return "", errors.New("unknown entity type") } diff --git a/runner/mocks/PoolManagerController.go b/runner/mocks/PoolManagerController.go index b17196ece..579457b03 100644 --- a/runner/mocks/PoolManagerController.go +++ b/runner/mocks/PoolManagerController.go @@ -88,6 +88,67 @@ func (_c *PoolManagerController_CreateEnterprisePoolManager_Call) RunAndReturn(r return _c } +// CreateForgeInstancePoolManager provides a mock function with given fields: ctx, forgeInstance, providers, store +func (_m *PoolManagerController) CreateForgeInstancePoolManager(ctx context.Context, forgeInstance params.ForgeInstance, providers map[string]common.Provider, store databasecommon.Store) (common.PoolManager, error) { + ret := _m.Called(ctx, forgeInstance, providers, store) + + if len(ret) == 0 { + panic("no return value specified for CreateForgeInstancePoolManager") + } + + var r0 common.PoolManager + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, params.ForgeInstance, map[string]common.Provider, databasecommon.Store) (common.PoolManager, error)); ok { + return rf(ctx, forgeInstance, providers, store) + } + if rf, ok := ret.Get(0).(func(context.Context, params.ForgeInstance, map[string]common.Provider, databasecommon.Store) common.PoolManager); ok { + r0 = rf(ctx, forgeInstance, providers, store) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.PoolManager) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, params.ForgeInstance, map[string]common.Provider, databasecommon.Store) error); ok { + r1 = rf(ctx, forgeInstance, providers, store) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PoolManagerController_CreateForgeInstancePoolManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateForgeInstancePoolManager' +type PoolManagerController_CreateForgeInstancePoolManager_Call struct { + *mock.Call +} + +// CreateForgeInstancePoolManager is a helper method to define mock.On call +// - ctx context.Context +// - forgeInstance params.ForgeInstance +// - providers map[string]common.Provider +// - store databasecommon.Store +func (_e *PoolManagerController_Expecter) CreateForgeInstancePoolManager(ctx interface{}, forgeInstance interface{}, providers interface{}, store interface{}) *PoolManagerController_CreateForgeInstancePoolManager_Call { + return &PoolManagerController_CreateForgeInstancePoolManager_Call{Call: _e.mock.On("CreateForgeInstancePoolManager", ctx, forgeInstance, providers, store)} +} + +func (_c *PoolManagerController_CreateForgeInstancePoolManager_Call) Run(run func(ctx context.Context, forgeInstance params.ForgeInstance, providers map[string]common.Provider, store databasecommon.Store)) *PoolManagerController_CreateForgeInstancePoolManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(params.ForgeInstance), args[2].(map[string]common.Provider), args[3].(databasecommon.Store)) + }) + return _c +} + +func (_c *PoolManagerController_CreateForgeInstancePoolManager_Call) Return(_a0 common.PoolManager, _a1 error) *PoolManagerController_CreateForgeInstancePoolManager_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *PoolManagerController_CreateForgeInstancePoolManager_Call) RunAndReturn(run func(context.Context, params.ForgeInstance, map[string]common.Provider, databasecommon.Store) (common.PoolManager, error)) *PoolManagerController_CreateForgeInstancePoolManager_Call { + _c.Call.Return(run) + return _c +} + // CreateOrgPoolManager provides a mock function with given fields: ctx, org, providers, store func (_m *PoolManagerController) CreateOrgPoolManager(ctx context.Context, org params.Organization, providers map[string]common.Provider, store databasecommon.Store) (common.PoolManager, error) { ret := _m.Called(ctx, org, providers, store) @@ -256,6 +317,52 @@ func (_c *PoolManagerController_DeleteEnterprisePoolManager_Call) RunAndReturn(r return _c } +// DeleteForgeInstancePoolManager provides a mock function with given fields: forgeInstance +func (_m *PoolManagerController) DeleteForgeInstancePoolManager(forgeInstance params.ForgeInstance) error { + ret := _m.Called(forgeInstance) + + if len(ret) == 0 { + panic("no return value specified for DeleteForgeInstancePoolManager") + } + + var r0 error + if rf, ok := ret.Get(0).(func(params.ForgeInstance) error); ok { + r0 = rf(forgeInstance) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// PoolManagerController_DeleteForgeInstancePoolManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteForgeInstancePoolManager' +type PoolManagerController_DeleteForgeInstancePoolManager_Call struct { + *mock.Call +} + +// DeleteForgeInstancePoolManager is a helper method to define mock.On call +// - forgeInstance params.ForgeInstance +func (_e *PoolManagerController_Expecter) DeleteForgeInstancePoolManager(forgeInstance interface{}) *PoolManagerController_DeleteForgeInstancePoolManager_Call { + return &PoolManagerController_DeleteForgeInstancePoolManager_Call{Call: _e.mock.On("DeleteForgeInstancePoolManager", forgeInstance)} +} + +func (_c *PoolManagerController_DeleteForgeInstancePoolManager_Call) Run(run func(forgeInstance params.ForgeInstance)) *PoolManagerController_DeleteForgeInstancePoolManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(params.ForgeInstance)) + }) + return _c +} + +func (_c *PoolManagerController_DeleteForgeInstancePoolManager_Call) Return(_a0 error) *PoolManagerController_DeleteForgeInstancePoolManager_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *PoolManagerController_DeleteForgeInstancePoolManager_Call) RunAndReturn(run func(params.ForgeInstance) error) *PoolManagerController_DeleteForgeInstancePoolManager_Call { + _c.Call.Return(run) + return _c +} + // DeleteOrgPoolManager provides a mock function with given fields: org func (_m *PoolManagerController) DeleteOrgPoolManager(org params.Organization) error { ret := _m.Called(org) @@ -463,6 +570,121 @@ func (_c *PoolManagerController_GetEnterprisePoolManagers_Call) RunAndReturn(run return _c } +// GetForgeInstancePoolManager provides a mock function with given fields: forgeInstance +func (_m *PoolManagerController) GetForgeInstancePoolManager(forgeInstance params.ForgeInstance) (common.PoolManager, error) { + ret := _m.Called(forgeInstance) + + if len(ret) == 0 { + panic("no return value specified for GetForgeInstancePoolManager") + } + + var r0 common.PoolManager + var r1 error + if rf, ok := ret.Get(0).(func(params.ForgeInstance) (common.PoolManager, error)); ok { + return rf(forgeInstance) + } + if rf, ok := ret.Get(0).(func(params.ForgeInstance) common.PoolManager); ok { + r0 = rf(forgeInstance) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.PoolManager) + } + } + + if rf, ok := ret.Get(1).(func(params.ForgeInstance) error); ok { + r1 = rf(forgeInstance) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PoolManagerController_GetForgeInstancePoolManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForgeInstancePoolManager' +type PoolManagerController_GetForgeInstancePoolManager_Call struct { + *mock.Call +} + +// GetForgeInstancePoolManager is a helper method to define mock.On call +// - forgeInstance params.ForgeInstance +func (_e *PoolManagerController_Expecter) GetForgeInstancePoolManager(forgeInstance interface{}) *PoolManagerController_GetForgeInstancePoolManager_Call { + return &PoolManagerController_GetForgeInstancePoolManager_Call{Call: _e.mock.On("GetForgeInstancePoolManager", forgeInstance)} +} + +func (_c *PoolManagerController_GetForgeInstancePoolManager_Call) Run(run func(forgeInstance params.ForgeInstance)) *PoolManagerController_GetForgeInstancePoolManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(params.ForgeInstance)) + }) + return _c +} + +func (_c *PoolManagerController_GetForgeInstancePoolManager_Call) Return(_a0 common.PoolManager, _a1 error) *PoolManagerController_GetForgeInstancePoolManager_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *PoolManagerController_GetForgeInstancePoolManager_Call) RunAndReturn(run func(params.ForgeInstance) (common.PoolManager, error)) *PoolManagerController_GetForgeInstancePoolManager_Call { + _c.Call.Return(run) + return _c +} + +// GetForgeInstancePoolManagers provides a mock function with no fields +func (_m *PoolManagerController) GetForgeInstancePoolManagers() (map[string]common.PoolManager, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetForgeInstancePoolManagers") + } + + var r0 map[string]common.PoolManager + var r1 error + if rf, ok := ret.Get(0).(func() (map[string]common.PoolManager, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() map[string]common.PoolManager); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]common.PoolManager) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PoolManagerController_GetForgeInstancePoolManagers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForgeInstancePoolManagers' +type PoolManagerController_GetForgeInstancePoolManagers_Call struct { + *mock.Call +} + +// GetForgeInstancePoolManagers is a helper method to define mock.On call +func (_e *PoolManagerController_Expecter) GetForgeInstancePoolManagers() *PoolManagerController_GetForgeInstancePoolManagers_Call { + return &PoolManagerController_GetForgeInstancePoolManagers_Call{Call: _e.mock.On("GetForgeInstancePoolManagers")} +} + +func (_c *PoolManagerController_GetForgeInstancePoolManagers_Call) Run(run func()) *PoolManagerController_GetForgeInstancePoolManagers_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *PoolManagerController_GetForgeInstancePoolManagers_Call) Return(_a0 map[string]common.PoolManager, _a1 error) *PoolManagerController_GetForgeInstancePoolManagers_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *PoolManagerController_GetForgeInstancePoolManagers_Call) RunAndReturn(run func() (map[string]common.PoolManager, error)) *PoolManagerController_GetForgeInstancePoolManagers_Call { + _c.Call.Return(run) + return _c +} + // GetOrgPoolManager provides a mock function with given fields: org func (_m *PoolManagerController) GetOrgPoolManager(org params.Organization) (common.PoolManager, error) { ret := _m.Called(org) diff --git a/runner/pool/pool.go b/runner/pool/pool.go index b575b60e5..a2d5e441f 100644 --- a/runner/pool/pool.go +++ b/runner/pool/pool.go @@ -180,6 +180,8 @@ func (r *basePoolManager) isEntityPool(pool params.Pool) bool { return pool.OrgID != "" && pool.OrgID == r.entity.ID case params.ForgeEntityTypeEnterprise: return pool.EnterpriseID != "" && pool.EnterpriseID == r.entity.ID + case params.ForgeEntityTypeInstance: + return pool.ForgeInstanceID != "" && pool.ForgeInstanceID == r.entity.ID default: return false } @@ -1196,6 +1198,8 @@ func (r *basePoolManager) paramsWorkflowJobToParamsJob(job params.WorkflowJob) ( jobParams.RepoID = &asUUID case params.ForgeEntityTypeOrganization: jobParams.OrgID = &asUUID + case params.ForgeEntityTypeInstance: + jobParams.ForgeInstanceID = &asUUID default: return jobParams, fmt.Errorf("unknown pool type: %s", r.entity.EntityType) } @@ -2314,6 +2318,9 @@ func (r *basePoolManager) ValidateOwner(job params.WorkflowJob) error { if !strings.EqualFold(job.Enterprise.Slug, r.entity.Owner) { return runnerErrors.NewBadRequestError("job not meant for this pool manager") } + case params.ForgeEntityTypeInstance: + // Instance-level (system) hooks accept all jobs from the forge instance. + // There is no owner/slug to validate against. default: return runnerErrors.NewBadRequestError("unknown entity type") } @@ -2332,25 +2339,6 @@ func (r *basePoolManager) GithubRunnerRegistrationToken() (string, error) { return *tk.Token, nil } -func (r *basePoolManager) FetchTools() ([]commonParams.RunnerApplicationDownload, error) { - tools, ghResp, err := r.ghcli.ListEntityRunnerApplicationDownloads(r.ctx) - if err != nil { - if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { - return nil, runnerErrors.NewUnauthorizedError("error fetching tools") - } - return nil, fmt.Errorf("error fetching runner tools: %w", err) - } - - ret := []commonParams.RunnerApplicationDownload{} - for _, tool := range tools { - if tool == nil { - continue - } - ret = append(ret, commonParams.RunnerApplicationDownload(*tool)) - } - return ret, nil -} - func (r *basePoolManager) GetWebhookInfo(ctx context.Context) (params.HookInfo, error) { allHooks, err := r.listHooks(ctx) if err != nil { diff --git a/runner/runner.go b/runner/runner.go index e34c3f0d9..d3cd5a6cd 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -67,12 +67,13 @@ func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store, token } poolManagerCtrl := &poolManagerCtrl{ - config: cfg, - store: db, - token: token, - repositories: map[string]common.PoolManager{}, - organizations: map[string]common.PoolManager{}, - enterprises: map[string]common.PoolManager{}, + config: cfg, + store: db, + token: token, + repositories: map[string]common.PoolManager{}, + organizations: map[string]common.PoolManager{}, + enterprises: map[string]common.PoolManager{}, + forgeInstances: map[string]common.PoolManager{}, } runner := &Runner{ ctx: ctx, @@ -97,9 +98,10 @@ type poolManagerCtrl struct { store dbCommon.Store token auth.InstanceTokenGetter - repositories map[string]common.PoolManager - organizations map[string]common.PoolManager - enterprises map[string]common.PoolManager + repositories map[string]common.PoolManager + organizations map[string]common.PoolManager + enterprises map[string]common.PoolManager + forgeInstances map[string]common.PoolManager } func (p *poolManagerCtrl) CreateRepoPoolManager(ctx context.Context, repo params.Repository, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) { @@ -228,6 +230,48 @@ func (p *poolManagerCtrl) GetEnterprisePoolManagers() (map[string]common.PoolMan return p.enterprises, nil } +func (p *poolManagerCtrl) CreateForgeInstancePoolManager(ctx context.Context, forgeInstance params.ForgeInstance, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) { + p.mux.Lock() + defer p.mux.Unlock() + + entity, err := forgeInstance.GetEntity() + if err != nil { + return nil, fmt.Errorf("error getting entity: %w", err) + } + + poolManager, err := pool.NewEntityPoolManager(ctx, entity, p.token, providers, store) + if err != nil { + return nil, fmt.Errorf("error creating forge instance pool manager: %w", err) + } + p.forgeInstances[forgeInstance.ID] = poolManager + return poolManager, nil +} + +func (p *poolManagerCtrl) GetForgeInstancePoolManager(forgeInstance params.ForgeInstance) (common.PoolManager, error) { + if fiPoolMgr, ok := p.forgeInstances[forgeInstance.ID]; ok { + return fiPoolMgr, nil + } + return nil, fmt.Errorf("forge instance %s pool manager not loaded: %w", forgeInstance.ID, runnerErrors.ErrNotFound) +} + +func (p *poolManagerCtrl) DeleteForgeInstancePoolManager(forgeInstance params.ForgeInstance) error { + p.mux.Lock() + defer p.mux.Unlock() + + poolMgr, ok := p.forgeInstances[forgeInstance.ID] + if ok { + if err := poolMgr.Stop(); err != nil { + return fmt.Errorf("error stopping forge instance pool manager: %w", err) + } + delete(p.forgeInstances, forgeInstance.ID) + } + return nil +} + +func (p *poolManagerCtrl) GetForgeInstancePoolManagers() (map[string]common.PoolManager, error) { + return p.forgeInstances, nil +} + type Runner struct { mux sync.Mutex @@ -243,10 +287,11 @@ type Runner struct { quit chan struct{} running bool - failedEntities map[string]failedEntity - reposLoaded bool - orgsLoaded bool - enterprisesLoaded bool + failedEntities map[string]failedEntity + reposLoaded bool + orgsLoaded bool + enterprisesLoaded bool + forgeInstancesLoaded bool } // UpdateController will update the controller settings. @@ -398,6 +443,16 @@ func (r *Runner) loadReposOrgsAndEnterprises() { for _, enterprise := range enterprises { r.createAndStartEnterprisePoolManager(enterprise) } + + forgeInstances, err := r.store.ListForgeInstances(r.ctx, params.ForgeInstanceFilter{}) + if err != nil { + slog.ErrorContext(r.ctx, "fetching forge instances", "error", err) + } else { + r.forgeInstancesLoaded = true + } + for _, fi := range forgeInstances { + r.createAndStartForgeInstancePoolManager(fi) + } } func (r *Runner) Start() error { @@ -553,6 +608,22 @@ func (r *Runner) retryFailedPoolManagers() { } } + if !r.forgeInstancesLoaded { + forgeInstances, err := r.store.ListForgeInstances(r.ctx, params.ForgeInstanceFilter{}) + if err != nil { + slog.ErrorContext(r.ctx, "retrying forge instance list", "error", err) + } else { + slog.InfoContext(r.ctx, "forge instances loaded successfully after retry") + r.forgeInstancesLoaded = true + for _, fi := range forgeInstances { + if _, err := r.poolManagerCtrl.GetForgeInstancePoolManager(fi); err == nil { + continue + } + r.createAndStartForgeInstancePoolManager(fi) + } + } + } + // Retry individual failed entities. for id, fe := range r.failedEntities { if !r.backoff.ShouldRetry(id) { @@ -623,6 +694,25 @@ func (r *Runner) retryFailedEntity(fe failedEntity) { return } r.createAndStartEnterprisePoolManager(enterprise) + case params.ForgeEntityTypeInstance: + fi, err := r.store.GetForgeInstanceByID(r.ctx, fe.id) + if err != nil { + if errors.Is(err, runnerErrors.ErrNotFound) { + slog.InfoContext(r.ctx, "forge instance deleted, removing from retry set", "forge_instance_id", fe.id) + delete(r.failedEntities, fe.id) + r.backoff.RecordSuccess(fe.id) + return + } + slog.ErrorContext(r.ctx, "fetching forge instance for retry", "forge_instance_id", fe.id, "error", err) + r.backoff.RecordFailure(fe.id) + return + } + if err := r.poolManagerCtrl.DeleteForgeInstancePoolManager(fi); err != nil { + slog.ErrorContext(r.ctx, "cleaning up stale forge instance pool manager before retry", "forge_instance_id", fe.id, "error", err) + r.backoff.RecordFailure(fe.id) + return + } + r.createAndStartForgeInstancePoolManager(fi) } } @@ -651,6 +741,11 @@ func (r *Runner) Stop() error { return fmt.Errorf("error fetching enterprise pool managers: %w", err) } + forgeInstances, err := r.poolManagerCtrl.GetForgeInstancePoolManagers() + if err != nil { + return fmt.Errorf("error fetching forge instance pool managers: %w", err) + } + g, _ := errgroup.WithContext(r.ctx) for _, repo := range repos { @@ -686,6 +781,17 @@ func (r *Runner) Stop() error { }) } + for _, fi := range forgeInstances { + poolMgr := fi + g.Go(func() error { + err := poolMgr.Stop() + if err != nil { + return fmt.Errorf("failed to stop forge instance pool manager: %w", err) + } + return poolMgr.Wait() + }) + } + if err := r.waitForErrorGroupOrTimeout(g); err != nil { return fmt.Errorf("failed to stop pool managers: %w", err) } @@ -866,17 +972,22 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, forgeType "enterprise", util.SanitizeLogEntry(job.Enterprise.Slug), "endpoint", endpoint.Name) poolManager, err = r.findEnterprisePoolManager(job.Enterprise.Slug, endpoint.Name) + case SystemHook: + slog.DebugContext( + r.ctx, "got hook for forge instance", + "endpoint", endpoint.Name) + poolManager, err = r.findForgeInstancePoolManager(endpoint.Name) default: return runnerErrors.NewBadRequestError("cannot handle hook target type %s", hookTargetType) } - slog.DebugContext(r.ctx, "found pool manager", "pool_manager", poolManager.ID()) if err != nil { slog.ErrorContext(r.ctx, "failed to find pool manager", "error", err, "hook_target_type", hookTargetType) // We don't have a repository or organization configured that // can handle this workflow job. return fmt.Errorf("error fetching poolManager: %w", err) } + slog.DebugContext(r.ctx, "found pool manager", "pool_manager", poolManager.ID()) // We found a pool. Validate the webhook job. If a secret is configured, // we make sure that the source of this workflow job is valid. @@ -1029,6 +1140,13 @@ func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params if err != nil { return nil, fmt.Errorf("error fetching pool manager for enterprise %s: %w", pool.EnterpriseName, err) } + case pool.ForgeInstanceID != "": + poolMgr, err = r.findForgeInstancePoolManager(pool.Endpoint.Name) + if err != nil { + return nil, fmt.Errorf("error fetching pool manager for forge instance %s: %w", pool.Endpoint.Name, err) + } + default: + return nil, fmt.Errorf("pool %s has no associated entity", pool.ID) } return poolMgr, nil diff --git a/runner/types.go b/runner/types.go index 1fb38bb71..ee41188ac 100644 --- a/runner/types.go +++ b/runner/types.go @@ -22,6 +22,7 @@ const ( RepoHook HookTargetType = "repository" OrganizationHook HookTargetType = "organization" EnterpriseHook HookTargetType = "business" + SystemHook HookTargetType = "system" ) var ( diff --git a/util/github/client.go b/util/github/client.go index 1c1a1a306..544ddd316 100644 --- a/util/github/client.go +++ b/util/github/client.go @@ -63,6 +63,8 @@ func (g *githubClient) ListEntityHooks(ctx context.Context, opts *github.ListOpt ret, response, err = g.repo.ListHooks(ctx, g.entity.Owner, g.entity.Name, opts) case params.ForgeEntityTypeOrganization: ret, response, err = g.org.ListHooks(ctx, g.entity.Owner, opts) + case params.ForgeEntityTypeInstance: + ret, response, err = g.listGiteaInstanceHooks(ctx, opts) default: return nil, nil, fmt.Errorf("invalid entity type: %s", g.entity.EntityType) } @@ -91,6 +93,8 @@ func (g *githubClient) GetEntityHook(ctx context.Context, id int64) (ret *github ret, response, err = g.repo.GetHook(ctx, g.entity.Owner, g.entity.Name, id) case params.ForgeEntityTypeOrganization: ret, response, err = g.org.GetHook(ctx, g.entity.Owner, id) + case params.ForgeEntityTypeInstance: + ret, err = g.getGiteaInstanceHook(ctx, id) default: return nil, errors.New("invalid entity type") } @@ -158,6 +162,8 @@ func (g *githubClient) DeleteEntityHook(ctx context.Context, id int64) (ret *git ret, err = g.repo.DeleteHook(ctx, g.entity.Owner, g.entity.Name, id) case params.ForgeEntityTypeOrganization: ret, err = g.org.DeleteHook(ctx, g.entity.Owner, id) + case params.ForgeEntityTypeInstance: + ret, err = g.deleteGiteaInstanceHook(ctx, id) default: return nil, errors.New("invalid entity type") } @@ -185,6 +191,8 @@ func (g *githubClient) PingEntityHook(ctx context.Context, id int64) (ret *githu ret, err = g.repo.PingHook(ctx, g.entity.Owner, g.entity.Name, id) case params.ForgeEntityTypeOrganization: ret, err = g.org.PingHook(ctx, g.entity.Owner, id) + case params.ForgeEntityTypeInstance: + return nil, fmt.Errorf("ping hook is not supported for instance-level entities") default: return nil, errors.New("invalid entity type") } @@ -220,6 +228,8 @@ func (g *githubClient) ListEntityRunners(ctx context.Context, opts *github.ListR ret, response, err = g.ListOrganizationRunners(ctx, g.entity.Owner, opts) case params.ForgeEntityTypeEnterprise: ret, response, err = g.enterprise.ListRunners(ctx, g.entity.Owner, opts) + case params.ForgeEntityTypeInstance: + ret, response, err = g.listGiteaInstanceRunners(ctx, opts) default: return nil, nil, errors.New("invalid entity type") } @@ -254,6 +264,8 @@ func (g *githubClient) ListEntityRunnerApplicationDownloads(ctx context.Context) ret, response, err = g.ListOrganizationRunnerApplicationDownloads(ctx, g.entity.Owner) case params.ForgeEntityTypeEnterprise: ret, response, err = g.enterprise.ListRunnerApplicationDownloads(ctx, g.entity.Owner) + case params.ForgeEntityTypeInstance: + return nil, nil, fmt.Errorf("listing runner application downloads is not supported for instance-level entities") default: return nil, nil, errors.New("invalid entity type") } @@ -328,6 +340,8 @@ func (g *githubClient) RemoveEntityRunner(ctx context.Context, runnerID int64) e response, err = g.RemoveOrganizationRunner(ctx, g.entity.Owner, runnerID) case params.ForgeEntityTypeEnterprise: response, err = g.enterprise.RemoveRunner(ctx, g.entity.Owner, runnerID) + case params.ForgeEntityTypeInstance: + response, err = g.removeGiteaInstanceRunner(ctx, runnerID) default: return errors.New("invalid entity type") } @@ -367,6 +381,8 @@ func (g *githubClient) CreateEntityRegistrationToken(ctx context.Context) (*gith ret, response, err = g.CreateOrganizationRegistrationToken(ctx, g.entity.Owner) case params.ForgeEntityTypeEnterprise: ret, response, err = g.enterprise.CreateRegistrationToken(ctx, g.entity.Owner) + case params.ForgeEntityTypeInstance: + ret, response, err = g.createGiteaInstanceRegistrationToken(ctx) default: return nil, nil, errors.New("invalid entity type") } diff --git a/util/github/gitea.go b/util/github/gitea.go index 44bb467ee..6563cfada 100644 --- a/util/github/gitea.go +++ b/util/github/gitea.go @@ -91,6 +91,135 @@ func (g *githubClient) createGiteaOrgHook(ctx context.Context, owner string, hoo return hook, nil } +func (g *githubClient) createGiteaInstanceHook(ctx context.Context, hook *github.Hook) (ret *github.Hook, err error) { + u := "admin/hooks" + createOpts := &createGiteaHookOptions{ + Type: "gitea", + Events: hook.Events, + Active: hook.GetActive(), + BranchFilter: "*", + Config: map[string]string{ + "content_type": hook.GetConfig().GetContentType(), + "url": hook.GetConfig().GetURL(), + "http_method": "post", + "secret": hook.GetConfig().GetSecret(), + "is_system_webhook": "true", + }, + } + + req, err := g.cli.NewRequest(http.MethodPost, u, createOpts) + if err != nil { + return nil, fmt.Errorf("failed to construct request: %w", err) + } + + hook = new(github.Hook) + _, err = g.cli.Do(ctx, req, hook) + if err != nil { + return nil, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return hook, nil +} + +func (g *githubClient) listGiteaInstanceHooks(ctx context.Context, opts *github.ListOptions) ([]*github.Hook, *github.Response, error) { + u := "admin/hooks" + if opts != nil { + u = fmt.Sprintf("%s?page=%d&limit=%d", u, opts.Page, opts.PerPage) + } + + req, err := g.cli.NewRequest(http.MethodGet, u, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to construct request: %w", err) + } + + var hooks []*github.Hook + resp, err := g.cli.Do(ctx, req, &hooks) + if err != nil { + return nil, resp, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return hooks, resp, nil +} + +func (g *githubClient) getGiteaInstanceHook(ctx context.Context, id int64) (*github.Hook, error) { + u := fmt.Sprintf("admin/hooks/%d", id) + + req, err := g.cli.NewRequest(http.MethodGet, u, nil) + if err != nil { + return nil, fmt.Errorf("failed to construct request: %w", err) + } + + hook := new(github.Hook) + _, err = g.cli.Do(ctx, req, hook) + if err != nil { + return nil, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return hook, nil +} + +func (g *githubClient) deleteGiteaInstanceHook(ctx context.Context, id int64) (*github.Response, error) { + u := fmt.Sprintf("admin/hooks/%d", id) + + req, err := g.cli.NewRequest(http.MethodDelete, u, nil) + if err != nil { + return nil, fmt.Errorf("failed to construct request: %w", err) + } + + resp, err := g.cli.Do(ctx, req, nil) + if err != nil { + return resp, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return resp, nil +} + +func (g *githubClient) createGiteaInstanceRegistrationToken(ctx context.Context) (*github.RegistrationToken, *github.Response, error) { + u := "admin/actions/runners/registration-token" + + req, err := g.cli.NewRequest(http.MethodPost, u, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to construct request: %w", err) + } + + token := new(github.RegistrationToken) + resp, err := g.cli.Do(ctx, req, token) + if err != nil { + return nil, resp, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return token, resp, nil +} + +func (g *githubClient) listGiteaInstanceRunners(ctx context.Context, opts *github.ListRunnersOptions) (*github.Runners, *github.Response, error) { + u := "admin/actions/runners" + if opts != nil { + u = fmt.Sprintf("%s?page=%d&limit=%d", u, opts.Page, opts.PerPage) + } + + req, err := g.cli.NewRequest(http.MethodGet, u, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to construct request: %w", err) + } + + runners := new(github.Runners) + resp, err := g.cli.Do(ctx, req, runners) + if err != nil { + return nil, resp, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return runners, resp, nil +} + +func (g *githubClient) removeGiteaInstanceRunner(ctx context.Context, runnerID int64) (*github.Response, error) { + u := fmt.Sprintf("admin/actions/runners/%d", runnerID) + + req, err := g.cli.NewRequest(http.MethodDelete, u, nil) + if err != nil { + return nil, fmt.Errorf("failed to construct request: %w", err) + } + + resp, err := g.cli.Do(ctx, req, nil) + if err != nil { + return resp, fmt.Errorf("request failed for %s: %w", req.URL.String(), err) + } + return resp, nil +} + func (g *githubClient) createGiteaEntityHook(ctx context.Context, hook *github.Hook) (ret *github.Hook, err error) { metrics.GithubOperationCount.WithLabelValues( "CreateHook", // label: operation @@ -109,6 +238,8 @@ func (g *githubClient) createGiteaEntityHook(ctx context.Context, hook *github.H ret, err = g.createGiteaRepoHook(ctx, g.entity.Owner, g.entity.Name, hook) case params.ForgeEntityTypeOrganization: ret, err = g.createGiteaOrgHook(ctx, g.entity.Owner, hook) + case params.ForgeEntityTypeInstance: + ret, err = g.createGiteaInstanceHook(ctx, hook) default: return nil, errors.New("invalid entity type") } diff --git a/vendor/github.com/dlclark/regexp2/v2/syntax/charclass.go b/vendor/github.com/dlclark/regexp2/v2/syntax/charclass.go index 9dc4b630e..b00fc9ad8 100644 --- a/vendor/github.com/dlclark/regexp2/v2/syntax/charclass.go +++ b/vendor/github.com/dlclark/regexp2/v2/syntax/charclass.go @@ -688,11 +688,6 @@ func canonicalUnicodeCatName(catName string) (string, bool) { return "", false } -func isValidUnicodeCat(catName string) bool { - _, ok := canonicalUnicodeCatName(catName) - return ok -} - func (c *CharSet) addCategory(categoryName string, negate, caseInsensitive bool) { var ok bool categoryName, ok = canonicalUnicodeCatName(categoryName) @@ -719,28 +714,19 @@ func (c *CharSet) addCaseEquivalences() { if c.anything { return } - for i := 0; i < len(c.ranges); i++ { + rangeCount := len(c.ranges) + for i := 0; i < rangeCount; i++ { r := c.ranges[i] - if r.First == r.Last { - equiv := tryFindCaseEquivalences(r.First) + // For a single range that's in the set, adds any additional ranges + // necessary to ensure that lowercase equivalents are also included. + for i := r.First; i <= r.Last; i++ { + equiv := tryFindCaseEquivalences(i) for _, eq := range equiv { - c.addChar(eq) + c.ranges = append(c.ranges, SingleRange{First: eq, Last: eq}) } - } else { - c.addCaseEquivalenceRange(r.First, r.Last) - } - } -} - -// For a single range that's in the set, adds any additional ranges -// necessary to ensure that lowercase equivalents are also included. -func (c *CharSet) addCaseEquivalenceRange(chMin, chMax rune) { - for i := chMin; i <= chMax; i++ { - equiv := tryFindCaseEquivalences(i) - for _, eq := range equiv { - c.addChar(eq) } } + c.canonicalize() } // Performs a fast lookup which determines if a character is involved in case conversion, as well as @@ -1141,7 +1127,7 @@ func (c *CharSet) addLowercaseRange(chMin, chMax rune) { } if chMinT < chMin || chMaxT > chMax { - c.addRange(chMinT, chMaxT) + c.ranges = append(c.ranges, SingleRange{First: chMinT, Last: chMaxT}) } } } diff --git a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md index d86830a0f..c793ad250 100644 --- a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 22 | 267 | +| 22 | 271 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 127 | | +| @fredbi | 131 | | | @casualjim | 91 | | | @keramix | 9 | | | @youyuanwu | 8 | | diff --git a/vendor/github.com/go-openapi/analysis/README.md b/vendor/github.com/go-openapi/analysis/README.md index e4e308659..2a9046297 100644 --- a/vendor/github.com/go-openapi/analysis/README.md +++ b/vendor/github.com/go-openapi/analysis/README.md @@ -18,12 +18,9 @@ A foundational library to analyze, diff, flatten, merge, and fix OAI specificati * **2025-12-19** : new community chat on discord * a new discord community channel is available to be notified of changes and support users - * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31** You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url] -Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url] - ## Status API is stable. @@ -79,9 +76,9 @@ on top of which it has been built. ## Other documentation * [All-time contributors](./CONTRIBUTORS.md) -* [Contributing guidelines](.github/CONTRIBUTING.md) -* [Maintainers documentation](docs/MAINTAINERS.md) -* [Code style](docs/STYLE.md) +* [Contributing guidelines][contributing-doc-site] +* [Maintainers documentation][maintainers-doc-site] +* [Code style][style-doc-site] ## Cutting a new release @@ -112,9 +109,6 @@ Maintainers can cut a new release by either: [godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/analysis [godoc-url]: http://pkg.go.dev/github.com/go-openapi/analysis -[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png -[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM -[slack-url]: https://goswagger.slack.com/archives/C04R30YMU [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue [discord-url]: https://discord.gg/FfnFYaC3k5 @@ -126,3 +120,7 @@ Maintainers can cut a new release by either: [goversion-url]: https://github.com/go-openapi/analysis/blob/master/go.mod [top-badge]: https://img.shields.io/github/languages/top/go-openapi/analysis [commits-badge]: https://img.shields.io/github/commits-since/go-openapi/analysis/latest + +[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html +[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html +[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html diff --git a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml index dc7c96053..9d2733176 100644 --- a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml +++ b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml @@ -4,7 +4,10 @@ linters: disable: - depguard - funlen + - goconst - godox + - gomodguard + - gomodguard_v2 - exhaustruct - nlreturn - nonamedreturns diff --git a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md index 9990f4a35..0cdcfb4ce 100644 --- a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 13 | 111 | +| 13 | 115 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 63 | | +| @fredbi | 67 | | | @casualjim | 33 | | | @magodo | 3 | | | @youyuanwu | 3 | | diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md index 24fbe1bf6..a90e79935 100644 --- a/vendor/github.com/go-openapi/jsonpointer/README.md +++ b/vendor/github.com/go-openapi/jsonpointer/README.md @@ -16,6 +16,11 @@ An implementation of JSON Pointer for golang, which supports go `struct`. ## Announcements +* **2026-06-29** : reinsourced external dependency to swag (v0.24.0) + * module `github.com/go-openapi/swag/jsonname` is source directly here, so we no longer have any external dependency + * `jsonname` was never really used by any other package, so it makes sense to deprecate it away from the `swag` family + and retrofit its functionality here. `jsonpointer` no longer get external dependencies, besides test dependencies. + * **2026-04-15** : added support for trailing "-" for arrays (v0.23.0) * this brings full support of [RFC6901][RFC6901] * this is supported for types relying on the reflection-based implemented @@ -30,12 +35,13 @@ An implementation of JSON Pointer for golang, which supports go `struct`. * the default name provider in use is not fully aligned with go JSON stdlib * exposed an option (or global setting) to change the provider that resolves a struct into json keys * the default behavior is not altered - * a new alternate name provider is added (imported from `go-openapi/swag/jsonname`), aligned with JSON stdlib behavior ## Status API is stable and feature-complete. +The project continues to receive regular updates, bug fixes and hygiene maintenance (CI, linting, etc). + ## Import this library in your project ```cmd diff --git a/vendor/github.com/go-openapi/jsonpointer/errors.go b/vendor/github.com/go-openapi/jsonpointer/errors.go index 8813474d4..2ae6e3cfb 100644 --- a/vendor/github.com/go-openapi/jsonpointer/errors.go +++ b/vendor/github.com/go-openapi/jsonpointer/errors.go @@ -21,14 +21,15 @@ const ( // ErrUnsupportedValueType indicates that a value of the wrong type is being set. ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values" - // ErrDashToken indicates use of the RFC 6901 "-" reference token - // in a context where it cannot be resolved. + // ErrDashToken indicates use of the RFC 6901 "-" reference token in a context where it cannot be + // resolved. // - // Per RFC 6901 §4 the "-" token refers to the (nonexistent) element - // after the last array element. It may only be used as the terminal - // token of a [Pointer.Set] against a slice, where it means "append". - // Any other use (get, offset, intermediate traversal, non-slice target) - // is an error condition that wraps this sentinel. + // Per RFC 6901 §4 the "-" token refers to the (nonexistent) element after the last array element. + // It may only be used as the terminal token of a [Pointer.Set] against a slice, where it means + // "append". + // + // Any other use (get, offset, intermediate traversal, non-slice target) is an error condition that + // wraps this sentinel. ErrDashToken pointerError = `the "-" array token cannot be resolved here` //nolint:gosec // G101 false positive: this is a JSON Pointer reference token, not a credential. ) diff --git a/vendor/github.com/go-openapi/jsonpointer/ifaces.go b/vendor/github.com/go-openapi/jsonpointer/ifaces.go index 1e56ac044..31359c48f 100644 --- a/vendor/github.com/go-openapi/jsonpointer/ifaces.go +++ b/vendor/github.com/go-openapi/jsonpointer/ifaces.go @@ -5,39 +5,42 @@ package jsonpointer import "reflect" -// JSONPointable is an interface for structs to implement, -// when they need to customize the json pointer process or want to avoid the use of reflection. +// JSONPointable is an interface for structs to implement, when they need to customize the json +// pointer process or want to avoid the use of reflection. type JSONPointable interface { // JSONLookup returns a value pointed at this (unescaped) key. JSONLookup(key string) (any, error) } -// JSONSetable is an interface for structs to implement, -// when they need to customize the json pointer process or want to avoid the use of reflection. +// JSONSetable is an interface for structs to implement, when they need to customize the json +// pointer process or want to avoid the use of reflection. // // # Handling of the RFC 6901 "-" token // -// When a type implementing JSONSetable is the terminal parent of a [Pointer.Set] -// call, the library passes the raw reference token to JSONSet without -// interpretation. In particular, the RFC 6901 "-" token (which conventionally -// means "append" for arrays, per RFC 6902) is forwarded verbatim as the key -// argument. Implementations that model an array-like container are expected -// to give "-" the append semantics; implementations that do not should return -// an error wrapping [ErrDashToken] (or [ErrPointer]) for clarity. +// When a type implementing JSONSetable is the terminal parent of a [Pointer.Set] call, the library +// passes the raw reference token to JSONSet without interpretation. // -// Implementations are responsible for any in-place mutation: the library does -// not attempt to rebind the result of JSONSet into a parent container. +// In particular, the RFC 6901 "-" token (which conventionally means "append" for arrays, per RFC +// 6902) is forwarded verbatim as the key argument. +// +// Implementations that model an array-like container are expected to give "-" the append semantics; +// implementations that do not should return an error wrapping [ErrDashToken] (or [ErrPointer]) for +// clarity. +// +// Implementations are responsible for any in-place mutation: the library does not attempt to rebind +// the result of JSONSet into a parent container. type JSONSetable interface { // JSONSet sets the value pointed at the (unescaped) key. // - // The key may be the RFC 6901 "-" token when the pointer targets a - // slice-like member; see the interface documentation for details. + // The key may be the RFC 6901 "-" token when the pointer targets a slice-like member; see the + // interface documentation for details. JSONSet(key string, value any) error } // NameProvider knows how to resolve go struct fields into json names. // -// The default provider is brought by [github.com/go-openapi/swag/jsonname.DefaultJSONNameProvider]. +// The default provider is brought by +// [github.com/go-openapi/jsonpointer/jsonname.DefaultJSONNameProvider]. type NameProvider interface { // GetGoName gets the go name for a json property name GetGoName(subject any, name string) (string, bool) diff --git a/vendor/github.com/go-openapi/jsonpointer/jsonname/doc.go b/vendor/github.com/go-openapi/jsonpointer/jsonname/doc.go new file mode 100644 index 000000000..79232eaca --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/jsonname/doc.go @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Package jsonname is a provider of json property names from go properties. +package jsonname diff --git a/vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go b/vendor/github.com/go-openapi/jsonpointer/jsonname/go_name_provider.go similarity index 88% rename from vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go rename to vendor/github.com/go-openapi/jsonpointer/jsonname/go_name_provider.go index adc442687..5eec18fbf 100644 --- a/vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go +++ b/vendor/github.com/go-openapi/jsonpointer/jsonname/go_name_provider.go @@ -11,11 +11,11 @@ import ( var _ providerIface = (*GoNameProvider)(nil) -// GoNameProvider resolves json property names to go struct field names following -// the same rules as the standard library's [encoding/json] package. +// GoNameProvider resolves json property names to go struct field names following the same rules as +// the standard library's [encoding/json] package. // -// Contrary to [NameProvider], it considers exported fields without a json tag, -// and promotes fields from anonymous embedded struct types. +// Contrary to [NameProvider], it considers exported fields without a json tag, and promotes fields +// from anonymous embedded struct types. // // Rules (aligned with encoding/json): // @@ -104,9 +104,9 @@ func (n *GoNameProvider) nameIndexFor(tpe reflect.Type) nameIndex { return names } -// fieldEntry captures a candidate field discovered while walking a struct -// along with the indirection path from the root type (used to resolve conflicts -// by depth in the same way encoding/json does). +// fieldEntry captures a candidate field discovered while walking a struct along with the +// indirection path from the root type (used to resolve conflicts by depth in the same way +// encoding/json does). type fieldEntry struct { goName string jsonName string @@ -129,6 +129,8 @@ func buildGoNameIndex(tpe reflect.Type) nameIndex { // collectGoFields walks tpe breadth-first along anonymous struct fields, // reproducing the field selection performed by encoding/json.typeFields. +// +//nolint:gocognit // everything is inlined to help the compiler determine what escapes and what doesn't func collectGoFields(tpe reflect.Type) []fieldEntry { if tpe.Kind() != reflect.Struct { return nil @@ -157,12 +159,12 @@ func collectGoFields(tpe reflect.Type) []fieldEntry { } for _, q := range current { - for i := 0; i < q.typ.NumField(); i++ { + for i := range q.typ.NumField() { sf := q.typ.Field(i) if sf.Anonymous { ft := sf.Type - if ft.Kind() == reflect.Ptr { + if ft.Kind() == reflect.Pointer { ft = ft.Elem() } if !sf.IsExported() && ft.Kind() != reflect.Struct { @@ -180,7 +182,7 @@ func collectGoFields(tpe reflect.Type) []fieldEntry { tagged := jsonName != "" ft := sf.Type - if ft.Kind() == reflect.Ptr { + if ft.Kind() == reflect.Pointer { ft = ft.Elem() } @@ -221,9 +223,9 @@ func collectGoFields(tpe reflect.Type) []fieldEntry { return dominantFields(candidates) } -// dominantFields applies the Go encoding/json conflict resolution rules: -// at each JSON name, the shallowest field wins; at equal depth, a uniquely -// tagged candidate wins; otherwise all candidates for that name are dropped. +// dominantFields applies the Go encoding/json conflict resolution rules: at each JSON name, the +// shallowest field wins; at equal depth, a uniquely tagged candidate wins; otherwise all candidates +// for that name are dropped. func dominantFields(candidates []fieldEntry) []fieldEntry { byName := make(map[string][]fieldEntry, len(candidates)) for _, c := range candidates { @@ -272,14 +274,14 @@ func dominantFields(candidates []fieldEntry) []fieldEntry { return out } -// parseJSONTag returns the name component of a json struct tag and whether -// it carried any non-name option (kept for future-proofing, e.g. "omitempty"). +// parseJSONTag returns the name component of a json struct tag and whether it carried any non-name +// option (kept for future-proofing, e.g. "omitempty"). func parseJSONTag(tag string) (string, string) { if tag == "" { return "", "" } - if idx := strings.IndexByte(tag, ','); idx >= 0 { - return tag[:idx], tag[idx+1:] + if before, after, ok := strings.Cut(tag, ","); ok { + return before, after } return tag, "" diff --git a/vendor/github.com/go-openapi/swag/jsonname/ifaces.go b/vendor/github.com/go-openapi/jsonpointer/jsonname/ifaces.go similarity index 77% rename from vendor/github.com/go-openapi/swag/jsonname/ifaces.go rename to vendor/github.com/go-openapi/jsonpointer/jsonname/ifaces.go index 812ace563..64871f0d2 100644 --- a/vendor/github.com/go-openapi/swag/jsonname/ifaces.go +++ b/vendor/github.com/go-openapi/jsonpointer/jsonname/ifaces.go @@ -5,9 +5,11 @@ package jsonname import "reflect" -// providerIface is an unexported compile-time contract that every name provider -// in this package is expected to satisfy. -// It mirrors the interface declared by the main consumer of this module: [github.com/go-openapi/jsonpointer.NameProvider]. +// providerIface is an unexported compile-time contract that every name provider in this package is +// expected to satisfy. +// +// It mirrors the interface declared by the main consumer of this module: +// [github.com/go-openapi/jsonpointer.NameProvider]. type providerIface interface { GetGoName(subject any, name string) (string, bool) GetGoNameForType(tpe reflect.Type, name string) (string, bool) diff --git a/vendor/github.com/go-openapi/swag/jsonname/name_provider.go b/vendor/github.com/go-openapi/jsonpointer/jsonname/name_provider.go similarity index 83% rename from vendor/github.com/go-openapi/swag/jsonname/name_provider.go rename to vendor/github.com/go-openapi/jsonpointer/jsonname/name_provider.go index 9f5da7a01..1bec2406b 100644 --- a/vendor/github.com/go-openapi/swag/jsonname/name_provider.go +++ b/vendor/github.com/go-openapi/jsonpointer/jsonname/name_provider.go @@ -10,12 +10,12 @@ import ( ) // DefaultJSONNameProvider is the default cache for types. -var DefaultJSONNameProvider = NewNameProvider() +var DefaultJSONNameProvider = NewNameProvider() //nolint:gochecknoglobals // default settings, for backward compatible package-level settings var _ providerIface = (*NameProvider)(nil) -// NameProvider represents an object capable of translating from go property names -// to json property names. +// NameProvider represents an object capable of translating from go property names to json property +// names. // // This type is thread-safe. // @@ -30,7 +30,7 @@ type nameIndex struct { goNames map[string]string } -// NewNameProvider creates a new name provider +// NewNameProvider creates a new name provider. func NewNameProvider() *NameProvider { return &NameProvider{ lock: &sync.Mutex{}, @@ -39,7 +39,7 @@ func NewNameProvider() *NameProvider { } func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) { - for i := 0; i < tpe.NumField(); i++ { + for i := range tpe.NumField() { targetDes := tpe.Field(i) if targetDes.PkgPath != "" { // unexported @@ -73,14 +73,14 @@ func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) { } func newNameIndex(tpe reflect.Type) nameIndex { - var idx = make(map[string]string, tpe.NumField()) - var reverseIdx = make(map[string]string, tpe.NumField()) + idx := make(map[string]string, tpe.NumField()) + reverseIdx := make(map[string]string, tpe.NumField()) buildnameIndex(tpe, idx, reverseIdx) return nameIndex{jsonNames: idx, goNames: reverseIdx} } -// GetJSONNames gets all the json property names for a type +// GetJSONNames gets all the json property names for a type. func (n *NameProvider) GetJSONNames(subject any) []string { n.lock.Lock() defer n.lock.Unlock() @@ -97,13 +97,13 @@ func (n *NameProvider) GetJSONNames(subject any) []string { return res } -// GetJSONName gets the json name for a go property name +// GetJSONName gets the json name for a go property name. func (n *NameProvider) GetJSONName(subject any, name string) (string, bool) { tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() return n.GetJSONNameForType(tpe, name) } -// GetJSONNameForType gets the json name for a go property name on a given type +// GetJSONNameForType gets the json name for a go property name on a given type. func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) { n.lock.Lock() defer n.lock.Unlock() @@ -115,13 +115,13 @@ func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string return nme, ok } -// GetGoName gets the go name for a json property name +// GetGoName gets the go name for a json property name. func (n *NameProvider) GetGoName(subject any, name string) (string, bool) { tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() return n.GetGoNameForType(tpe, name) } -// GetGoNameForType gets the go name for a given type for a json property name +// GetGoNameForType gets the go name for a given type for a json property name. func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) { n.lock.Lock() defer n.lock.Unlock() diff --git a/vendor/github.com/go-openapi/jsonpointer/options.go b/vendor/github.com/go-openapi/jsonpointer/options.go index d52caab22..223c1e5ff 100644 --- a/vendor/github.com/go-openapi/jsonpointer/options.go +++ b/vendor/github.com/go-openapi/jsonpointer/options.go @@ -6,7 +6,7 @@ package jsonpointer import ( "sync" - "github.com/go-openapi/swag/jsonname" + "github.com/go-openapi/jsonpointer/jsonname" ) // Option to tune the behavior of a JSON [Pointer]. @@ -25,9 +25,9 @@ var ( // // By default, the default provider is [jsonname.DefaultJSONNameProvider]. // -// It is safe to call concurrently with [Pointer.Get], [Pointer.Set], -// [GetForToken] and [SetForToken]. The typical usage is to call it once -// at initialization time. +// It is safe to call concurrently with [Pointer.Get], [Pointer.Set], [GetForToken] and +// [SetForToken]. +// The typical usage is to call it once at initialization time. // // A nil provider is ignored. func SetDefaultNameProvider(provider NameProvider) { @@ -41,16 +41,15 @@ func SetDefaultNameProvider(provider NameProvider) { defaultOptions.provider = provider } -// UseGoNameProvider sets the [NameProvider] as a package-level default -// to the alternative provider [jsonname.GoNameProvider], that covers a few areas -// not supported by the default name provider. +// UseGoNameProvider sets the [NameProvider] as a package-level default to the alternative provider +// [jsonname.GoNameProvider], that covers a few areas not supported by the default name provider. // // This implementation supports untagged exported fields and embedded types in go struct. // It follows strictly the behavior of the JSON standard library regarding field naming conventions. // -// It is safe to call concurrently with [Pointer.Get], [Pointer.Set], -// [GetForToken] and [SetForToken]. The typical usage is to call it once -// at initialization time. +// It is safe to call concurrently with [Pointer.Get], [Pointer.Set], [GetForToken] and +// [SetForToken]. +// The typical usage is to call it once at initialization time. func UseGoNameProvider() { SetDefaultNameProvider(jsonname.NewGoNameProvider()) } diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go index 2369c1827..05fc863ee 100644 --- a/vendor/github.com/go-openapi/jsonpointer/pointer.go +++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go @@ -34,7 +34,8 @@ const ( // // For struct s resolved by reflection, key mappings honor the conventional struct tag `json`. // -// Fields that do not specify a `json` tag, or specify an empty one, or are tagged as `json:"-"` are ignored. +// Fields that do not specify a `json` tag, or specify an empty one, or are tagged as `json:"-"` are +// ignored. // // # Limitations // @@ -61,23 +62,24 @@ func (p *Pointer) Get(document any, opts ...Option) (any, reflect.Kind, error) { return p.get(document, o.provider) } -// Set uses the pointer to set a value from a data type -// that represent a JSON document. +// Set uses the pointer to set a value from a data type that represent a JSON document. // // # Mutation contract // -// Set mutates the provided document in place whenever Go's type system allows -// it: when document is a map, a pointer, or when the targeted value is reached -// through an addressable ancestor (e.g. a struct field traversed via a pointer, -// a slice element). Callers that rely on this in-place behavior may continue -// to ignore the returned document. +// Set mutates the provided document in place whenever Go's type system allows it: when document is +// a map, a pointer, or when the targeted value is reached through an addressable ancestor (e.g. a +// struct field traversed via a pointer, a slice element). +// +// Callers that rely on this in-place behavior may continue to ignore the returned document. // // The returned document is only load-bearing when Set cannot mutate in place. -// This happens in one specific case: appending to a top-level slice passed by -// value (e.g. document of type []T rather than *[]T) via the RFC 6901 "-" -// terminal token. reflect.Append produces a new slice header that the library -// cannot rebind into the caller's variable; the updated document is returned -// instead. Pass *[]T if you want in-place rebind for that case as well. +// +// This happens in one specific case: appending to a top-level slice passed by value (e.g. document +// of type []T rather than *[]T) via the RFC 6901 "-" terminal token. reflect.Append produces a new +// slice header that the library cannot rebind into the caller's variable; the updated document is +// returned instead. +// +// Pass *[]T if you want in-place rebind for that case as well. // // See [ErrDashToken] for the semantics of the "-" token. func (p *Pointer) Set(document any, value any, opts ...Option) (any, error) { @@ -112,23 +114,23 @@ func (p *Pointer) String() string { return pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator) } -// Offset returns the byte offset, in the raw JSON text of document, of the -// location referenced by this pointer's terminal token. +// Offset returns the byte offset, in the raw JSON text of document, of the location referenced by +// this pointer's terminal token. +// +// Unlike [Pointer.Get] and [Pointer.Set], which operate on a decoded Go value, Offset operates +// directly on the textual JSON source. // -// Unlike [Pointer.Get] and [Pointer.Set], which operate on a decoded Go value, -// Offset operates directly on the textual JSON source. It drives an -// [encoding/json.Decoder] over the string and stops at the terminal token, -// returning the position at which the decoder was about to read that token. +// It drives an [encoding/json.Decoder] over the string and stops at the terminal token, returning +// the position at which the decoder was about to read that token. // -// It is primarily intended for tooling that needs to map a pointer back to a -// region of the original source: reporting line/column for validation or -// parse diagnostics, extracting a sub-document by slicing the raw bytes, or -// highlighting the referenced span in an editor. +// It is primarily intended for tooling that needs to map a pointer back to a region of the original +// source: reporting line/column for validation or parse diagnostics, extracting a sub-document by +// slicing the raw bytes, or highlighting the referenced span in an editor. // // # Offset semantics // -// The meaning of the returned offset depends on whether the terminal token -// addresses an object property or an array element: +// The meaning of the returned offset depends on whether the terminal token addresses an object +// property or an array element: // // - Object property: the offset points to the first byte of the key (its // opening quote character), not to the associated value. For example, @@ -183,16 +185,15 @@ func (p *Pointer) Offset(document string) (int64, error) { return skipJSONSeparator(document, offset), nil } -// skipJSONSeparator advances offset past trailing JSON whitespace and at most -// one value separator (comma) in document, so the result points at the first -// byte of the next JSON token. +// skipJSONSeparator advances offset past trailing JSON whitespace and at most one value separator +// (comma) in document, so the result points at the first byte of the next JSON token. // -// The streaming decoder's InputOffset sits right after the most recently -// consumed token, which between values is the comma (or whitespace) — not -// the following token. Normalizing here keeps Offset's contract uniform: -// for both object keys and array elements, and regardless of position within -// the parent container, the returned offset always points at the first byte -// of the addressed token. +// The streaming decoder's InputOffset sits right after the most recently consumed token, which +// between values is the comma (or whitespace) — not the following token. +// +// Normalizing here keeps Offset's contract uniform: for both object keys and array elements, and +// regardless of position within the parent container, the returned offset always points at the +// first byte of the addressed token. func skipJSONSeparator(document string, offset int64) int64 { n := int64(len(document)) for offset < n && isJSONWhitespace(document[offset]) { @@ -279,14 +280,13 @@ func (p *Pointer) set(node, data any, nameProvider NameProvider) (any, error) { return p.setAt(node, p.referenceTokens, data, nameProvider) } -// setAt recursively walks the token list, setting the data at the terminal -// token and rebinding any new child reference (e.g. a slice header returned -// by an "-" append) into its parent on the way back up. +// setAt recursively walks the token list, setting the data at the terminal token and rebinding any +// new child reference (e.g. a slice header returned by an "-" append) into its parent on the way +// back up. // -// Returning the (possibly new) node at each level is what makes append work -// at any depth without requiring the caller to pass a pointer to the -// containing slice: the new slice header propagates up and each parent -// rebinds it via the appropriate kind-specific setter. +// Returning the (possibly new) node at each level is what makes append work at any depth without +// requiring the caller to pass a pointer to the containing slice: the new slice header propagates +// up and each parent rebinds it via the appropriate kind-specific setter. func (p *Pointer) setAt(node any, tokens []string, data any, nameProvider NameProvider) (any, error) { decodedToken := Unescape(tokens[0]) @@ -309,15 +309,14 @@ func (p *Pointer) setAt(node any, tokens []string, data any, nameProvider NamePr // rebindChild writes newChild back into node at decodedToken. // -// For cases where the child was already mutated in place (pointer aliasing, -// addressable slice elements) the rebind is a safe no-op. For cases where -// the child was returned by value (map entries holding a slice, slices -// reached through a non-addressable ancestor), the rebind propagates the -// new value into the parent. +// For cases where the child was already mutated in place (pointer aliasing, addressable slice +// elements) the rebind is a safe no-op. +// +// For cases where the child was returned by value (map entries holding a slice, slices reached +// through a non-addressable ancestor), the rebind propagates the new value into the parent. // -// Parents implementing [JSONPointable] are left alone: they took ownership -// of the child via JSONLookup and did not opt into a JSONSet-based rebind -// on intermediate tokens. +// Parents implementing [JSONPointable] are left alone: they took ownership of the child via +// JSONLookup and did not opt into a JSONSet-based rebind on intermediate tokens. func rebindChild(node any, decodedToken string, newChild any, nameProvider NameProvider) (any, error) { if _, ok := node.(JSONPointable); ok { return node, nil @@ -362,9 +361,9 @@ func rebindChild(node any, decodedToken string, newChild any, nameProvider NameP } } -// assignReflectValue assigns src into dst, unwrapping a pointer when dst -// expects the pointee type. This tolerates the pointer-wrapping performed -// by [typeFromValue] for addressable fields. +// assignReflectValue assigns src into dst, unwrapping a pointer when dst expects the pointee type. +// +// This tolerates the pointer-wrapping performed by [typeFromValue] for addressable fields. func assignReflectValue(dst reflect.Value, src any) { nv := reflect.ValueOf(src) if !nv.IsValid() { @@ -474,8 +473,8 @@ func GetForToken(document any, decodedToken string, opts ...Option) (any, reflec // SetForToken sets a value for a json pointer token 1 level deep. // -// See [Pointer.Set] for the mutation contract, in particular the handling of -// the RFC 6901 "-" token on slices. +// See [Pointer.Set] for the mutation contract, in particular the handling of the RFC 6901 "-" token +// on slices. func SetForToken(document any, decodedToken string, value any, opts ...Option) (any, error) { o := optionsWithDefaults(opts) @@ -586,10 +585,10 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider NameProvide case reflect.Slice: if decodedToken == dashToken { - // RFC 6901 §4 / RFC 6902 append semantics: terminal "-" appends - // the value to the slice. We rebind in place when the slice is - // reachable via an addressable ancestor; otherwise we return the - // new slice header for the parent (or the public Set) to rebind. + // RFC 6901 §4 / RFC 6902 append semantics: terminal "-" appends the value to the slice. + // + // We rebind in place when the slice is reachable via an addressable ancestor; otherwise we + // return the new slice header for the parent (or the public Set) to rebind. value := reflect.ValueOf(data) elemType := rValue.Type().Elem() if !value.Type().AssignableTo(elemType) { @@ -650,8 +649,8 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) { return offset, nil } - // Consume the associated value. Scalars are fully read by a single - // Token() call; composite values must be drained. + // Consume the associated value. + // Scalars are fully read by a single Token() call; composite values must be drained. tk, err = dec.Token() if err != nil { return 0, err @@ -736,10 +735,7 @@ func drainSingle(dec *json.Decoder) error { return nil } -// JSON pointer encoding: -// ~0 => ~ -// ~1 => / -// ... and vice versa +// JSON pointer encoding: ~0 => ~ ~1 => / ... and vice versa. const ( encRefTok0 = `~0` diff --git a/vendor/github.com/go-openapi/strfmt/.golangci.yml b/vendor/github.com/go-openapi/strfmt/.golangci.yml index 3c4cd489a..8a3b3bff7 100644 --- a/vendor/github.com/go-openapi/strfmt/.golangci.yml +++ b/vendor/github.com/go-openapi/strfmt/.golangci.yml @@ -2,6 +2,7 @@ version: "2" linters: default: all disable: + - goconst # has become too noisy. Disabled - depguard - funlen - gomoddirectives diff --git a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md index b6d62d76e..4aa4fcb54 100644 --- a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 40 | 234 | +| 40 | 239 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 88 | | -| @fredbi | 66 | | +| @fredbi | 71 | | | @youyuanwu | 13 | | | @jlambatl | 9 | | | @GlenDC | 5 | | diff --git a/vendor/github.com/go-openapi/strfmt/default.go b/vendor/github.com/go-openapi/strfmt/default.go index 87d3856ad..725cc0e1a 100644 --- a/vendor/github.com/go-openapi/strfmt/default.go +++ b/vendor/github.com/go-openapi/strfmt/default.go @@ -1978,6 +1978,14 @@ func (r *Password) DeepCopy() *Password { } func isRequestURI(rawurl string) bool { + // url.ParseRequestURI assumes the input contains no "#fragment" + // (RFC 3986 §3.5). A URI with a fragment and an empty path, such as + // "https://host#@frag", is therefore misread as userinfo and rejected + // as "invalid userinfo". Strip the fragment first so the absolute + // request URI validates, matching url.Parse's RFC 3986 handling. + if i := strings.IndexByte(rawurl, '#'); i >= 0 { + rawurl = rawurl[:i] + } _, err := url.ParseRequestURI(rawurl) return err == nil } diff --git a/vendor/github.com/go-openapi/swag/.gitignore b/vendor/github.com/go-openapi/swag/.gitignore index 1680db44c..3ceb596fa 100644 --- a/vendor/github.com/go-openapi/swag/.gitignore +++ b/vendor/github.com/go-openapi/swag/.gitignore @@ -4,3 +4,4 @@ Godeps .idea *.out .mcp.json +.worktrees diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml index 126264a6b..099c0a78c 100644 --- a/vendor/github.com/go-openapi/swag/.golangci.yml +++ b/vendor/github.com/go-openapi/swag/.golangci.yml @@ -14,7 +14,10 @@ linters: - gocognit - godot - godox + - goconst - gomoddirectives + - gomodguard + - gomodguard_v2 - gosmopolitan - inamedparam - intrange diff --git a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md index ef1a73529..b619a01df 100644 --- a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 24 | 246 | +| 24 | 247 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 116 | | +| @fredbi | 117 | | | @casualjim | 98 | | | @alexandear | 4 | | | @orisano | 3 | | diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md index ddbd8735c..c6c2d21e9 100644 --- a/vendor/github.com/go-openapi/swag/README.md +++ b/vendor/github.com/go-openapi/swag/README.md @@ -67,11 +67,12 @@ Child modules will continue to evolve and some new ones may be added in the futu | `cmdutils` | utilities to work with CLIs || | `conv` | type conversion utilities | convert between values and pointers for any types
convert from string to builtin types (wraps `strconv`)
require `./typeutils` (test dependency)
| | `fileutils` | file utilities | | -| `jsonname` | JSON utilities | infer JSON names from `go` properties
| +| `jsonname` | JSON utilities (deprecated) | infer JSON names from `go` properties
use `github.com/go-openapi/jsonpointer/jsonname` instead | | `jsonutils` | JSON utilities | fast json concatenation
read and write JSON from and to dynamic `go` data structures
~require `github.com/mailru/easyjson`~
| | `loading` | file loading | load from file or http
require `./yamlutils`
| | `mangling` | safe name generation | name mangling for `go`
| | `netutils` | networking utilities | host, port from address
| +| `pools` | utilities to work with sync.Pools | | | `stringutils` | `string` utilities | search in slice (with case-insensitive)
split/join query parameters as arrays
| | `typeutils` | `go` types utilities | check the zero value for any type
safe check for a nil value
| | `yamlutils` | YAML utilities | converting YAML to JSON
loading YAML into a dynamic YAML document
maintaining the original order of keys in YAML objects
require `./jsonutils`
~require `github.com/mailru/easyjson`~
require `go.yaml.in/yaml/v3`
| diff --git a/vendor/github.com/go-openapi/swag/go.work b/vendor/github.com/go-openapi/swag/go.work index 8537cb2a7..f1dddc436 100644 --- a/vendor/github.com/go-openapi/swag/go.work +++ b/vendor/github.com/go-openapi/swag/go.work @@ -12,6 +12,7 @@ use ( ./loading ./mangling ./netutils + ./pools ./stringutils ./typeutils ./yamlutils diff --git a/vendor/github.com/go-openapi/swag/jsonname/doc.go b/vendor/github.com/go-openapi/swag/jsonname/doc.go index 79232eaca..8dda4ca79 100644 --- a/vendor/github.com/go-openapi/swag/jsonname/doc.go +++ b/vendor/github.com/go-openapi/swag/jsonname/doc.go @@ -2,4 +2,39 @@ // SPDX-License-Identifier: Apache-2.0 // Package jsonname is a provider of json property names from go properties. +// +// The entire package has moved closer to the main consumer of this functionality: jsonpointer. +// +// Deprecated: use [github.com/go-openapi/jsonpointer/jsonname] instead. package jsonname + +import "github.com/go-openapi/jsonpointer/jsonname" + +// GoNameProvider resolves json property names to go struct field names following +// the same rules as the standard library's [encoding/json] package. +// +// Deprecated: use [jsonname.GoNameProvideer] instead. +type GoNameProvider = jsonname.GoNameProvider + +// NewGoNameProvider creates a new [GoNameProvider]. +func NewGoNameProvider() *GoNameProvider { + return jsonname.NewGoNameProvider() +} + +// DefaultJSONNameProvider is the default cache for types. +// +// Deprecated: use [jsonname.DefaultJSONNameProvider] instead. +var DefaultJSONNameProvider = jsonname.DefaultJSONNameProvider + +// NameProvider represents an object capable of translating from go property names +// to json property names. +// +// Deprecated: use [jsonname.GoNameProvideer] instead. +type NameProvider = jsonname.NameProvider + +// NewNameProvider creates a new name provider +// +// Deprecated: use [jsonname.GoNameProvideer] instead. +func NewNameProvider() *NameProvider { + return jsonname.NewNameProvider() +} diff --git a/vendor/github.com/go-openapi/swag/jsonname_iface.go b/vendor/github.com/go-openapi/swag/jsonname_iface.go index 303a007f6..443560caa 100644 --- a/vendor/github.com/go-openapi/swag/jsonname_iface.go +++ b/vendor/github.com/go-openapi/swag/jsonname_iface.go @@ -4,21 +4,21 @@ package swag import ( - "github.com/go-openapi/swag/jsonname" + "github.com/go-openapi/jsonpointer/jsonname" ) // DefaultJSONNameProvider is the default cache for types // -// Deprecated: use [jsonname.DefaultJSONNameProvider] instead. +// Deprecated: use [github.com/go-openapi/jsonpointer/jsonname.DefaultJSONNameProvider] instead. var DefaultJSONNameProvider = jsonname.DefaultJSONNameProvider // NameProvider represents an object capable of translating from go property names // to json property names. // -// Deprecated: use [jsonname.NameProvider] instead. +// Deprecated: use [github.com/go-openapi/jsonpointer/jsonname.NameProvider] instead. type NameProvider = jsonname.NameProvider // NewNameProvider creates a new name provider // -// Deprecated: use [jsonname.NewNameProvider] instead. +// Deprecated: use [github.com/go-openapi/jsonpointer/jsonname.NewNameProvider] instead. func NewNameProvider() *NameProvider { return jsonname.NewNameProvider() } diff --git a/vendor/github.com/go-openapi/swag/loading_iface.go b/vendor/github.com/go-openapi/swag/loading_iface.go index 27ec3fb8c..78dadfccd 100644 --- a/vendor/github.com/go-openapi/swag/loading_iface.go +++ b/vendor/github.com/go-openapi/swag/loading_iface.go @@ -80,11 +80,13 @@ func YAMLData(path string) (any, error) { // loadingOptionsWithDefaults bridges deprecated default settings that use package-level variables, // with the recommended use of loading.Option. func loadingOptionsWithDefaults(opts []loading.Option) []loading.Option { - o := []loading.Option{ + const defaultOptions = 3 + o := make([]loading.Option, 0, defaultOptions+len(opts)) + o = append(o, []loading.Option{ loading.WithTimeout(LoadHTTPTimeout), loading.WithBasicAuth(LoadHTTPBasicAuthUsername, LoadHTTPBasicAuthPassword), loading.WithCustomHeaders(LoadHTTPCustomHeaders), - } + }...) o = append(o, opts...) return o diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go index d8b308459..7902b0e06 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go @@ -286,13 +286,16 @@ func StringWidthWithoutEscSequences(str string) int { return count } -// Trim trims a string to the given length while ignoring escape sequences. For -// ex.: +// Trim trims a string to the given display width (maxLen columns) while +// ignoring escape sequences. Wide East Asian characters count as two columns, +// so the result never exceeds maxLen columns. For ex.: // // Trim("Ghost", 3) == "Gho" // Trim("Ghost", 6) == "Ghost" // Trim("\x1b[33mGhost\x1b[0m", 3) == "\x1b[33mGho\x1b[0m" // Trim("\x1b[33mGhost\x1b[0m", 6) == "\x1b[33mGhost\x1b[0m" +// Trim("生命生命", 3) == "生" +// Trim("生命生命", 4) == "生命" func Trim(str string, maxLen int) string { if maxLen <= 0 { return "" @@ -301,7 +304,7 @@ func Trim(str string, maxLen int) string { var out strings.Builder out.Grow(maxLen) - outLen, esp := 0, EscSeqParser{} + outLen, full, esp := 0, false, EscSeqParser{} for _, sChr := range str { if esp.InSequence() { esp.Consume(sChr) @@ -313,10 +316,17 @@ func Trim(str string, maxLen int) string { out.WriteRune(sChr) continue } - if outLen < maxLen { - outLen++ - out.WriteRune(sChr) - continue + // Count the display width of the rune (wide East Asian characters + // occupy two columns) instead of counting runes, so the result never + // exceeds maxLen columns. Once a rune no longer fits, stop emitting + // visible runes but keep copying any trailing escape sequences. + if !full { + if w := RuneWidth(sChr); outLen+w <= maxLen { + outLen += w + out.WriteRune(sChr) + continue + } + full = true } } return out.String() diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go index 4e4c13e72..10bf35708 100644 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go @@ -122,7 +122,7 @@ func NewOpenMetricsFormat(version string) (Format, error) { // removed. func (f Format) WithEscapingScheme(s model.EscapingScheme) Format { var terms []string - for _, p := range strings.Split(string(f), ";") { + for p := range strings.SplitSeq(string(f), ";") { toks := strings.Split(p, "=") if len(toks) != 2 { trimmed := strings.TrimSpace(p) @@ -194,7 +194,7 @@ func (f Format) FormatType() FormatType { // "escaping" term exists, that will be used. Otherwise, the global default will // be returned. func (f Format) ToEscapingScheme() model.EscapingScheme { - for _, p := range strings.Split(string(f), ";") { + for p := range strings.SplitSeq(string(f), ";") { toks := strings.Split(p, "=") if len(toks) != 2 { continue diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go index 6b8978145..f4074ae9a 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_create.go +++ b/vendor/github.com/prometheus/common/expfmt/text_create.go @@ -42,12 +42,12 @@ const ( var ( bufPool = sync.Pool{ - New: func() interface{} { + New: func() any { return bufio.NewWriter(io.Discard) }, } numBufPool = sync.Pool{ - New: func() interface{} { + New: func() any { b := make([]byte, 0, initialNumBufSize) return &b }, diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go index 00c8841a1..4ce1f40b8 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go @@ -339,6 +339,16 @@ func (p *TextParser) startLabelName() stateFn { return nil // Unexpected end of input. } if p.currentByte == '}' { + if p.currentMF == nil { + // The closing brace was reached before any metric name was read, + // e.g. for the input "{}". There is no metric to attach labels to, + // so this is a malformed exposition. This mirrors the guard in + // startLabelValue. currentMF (not currentMetric) is checked because + // reset only clears currentMF between parses. + p.parseError("invalid metric name") + p.currentLabelPairs = nil + return nil + } p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPairs...) p.currentLabelPairs = nil if p.skipBlankTab(); p.err != nil { diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go index dfeb34be5..29688a13c 100644 --- a/vendor/github.com/prometheus/common/model/labels.go +++ b/vendor/github.com/prometheus/common/model/labels.go @@ -124,7 +124,7 @@ func (ln LabelName) IsValidLegacy() bool { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (ln *LabelName) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go index 9de47b256..6010b26a8 100644 --- a/vendor/github.com/prometheus/common/model/labelset.go +++ b/vendor/github.com/prometheus/common/model/labelset.go @@ -16,6 +16,7 @@ package model import ( "encoding/json" "fmt" + "maps" "sort" ) @@ -107,9 +108,7 @@ func (ls LabelSet) Before(o LabelSet) bool { // Clone returns a copy of the label set. func (ls LabelSet) Clone() LabelSet { lsn := make(LabelSet, len(ls)) - for ln, lv := range ls { - lsn[ln] = lv - } + maps.Copy(lsn, ls) return lsn } @@ -117,13 +116,9 @@ func (ls LabelSet) Clone() LabelSet { func (ls LabelSet) Merge(other LabelSet) LabelSet { result := make(LabelSet, len(ls)) - for k, v := range ls { - result[k] = v - } + maps.Copy(result, ls) - for k, v := range other { - result[k] = v - } + maps.Copy(result, other) return result } diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index 429a0dab1..2fe461511 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -17,6 +17,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "regexp" "sort" "strconv" @@ -258,9 +259,7 @@ func (m Metric) Before(o Metric) bool { // Clone returns a copy of the Metric. func (m Metric) Clone() Metric { clone := make(Metric, len(m)) - for k, v := range m { - clone[k] = v - } + maps.Copy(clone, m) return clone } diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index 1730b0fdc..0854753f4 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -123,44 +123,38 @@ func (t Time) MarshalJSON() ([]byte, error) { // UnmarshalJSON implements the json.Unmarshaler interface. func (t *Time) UnmarshalJSON(b []byte) error { - p := strings.Split(string(b), ".") - switch len(p) { - case 1: - v, err := strconv.ParseInt(p[0], 10, 64) + base, frac, found := strings.Cut(string(b), ".") + if !found { + v, err := strconv.ParseInt(base, 10, 64) if err != nil { return err } *t = Time(v * second) - - case 2: - v, err := strconv.ParseInt(p[0], 10, 64) + } else { + v, err := strconv.ParseInt(base, 10, 64) if err != nil { return err } - v *= second - prec := dotPrecision - len(p[1]) + prec := dotPrecision - len(frac) if prec < 0 { - p[1] = p[1][:dotPrecision] - } else if prec > 0 { - p[1] += strings.Repeat("0", prec) + frac = frac[:dotPrecision] } - - va, err := strconv.ParseInt(p[1], 10, 32) + va, err := strconv.ParseInt(frac, 10, 32) if err != nil { return err } - - // If the value was something like -0.1 the negative is lost in the - // parsing because of the leading zero, this ensures that we capture it. - if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 { - *t = Time(v+va) * -1 - } else { - *t = Time(v + va) + switch prec { + case 1: + va *= 10 + case 2: + va *= 100 } - default: - return fmt.Errorf("invalid time %q", string(b)) + if len(base) > 0 && base[0] == '-' { + va = -va + } + *t = Time(v*second + va) } return nil } @@ -340,12 +334,12 @@ func (d *Duration) UnmarshalText(text []byte) error { } // MarshalYAML implements the yaml.Marshaler interface. -func (d Duration) MarshalYAML() (interface{}, error) { +func (d Duration) MarshalYAML() (any, error) { return d.String(), nil } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (d *Duration) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go index a9995a37e..8dffd9c4a 100644 --- a/vendor/github.com/prometheus/common/model/value.go +++ b/vendor/github.com/prometheus/common/model/value.go @@ -259,13 +259,13 @@ func (s Scalar) String() string { // MarshalJSON implements json.Marshaler. func (s Scalar) MarshalJSON() ([]byte, error) { v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64) - return json.Marshal([...]interface{}{s.Timestamp, v}) + return json.Marshal([...]any{s.Timestamp, v}) } // UnmarshalJSON implements json.Unmarshaler. func (s *Scalar) UnmarshalJSON(b []byte) error { var f string - v := [...]interface{}{&s.Timestamp, &f} + v := [...]any{&s.Timestamp, &f} if err := json.Unmarshal(b, &v); err != nil { return err @@ -291,12 +291,12 @@ func (s *String) String() string { // MarshalJSON implements json.Marshaler. func (s String) MarshalJSON() ([]byte, error) { - return json.Marshal([]interface{}{s.Timestamp, s.Value}) + return json.Marshal([]any{s.Timestamp, s.Value}) } // UnmarshalJSON implements json.Unmarshaler. func (s *String) UnmarshalJSON(b []byte) error { - v := [...]interface{}{&s.Timestamp, &s.Value} + v := [...]any{&s.Timestamp, &s.Value} return json.Unmarshal(b, &v) } diff --git a/vendor/github.com/prometheus/common/model/value_float.go b/vendor/github.com/prometheus/common/model/value_float.go index 6bfc757d1..b7d93615e 100644 --- a/vendor/github.com/prometheus/common/model/value_float.go +++ b/vendor/github.com/prometheus/common/model/value_float.go @@ -79,7 +79,7 @@ func (s SamplePair) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil + return fmt.Appendf(nil, "[%s,%s]", t, v), nil } // UnmarshalJSON implements json.Unmarshaler. diff --git a/vendor/github.com/prometheus/common/model/value_histogram.go b/vendor/github.com/prometheus/common/model/value_histogram.go index 91ce5b7a4..f27856ccc 100644 --- a/vendor/github.com/prometheus/common/model/value_histogram.go +++ b/vendor/github.com/prometheus/common/model/value_histogram.go @@ -67,11 +67,11 @@ func (s HistogramBucket) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s,%s,%s]", b, l, u, c)), nil + return fmt.Appendf(nil, "[%s,%s,%s,%s]", b, l, u, c), nil } func (s *HistogramBucket) UnmarshalJSON(buf []byte) error { - tmp := []interface{}{&s.Boundaries, &s.Lower, &s.Upper, &s.Count} + tmp := []any{&s.Boundaries, &s.Lower, &s.Upper, &s.Count} wantLen := len(tmp) if err := json.Unmarshal(buf, &tmp); err != nil { return err @@ -152,11 +152,11 @@ func (s SampleHistogramPair) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil + return fmt.Appendf(nil, "[%s,%s]", t, v), nil } func (s *SampleHistogramPair) UnmarshalJSON(buf []byte) error { - tmp := []interface{}{&s.Timestamp, &s.Histogram} + tmp := []any{&s.Timestamp, &s.Histogram} wantLen := len(tmp) if err := json.Unmarshal(buf, &tmp); err != nil { return err diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common index cce3ef1d1..a7c5f553e 100644 --- a/vendor/github.com/prometheus/procfs/Makefile.common +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -55,13 +55,13 @@ ifneq ($(shell command -v gotestsum 2> /dev/null),) endif endif -PROMU_VERSION ?= 0.18.0 +PROMU_VERSION ?= 0.20.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v2.10.1 +GOLANGCI_LINT_VERSION ?= v2.11.4 GOLANGCI_FMT_OPTS ?= # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. @@ -90,8 +90,8 @@ ifdef DOCKERFILE_PATH $(error DOCKERFILE_PATH is deprecated. Use DOCKERFILE_VARIANTS ?= $(DOCKERFILE_PATH) in the Makefile) endif -DOCKER_ARCHS ?= amd64 -DOCKERFILE_VARIANTS ?= Dockerfile $(wildcard Dockerfile.*) +DOCKER_ARCHS ?= amd64 arm64 armv7 ppc64le riscv64 s390x +DOCKERFILE_VARIANTS ?= $(wildcard Dockerfile Dockerfile.*) # Function to extract variant from Dockerfile label. # Returns the variant name from io.prometheus.image.variant label, or "default" if not found. @@ -109,24 +109,6 @@ endif # Build variant:dockerfile pairs for shell iteration. DOCKERFILE_VARIANTS_WITH_NAMES := $(foreach df,$(DOCKERFILE_VARIANTS),$(call dockerfile_variant,$(df)):$(df)) -# Shell helper to check whether a dockerfile/arch pair is excluded. -define dockerfile_arch_is_excluded -case " $(DOCKERFILE_ARCH_EXCLUSIONS) " in \ - *" $$dockerfile:$(1) "*) true ;; \ - *) false ;; \ -esac -endef - -# Shell helper to check whether a registry/arch pair is excluded. -# Extracts registry from DOCKER_REPO (e.g., quay.io/prometheus -> quay.io) -define registry_arch_is_excluded -registry=$$(echo "$(DOCKER_REPO)" | cut -d'/' -f1); \ -case " $(DOCKER_REGISTRY_ARCH_EXCLUSIONS) " in \ - *" $$registry:$(1) "*) true ;; \ - *) false ;; \ -esac -endef - BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) @@ -268,10 +250,6 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \ dockerfile=$${variant#*:}; \ variant_name=$${variant%%:*}; \ - if $(call dockerfile_arch_is_excluded,$*); then \ - echo "Skipping $$variant_name variant for linux-$* (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ distroless_arch="$*"; \ if [ "$*" = "armv7" ]; then \ distroless_arch="arm"; \ @@ -306,14 +284,6 @@ $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \ dockerfile=$${variant#*:}; \ variant_name=$${variant%%:*}; \ - if $(call dockerfile_arch_is_excluded,$*); then \ - echo "Skipping push for $$variant_name variant on linux-$* (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$*); then \ - echo "Skipping push for $$variant_name variant on linux-$* to $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \ echo "Pushing $$variant_name variant for linux-$*"; \ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \ @@ -341,14 +311,6 @@ $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \ dockerfile=$${variant#*:}; \ variant_name=$${variant%%:*}; \ - if $(call dockerfile_arch_is_excluded,$*); then \ - echo "Skipping tag for $$variant_name variant on linux-$* (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$*); then \ - echo "Skipping tag for $$variant_name variant on linux-$* for $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \ echo "Tagging $$variant_name variant for linux-$* as latest"; \ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest-$$variant_name"; \ @@ -370,14 +332,6 @@ common-docker-manifest: echo "Creating manifest for $$variant_name variant"; \ refs=""; \ for arch in $(DOCKER_ARCHS); do \ - if $(call dockerfile_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for $$variant_name (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for $$variant_name on $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \ done; \ if [ -z "$$refs" ]; then \ @@ -391,14 +345,6 @@ common-docker-manifest: echo "Creating default variant ($$variant_name) manifest"; \ refs=""; \ for arch in $(DOCKER_ARCHS); do \ - if $(call dockerfile_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for default variant (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for default variant on $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:$(SANITIZED_DOCKER_IMAGE_TAG)"; \ done; \ if [ -z "$$refs" ]; then \ @@ -413,14 +359,6 @@ common-docker-manifest: echo "Creating manifest for $$variant_name variant version tag"; \ refs=""; \ for arch in $(DOCKER_ARCHS); do \ - if $(call dockerfile_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for $$variant_name version tag (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for $$variant_name version tag on $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \ done; \ if [ -z "$$refs" ]; then \ @@ -434,14 +372,6 @@ common-docker-manifest: echo "Creating default variant version tag manifest"; \ refs=""; \ for arch in $(DOCKER_ARCHS); do \ - if $(call dockerfile_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for default variant version tag (excluded by DOCKERFILE_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ - if $(call registry_arch_is_excluded,$$arch); then \ - echo " Skipping $$arch for default variant version tag on $(DOCKER_REPO) (excluded by DOCKER_REGISTRY_ARCH_EXCLUSIONS)"; \ - continue; \ - fi; \ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:v$(DOCKER_MAJOR_VERSION_TAG)"; \ done; \ if [ -z "$$refs" ]; then \ @@ -495,9 +425,3 @@ $(1)_precheck: exit 1; \ fi endef - -govulncheck: install-govulncheck - govulncheck ./... - -install-govulncheck: - command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md index 0718239cf..363524094 100644 --- a/vendor/github.com/prometheus/procfs/README.md +++ b/vendor/github.com/prometheus/procfs/README.md @@ -7,7 +7,7 @@ metrics from the pseudo-filesystems /proc and /sys. backwards-incompatible ways without warnings. Use it at your own risk. [![Go Reference](https://pkg.go.dev/badge/github.com/prometheus/procfs.svg)](https://pkg.go.dev/github.com/prometheus/procfs) -[![CircleCI](https://circleci.com/gh/prometheus/procfs/tree/master.svg?style=svg)](https://circleci.com/gh/prometheus/procfs/tree/master) +[![Build Status](https://github.com/prometheus/procfs/actions/workflows/ci.yml/badge.svg)](https://github.com/prometheus/procfs/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs) ## Usage diff --git a/vendor/github.com/prometheus/procfs/SECURITY.md b/vendor/github.com/prometheus/procfs/SECURITY.md index fed02d85c..5e6f976db 100644 --- a/vendor/github.com/prometheus/procfs/SECURITY.md +++ b/vendor/github.com/prometheus/procfs/SECURITY.md @@ -3,4 +3,4 @@ The Prometheus security policy, including how to report vulnerabilities, can be found here: - +[https://prometheus.io/docs/operating/security/](https://prometheus.io/docs/operating/security/) diff --git a/vendor/github.com/prometheus/procfs/crypto.go b/vendor/github.com/prometheus/procfs/crypto.go index e4a5876ea..d93b712e0 100644 --- a/vendor/github.com/prometheus/procfs/crypto.go +++ b/vendor/github.com/prometheus/procfs/crypto.go @@ -48,11 +48,13 @@ type Crypto struct { Walksize *uint64 } +var cryptoFile = "crypto" + // Crypto parses an crypto-file (/proc/crypto) and returns a slice of // structs containing the relevant info. More information available here: // https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html func (fs FS) Crypto() ([]Crypto, error) { - path := fs.proc.Path("crypto") + path := fs.proc.Path(cryptoFile) b, err := util.ReadFileNoStat(path) if err != nil { return nil, fmt.Errorf("%w: Cannot read file %v: %w", ErrFileRead, b, err) @@ -82,6 +84,10 @@ func parseCrypto(r io.Reader) ([]Crypto, error) { continue } + if len(out) == 0 { + return nil, fmt.Errorf("%w: parsed invalid line before name parsed: %q", ErrFileParse, text) + } + kv := strings.Split(text, ":") if len(kv) != 2 { return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, text) diff --git a/vendor/github.com/prometheus/procfs/mountinfo.go b/vendor/github.com/prometheus/procfs/mountinfo.go index 9414a12f4..8594ae7f1 100644 --- a/vendor/github.com/prometheus/procfs/mountinfo.go +++ b/vendor/github.com/prometheus/procfs/mountinfo.go @@ -17,10 +17,10 @@ import ( "bufio" "bytes" "fmt" + "io" + "os" "strconv" "strings" - - "github.com/prometheus/procfs/internal/util" ) // A MountInfo is a type that describes the details, options @@ -160,9 +160,19 @@ func mountOptionsParser(mountOptions string) map[string]string { return opts } +// readMountInfo reads a full mountinfo file (no 1 MiB cap, unlike util.ReadFileNoStat). +func readMountInfo(path string) ([]byte, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + return io.ReadAll(f) +} + // GetMounts retrieves mountinfo information from `/proc/self/mountinfo`. func GetMounts() ([]*MountInfo, error) { - data, err := util.ReadFileNoStat("/proc/self/mountinfo") + data, err := readMountInfo("/proc/self/mountinfo") if err != nil { return nil, err } @@ -171,7 +181,7 @@ func GetMounts() ([]*MountInfo, error) { // GetProcMounts retrieves mountinfo information from a processes' `/proc//mountinfo`. func GetProcMounts(pid int) ([]*MountInfo, error) { - data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/mountinfo", pid)) + data, err := readMountInfo(fmt.Sprintf("/proc/%d/mountinfo", pid)) if err != nil { return nil, err } @@ -180,7 +190,7 @@ func GetProcMounts(pid int) ([]*MountInfo, error) { // GetMounts retrieves mountinfo information from `/proc/self/mountinfo`. func (fs FS) GetMounts() ([]*MountInfo, error) { - data, err := util.ReadFileNoStat(fs.proc.Path("self/mountinfo")) + data, err := readMountInfo(fs.proc.Path("self/mountinfo")) if err != nil { return nil, err } @@ -189,7 +199,7 @@ func (fs FS) GetMounts() ([]*MountInfo, error) { // GetProcMounts retrieves mountinfo information from a processes' `/proc//mountinfo`. func (fs FS) GetProcMounts(pid int) ([]*MountInfo, error) { - data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%d/mountinfo", pid))) + data, err := readMountInfo(fs.proc.Path(fmt.Sprintf("%d/mountinfo", pid))) if err != nil { return nil, err } diff --git a/vendor/gorm.io/gorm/callbacks.go b/vendor/gorm.io/gorm/callbacks.go index bd97f0404..9f02cd8b9 100644 --- a/vendor/gorm.io/gorm/callbacks.go +++ b/vendor/gorm.io/gorm/callbacks.go @@ -310,7 +310,7 @@ func sortCallbacks(cs []*callback) (fns []func(*DB), err error) { // if after callback sorted, append current callback to last sorted = append(sorted, c.name) } else if curIdx < sortedIdx { - return fmt.Errorf("conflicting callback %s with before %s", c.name, c.after) + return fmt.Errorf("conflicting callback %s with after %s", c.name, c.after) } } else if idx := getRIndex(names, c.after); idx != -1 { // if after callback exists but haven't sorted diff --git a/vendor/gorm.io/gorm/callbacks/callbacks.go b/vendor/gorm.io/gorm/callbacks/callbacks.go index d681aef36..15835af78 100644 --- a/vendor/gorm.io/gorm/callbacks/callbacks.go +++ b/vendor/gorm.io/gorm/callbacks/callbacks.go @@ -1,3 +1,4 @@ +// Package callbacks provides the default callback functions for GORM operations such as create, query, update, and delete. package callbacks import ( diff --git a/vendor/gorm.io/gorm/callbacks/delete.go b/vendor/gorm.io/gorm/callbacks/delete.go index 07ed6feef..2a90a616d 100644 --- a/vendor/gorm.io/gorm/callbacks/delete.go +++ b/vendor/gorm.io/gorm/callbacks/delete.go @@ -171,12 +171,17 @@ func Delete(config *Config) func(db *gorm.DB) { } if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil { + defer func() { + if err := rows.Close(); err != nil { + _ = db.AddError(err) + } + }() + gorm.Scan(rows, db, mode) if db.Statement.Result != nil { db.Statement.Result.RowsAffected = db.RowsAffected } - db.AddError(rows.Close()) } } } diff --git a/vendor/gorm.io/gorm/callbacks/update.go b/vendor/gorm.io/gorm/callbacks/update.go index 8e2782e16..4ad96d555 100644 --- a/vendor/gorm.io/gorm/callbacks/update.go +++ b/vendor/gorm.io/gorm/callbacks/update.go @@ -87,11 +87,16 @@ func Update(config *Config) func(db *gorm.DB) { if !db.DryRun && db.Error == nil { if ok, mode := hasReturning(db, supportReturning); ok { if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil { + defer func() { + if err := rows.Close(); err != nil { + _ = db.AddError(err) + } + }() + dest := db.Statement.Dest db.Statement.Dest = db.Statement.ReflectValue.Addr().Interface() gorm.Scan(rows, db, mode) db.Statement.Dest = dest - db.AddError(rows.Close()) if db.Statement.Result != nil { db.Statement.Result.RowsAffected = db.RowsAffected diff --git a/vendor/gorm.io/gorm/clause/clause.go b/vendor/gorm.io/gorm/clause/clause.go index 1354fc057..c69e1c9e0 100644 --- a/vendor/gorm.io/gorm/clause/clause.go +++ b/vendor/gorm.io/gorm/clause/clause.go @@ -1,3 +1,4 @@ +// Package clause provides the clause interface and common clause implementations for GORM. package clause // Interface clause interface diff --git a/vendor/gorm.io/gorm/clause/expression.go b/vendor/gorm.io/gorm/clause/expression.go index 3140846ef..cbabde20a 100644 --- a/vendor/gorm.io/gorm/clause/expression.go +++ b/vendor/gorm.io/gorm/clause/expression.go @@ -34,25 +34,7 @@ func (expr Expr) Build(builder Builder) { for _, v := range []byte(expr.SQL) { if v == '?' && len(expr.Vars) > idx { if afterParenthesis || expr.WithoutParentheses { - if _, ok := expr.Vars[idx].(driver.Valuer); ok { - builder.AddVar(builder, expr.Vars[idx]) - } else { - switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() { - case reflect.Slice, reflect.Array: - if rv.Len() == 0 { - builder.AddVar(builder, nil) - } else { - for i := 0; i < rv.Len(); i++ { - if i > 0 { - builder.WriteByte(',') - } - builder.AddVar(builder, rv.Index(i).Interface()) - } - } - default: - builder.AddVar(builder, expr.Vars[idx]) - } - } + processValue(builder, expr.Vars[idx]) } else { builder.AddVar(builder, expr.Vars[idx]) } @@ -130,7 +112,11 @@ func (expr NamedExpr) Build(builder Builder) { } else if v == ' ' || v == ',' || v == ')' || v == '"' || v == '\'' || v == '`' || v == '\r' || v == '\n' || v == ';' { if inName { if nv, ok := namedMap[string(name)]; ok { - builder.AddVar(builder, nv) + if afterParenthesis { + processValue(builder, nv) + } else { + builder.AddVar(builder, nv) + } } else { builder.WriteByte('@') builder.WriteString(string(name)) @@ -142,25 +128,7 @@ func (expr NamedExpr) Build(builder Builder) { builder.WriteByte(v) } else if v == '?' && len(expr.Vars) > idx { if afterParenthesis { - if _, ok := expr.Vars[idx].(driver.Valuer); ok { - builder.AddVar(builder, expr.Vars[idx]) - } else { - switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() { - case reflect.Slice, reflect.Array: - if rv.Len() == 0 { - builder.AddVar(builder, nil) - } else { - for i := 0; i < rv.Len(); i++ { - if i > 0 { - builder.WriteByte(',') - } - builder.AddVar(builder, rv.Index(i).Interface()) - } - } - default: - builder.AddVar(builder, expr.Vars[idx]) - } - } + processValue(builder, expr.Vars[idx]) } else { builder.AddVar(builder, expr.Vars[idx]) } @@ -188,6 +156,31 @@ func (expr NamedExpr) Build(builder Builder) { } } +// processValue handles different value types appropriately for SQL parameter binding +// It checks for driver.Valuer first, then handles slices/arrays, and finally adds single values +func processValue(builder Builder, value interface{}) { + if _, ok := value.(driver.Valuer); ok { + builder.AddVar(builder, value) + return + } + + switch rv := reflect.ValueOf(value); rv.Kind() { + case reflect.Slice, reflect.Array: + if rv.Len() == 0 { + builder.AddVar(builder, nil) + } else { + for i := 0; i < rv.Len(); i++ { + if i > 0 { + builder.WriteByte(',') + } + builder.AddVar(builder, rv.Index(i).Interface()) + } + } + default: + builder.AddVar(builder, value) + } +} + // IN Whether a value is within a set of values type IN struct { Column interface{} diff --git a/vendor/gorm.io/gorm/finisher_api.go b/vendor/gorm.io/gorm/finisher_api.go index e9e35f1bf..1d0825235 100644 --- a/vendor/gorm.io/gorm/finisher_api.go +++ b/vendor/gorm.io/gorm/finisher_api.go @@ -46,11 +46,21 @@ func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) { } subtx := tx.getInstance() - subtx.Statement.Dest = reflectValue.Slice(i, ends).Interface() + batchSlice := reflect.New(reflectValue.Type()) + batchSlice.Elem().Set(reflectValue.Slice(i, ends)) + subtx.Statement.Dest = batchSlice.Interface() + subtx.callbacks.Create().Execute(subtx) + if subtx.Error != nil { return subtx.Error } + + resultSlice := reflect.Indirect(batchSlice) + for j := 0; j < resultSlice.Len(); j++ { + reflectValue.Index(i + j).Set(resultSlice.Index(j)) + } + rowsAffected += subtx.RowsAffected } return nil @@ -533,13 +543,18 @@ func (db *DB) Scan(dest interface{}) (tx *DB) { tx.Config = &config if rows, err := tx.Rows(); err == nil { + defer func() { + if err := rows.Close(); err != nil { + _ = tx.AddError(err) + } + }() + if rows.Next() { tx.ScanRows(rows, dest) } else { tx.RowsAffected = 0 tx.AddError(rows.Err()) } - tx.AddError(rows.Close()) } currentLogger.Trace(tx.Statement.Context, newLogger.BeginAt, func() (string, int64) { diff --git a/vendor/gorm.io/gorm/generics.go b/vendor/gorm.io/gorm/generics.go index 166d1520d..f5f4bede0 100644 --- a/vendor/gorm.io/gorm/generics.go +++ b/vendor/gorm.io/gorm/generics.go @@ -17,9 +17,13 @@ import ( type result struct { Result sql.Result RowsAffected int64 + Error error } func (info *result) ModifyStatement(stmt *Statement) { + info.Result = nil + info.RowsAffected = 0 + info.Error = nil stmt.Result = info } @@ -659,11 +663,13 @@ func (g execG[T]) FindInBatches(ctx context.Context, batchSize int, fc func(data } func (g execG[T]) Row(ctx context.Context) *sql.Row { - return g.g.apply(ctx).Row() + var r T + return g.g.apply(ctx).Model(r).Row() } func (g execG[T]) Rows(ctx context.Context) (*sql.Rows, error) { - return g.g.apply(ctx).Rows() + var r T + return g.g.apply(ctx).Model(r).Rows() } func (c chainG[T]) processSet(items ...clause.Assigner) setCreateOrUpdateG[T] { diff --git a/vendor/gorm.io/gorm/gorm.go b/vendor/gorm.io/gorm/gorm.go index a209bb09b..a0a10adf9 100644 --- a/vendor/gorm.io/gorm/gorm.go +++ b/vendor/gorm.io/gorm/gorm.go @@ -1,3 +1,5 @@ +// Package gorm is a full-featured, developer-friendly ORM for Golang. +// See https://gorm.io for documentation and community. package gorm import ( @@ -31,7 +33,9 @@ type Config struct { FullSaveAssociations bool // Logger Logger logger.Interface - // NowFunc the function to be used when creating a new timestamp + // NowFunc the function to be used when creating a new timestamp. + // It defaults to time.Now().Local(), so return values in the desired + // location when overriding it for timezone-sensitive applications. NowFunc func() time.Time // DryRun generate sql without execute DryRun bool @@ -124,8 +128,10 @@ type Session struct { QueryFields bool Context context.Context Logger logger.Interface - NowFunc func() time.Time - CreateBatchSize int + // NowFunc overrides the function used when creating a new timestamp + // for this session. + NowFunc func() time.Time + CreateBatchSize int } // Open initialize db session based on dialector @@ -236,6 +242,11 @@ func Open(dialector Dialector, opts ...Option) (db *DB, err error) { if err == nil && !config.DisableAutomaticPing { if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok { err = pinger.Ping() + if err != nil { + if db, _ := db.DB(); db != nil { + _ = db.Close() + } + } } } @@ -404,6 +415,9 @@ func (db *DB) AddError(err error) error { } else { db.Error = fmt.Errorf("%v; %w", db.Error, err) } + if db.Statement != nil && db.Statement.Result != nil { + db.Statement.Result.Error = db.Error + } } return db.Error } diff --git a/vendor/gorm.io/gorm/internal/lru/lru.go b/vendor/gorm.io/gorm/internal/lru/lru.go index 4f21589a0..fbb3b40a3 100644 --- a/vendor/gorm.io/gorm/internal/lru/lru.go +++ b/vendor/gorm.io/gorm/internal/lru/lru.go @@ -1,3 +1,4 @@ +// Package lru provides a thread-safe Least Recently Used (LRU) cache with expirable entries. package lru // golang -lru @@ -18,7 +19,7 @@ type LRU[K comparable, V any] struct { onEvict EvictCallback[K, V] // expirable options - mu sync.Mutex + mu sync.RWMutex ttl time.Duration done chan struct{} @@ -161,8 +162,8 @@ func (c *LRU[K, V]) Get(key K) (value V, ok bool) { // Contains checks if a key is in the cache, without updating the recent-ness // or deleting it for being stale. func (c *LRU[K, V]) Contains(key K) (ok bool) { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() _, ok = c.items[key] return ok } @@ -170,8 +171,8 @@ func (c *LRU[K, V]) Contains(key K) (ok bool) { // Peek returns the key value (or undefined if not found) without updating // the "recently used"-ness of the key. func (c *LRU[K, V]) Peek(key K) (value V, ok bool) { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() var ent *Entry[K, V] if ent, ok = c.items[key]; ok { // Expired item check @@ -208,8 +209,8 @@ func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) { // GetOldest returns the oldest entry func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() if ent := c.evictList.Back(); ent != nil { return ent.Key, ent.Value, true } @@ -217,8 +218,8 @@ func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) { } func (c *LRU[K, V]) KeyValues() map[K]V { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() maps := make(map[K]V) now := time.Now() for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() { @@ -234,8 +235,8 @@ func (c *LRU[K, V]) KeyValues() map[K]V { // Keys returns a slice of the keys in the cache, from oldest to newest. // Expired entries are filtered out. func (c *LRU[K, V]) Keys() []K { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() keys := make([]K, 0, len(c.items)) now := time.Now() for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() { @@ -250,8 +251,8 @@ func (c *LRU[K, V]) Keys() []K { // Values returns a slice of the values in the cache, from oldest to newest. // Expired entries are filtered out. func (c *LRU[K, V]) Values() []V { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() values := make([]V, 0, len(c.items)) now := time.Now() for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() { @@ -265,8 +266,8 @@ func (c *LRU[K, V]) Values() []V { // Len returns the number of items in the cache. func (c *LRU[K, V]) Len() int { - c.mu.Lock() - defer c.mu.Unlock() + c.mu.RLock() + defer c.mu.RUnlock() return c.evictList.Length() } diff --git a/vendor/gorm.io/gorm/internal/stmt_store/stmt_store.go b/vendor/gorm.io/gorm/internal/stmt_store/stmt_store.go index a82b2cf5c..6f13ebbc3 100644 --- a/vendor/gorm.io/gorm/internal/stmt_store/stmt_store.go +++ b/vendor/gorm.io/gorm/internal/stmt_store/stmt_store.go @@ -1,3 +1,4 @@ +// Package stmt_store provides an implementation of a statement cache for SQL statements. package stmt_store import ( diff --git a/vendor/gorm.io/gorm/logger/logger.go b/vendor/gorm.io/gorm/logger/logger.go index 8088cde27..0fec15189 100644 --- a/vendor/gorm.io/gorm/logger/logger.go +++ b/vendor/gorm.io/gorm/logger/logger.go @@ -1,3 +1,4 @@ +// Package logger provides a logger interface and its implementation for GORM. package logger import ( diff --git a/vendor/gorm.io/gorm/logger/sql.go b/vendor/gorm.io/gorm/logger/sql.go index ad4787956..899f02673 100644 --- a/vendor/gorm.io/gorm/logger/sql.go +++ b/vendor/gorm.io/gorm/logger/sql.go @@ -85,12 +85,14 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a case fmt.Stringer: reflectValue := reflect.ValueOf(v) switch reflectValue.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - vars[idx] = fmt.Sprintf("%d", reflectValue.Interface()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + vars[idx] = strconv.FormatInt(reflectValue.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + vars[idx] = strconv.FormatUint(reflectValue.Uint(), 10) case reflect.Float32, reflect.Float64: - vars[idx] = fmt.Sprintf("%.6f", reflectValue.Interface()) + vars[idx] = strconv.FormatFloat(reflectValue.Float(), 'f', 6, 64) case reflect.Bool: - vars[idx] = fmt.Sprintf("%t", reflectValue.Interface()) + vars[idx] = strconv.FormatBool(reflectValue.Bool()) case reflect.String: vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, escaper+escaper) + escaper default: @@ -124,10 +126,13 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a } else if rv.Kind() == reflect.Ptr && !rv.IsZero() { convertParams(reflect.Indirect(rv).Interface(), idx) } else if isNumeric(rv.Kind()) { - if rv.CanInt() || rv.CanUint() { - vars[idx] = fmt.Sprintf("%d", rv.Interface()) - } else { - vars[idx] = fmt.Sprintf("%.6f", rv.Interface()) + switch { + case rv.CanInt(): + vars[idx] = strconv.FormatInt(rv.Int(), 10) + case rv.CanUint(): + vars[idx] = strconv.FormatUint(rv.Uint(), 10) + default: + vars[idx] = strconv.FormatFloat(rv.Float(), 'f', 6, 64) } } else { for _, t := range convertibleTypes { diff --git a/vendor/gorm.io/gorm/migrator/column_type.go b/vendor/gorm.io/gorm/migrator/column_type.go index c6fdd6b2d..e1c5e942d 100644 --- a/vendor/gorm.io/gorm/migrator/column_type.go +++ b/vendor/gorm.io/gorm/migrator/column_type.go @@ -28,7 +28,10 @@ func (ct ColumnType) Name() string { if ct.NameValue.Valid { return ct.NameValue.String } - return ct.SQLColumnType.Name() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.Name() + } + return "" } // DatabaseTypeName returns the database system name of the column type. If an empty @@ -41,7 +44,10 @@ func (ct ColumnType) DatabaseTypeName() string { if ct.DataTypeValue.Valid { return ct.DataTypeValue.String } - return ct.SQLColumnType.DatabaseTypeName() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.DatabaseTypeName() + } + return "" } // ColumnType returns the database type of the column. like `varchar(16)` @@ -64,7 +70,10 @@ func (ct ColumnType) Length() (length int64, ok bool) { if ct.LengthValue.Valid { return ct.LengthValue.Int64, true } - return ct.SQLColumnType.Length() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.Length() + } + return 0, false } // DecimalSize returns the scale and precision of a decimal type. @@ -72,7 +81,10 @@ func (ct ColumnType) DecimalSize() (precision int64, scale int64, ok bool) { if ct.DecimalSizeValue.Valid { return ct.DecimalSizeValue.Int64, ct.ScaleValue.Int64, true } - return ct.SQLColumnType.DecimalSize() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.DecimalSize() + } + return 0, 0, false } // Nullable reports whether the column may be null. @@ -80,7 +92,10 @@ func (ct ColumnType) Nullable() (nullable bool, ok bool) { if ct.NullableValue.Valid { return ct.NullableValue.Bool, true } - return ct.SQLColumnType.Nullable() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.Nullable() + } + return false, false } // Unique reports whether the column may be unique. @@ -93,7 +108,10 @@ func (ct ColumnType) ScanType() reflect.Type { if ct.ScanTypeValue != nil { return ct.ScanTypeValue } - return ct.SQLColumnType.ScanType() + if ct.SQLColumnType != nil { + return ct.SQLColumnType.ScanType() + } + return nil } // Comment returns the comment of current column. diff --git a/vendor/gorm.io/gorm/migrator/migrator.go b/vendor/gorm.io/gorm/migrator/migrator.go index 35107d572..9729e574e 100644 --- a/vendor/gorm.io/gorm/migrator/migrator.go +++ b/vendor/gorm.io/gorm/migrator/migrator.go @@ -1,3 +1,4 @@ +// Package migrator provides the interface and implementation for database schema migration in GORM. package migrator import ( @@ -407,15 +408,15 @@ func (m Migrator) DropColumn(value interface{}, name string) error { }) } -// AlterColumn alter value's `field` column' type based on schema definition +// AlterColumn alter value's `field` column's type based on schema definition func (m Migrator) AlterColumn(value interface{}, field string) error { return m.RunWithValue(value, func(stmt *gorm.Statement) error { if stmt.Schema != nil { if field := stmt.Schema.LookUpField(field); field != nil { - fileType := m.FullDataTypeOf(field) + fieldType := m.FullDataTypeOf(field) return m.DB.Exec( "ALTER TABLE ? ALTER COLUMN ? TYPE ?", - m.CurrentTable(stmt), clause.Column{Name: field.DBName}, fileType, + m.CurrentTable(stmt), clause.Column{Name: field.DBName}, fieldType, ).Error } @@ -559,13 +560,17 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy case schema.Bool: v1, _ := strconv.ParseBool(dv) v2, _ := strconv.ParseBool(field.DefaultValue) - alterColumn = v1 != v2 + if v1 != v2 { + alterColumn = true + } case schema.String: if dv != field.DefaultValue && dv != strings.Trim(field.DefaultValue, "'\"") { alterColumn = true } default: - alterColumn = dv != field.DefaultValue + if dv != field.DefaultValue { + alterColumn = true + } } } } diff --git a/vendor/gorm.io/gorm/schema/field.go b/vendor/gorm.io/gorm/schema/field.go index de7974023..521b76599 100644 --- a/vendor/gorm.io/gorm/schema/field.go +++ b/vendor/gorm.io/gorm/schema/field.go @@ -962,6 +962,13 @@ func (field *Field) setupValuerAndSetter(modelType reflect.Type) { serializerType := serializerValue.Type() field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) { if s, ok := v.(*serializer); ok { + if s.fieldValue == nil && s.Serializer == nil { + rv := field.ReflectValueOf(ctx, value) + if rv.IsValid() && rv.CanSet() { + rv.Set(reflect.Zero(field.FieldType)) + } + return nil + } if s.fieldValue != nil { err = oldFieldSetter(ctx, value, s.fieldValue) } else if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil { diff --git a/vendor/gorm.io/gorm/schema/relationship.go b/vendor/gorm.io/gorm/schema/relationship.go index 0535bba40..0b55ee1b2 100644 --- a/vendor/gorm.io/gorm/schema/relationship.go +++ b/vendor/gorm.io/gorm/schema/relationship.go @@ -669,8 +669,9 @@ func (rel *Relationship) ParseConstraint() *Constraint { if r != rel && r.FieldSchema == rel.Schema && len(rel.References) == len(r.References) { matched := true for idx, ref := range r.References { - if !(rel.References[idx].PrimaryKey == ref.PrimaryKey && rel.References[idx].ForeignKey == ref.ForeignKey && - rel.References[idx].PrimaryValue == ref.PrimaryValue) { + if rel.References[idx].PrimaryKey != ref.PrimaryKey || + rel.References[idx].ForeignKey != ref.ForeignKey || + rel.References[idx].PrimaryValue != ref.PrimaryValue { matched = false break } diff --git a/vendor/gorm.io/gorm/schema/schema.go b/vendor/gorm.io/gorm/schema/schema.go index 09697a7ab..b28149566 100644 --- a/vendor/gorm.io/gorm/schema/schema.go +++ b/vendor/gorm.io/gorm/schema/schema.go @@ -1,3 +1,4 @@ +// Package schema provides the Schema struct and related functions for parsing and managing database schemas in GORM. package schema import ( diff --git a/vendor/gorm.io/gorm/utils/utils.go b/vendor/gorm.io/gorm/utils/utils.go index 7e59264be..b3323555e 100644 --- a/vendor/gorm.io/gorm/utils/utils.go +++ b/vendor/gorm.io/gorm/utils/utils.go @@ -1,3 +1,4 @@ +// Package utils provides internal utility functions for GORM. package utils import ( @@ -36,9 +37,14 @@ func sourceDir(file string) string { // - Exclude test files (*_test.go) // - go-gorm/gen's Generated files (*.gen.go) func CallerFrame() runtime.Frame { + // Preserve the original CallerFrame stack depth after introducing callerFrame(). + return callerFrame(4) +} + +func callerFrame(skip int) runtime.Frame { pcs := [13]uintptr{} - // the third caller usually from gorm internal - len := runtime.Callers(3, pcs[:]) + // skip is caller-path sensitive and should be selected by each public helper. + len := runtime.Callers(skip, pcs[:]) frames := runtime.CallersFrames(pcs[:len]) for i := 0; i < len; i++ { // second return value is "more", not "ok" @@ -54,7 +60,8 @@ func CallerFrame() runtime.Frame { // FileWithLineNum return the file name and line number of the current file func FileWithLineNum() string { - frame := CallerFrame() + // Keep FileWithLineNum one frame outer than CallerFrame to preserve pre-v1.31.1 semantics. + frame := callerFrame(4) if frame.PC != 0 { return string(strconv.AppendInt(append([]byte(frame.File), ':'), int64(frame.Line), 10)) } diff --git a/vendor/modules.txt b/vendor/modules.txt index bc027c676..8ff75e1c6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -38,7 +38,7 @@ github.com/cloudbase/garm-provider-common/util/websocket # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/dlclark/regexp2/v2 v2.2.1 +# github.com/dlclark/regexp2/v2 v2.2.2 ## explicit; go 1.25 github.com/dlclark/regexp2/v2 github.com/dlclark/regexp2/v2/helpers @@ -93,7 +93,7 @@ github.com/go-logr/logr/funcr # github.com/go-logr/stdr v1.2.2 ## explicit; go 1.16 github.com/go-logr/stdr -# github.com/go-openapi/analysis v0.25.2 +# github.com/go-openapi/analysis v0.25.3 ## explicit; go 1.25.0 github.com/go-openapi/analysis github.com/go-openapi/analysis/internal/debug @@ -105,9 +105,10 @@ github.com/go-openapi/analysis/internal/flatten/sortref # github.com/go-openapi/errors v0.22.8 ## explicit; go 1.25.0 github.com/go-openapi/errors -# github.com/go-openapi/jsonpointer v0.23.1 +# github.com/go-openapi/jsonpointer v0.24.0 ## explicit; go 1.25.0 github.com/go-openapi/jsonpointer +github.com/go-openapi/jsonpointer/jsonname # github.com/go-openapi/jsonreference v0.21.6 ## explicit; go 1.25.0 github.com/go-openapi/jsonreference @@ -126,7 +127,7 @@ github.com/go-openapi/runtime/middleware/denco github.com/go-openapi/runtime/middleware/untyped github.com/go-openapi/runtime/security github.com/go-openapi/runtime/yamlpc -# github.com/go-openapi/runtime/server-middleware v0.32.3 +# github.com/go-openapi/runtime/server-middleware v0.32.4 ## explicit; go 1.25.0 github.com/go-openapi/runtime/server-middleware/docui github.com/go-openapi/runtime/server-middleware/mediatype @@ -135,47 +136,47 @@ github.com/go-openapi/runtime/server-middleware/negotiate/header # github.com/go-openapi/spec v0.22.6 ## explicit; go 1.25.0 github.com/go-openapi/spec -# github.com/go-openapi/strfmt v0.26.3 +# github.com/go-openapi/strfmt v0.26.4 ## explicit; go 1.25.0 github.com/go-openapi/strfmt github.com/go-openapi/strfmt/internal/bsonlite -# github.com/go-openapi/swag v0.26.1 +# github.com/go-openapi/swag v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag -# github.com/go-openapi/swag/cmdutils v0.26.1 +# github.com/go-openapi/swag/cmdutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/cmdutils -# github.com/go-openapi/swag/conv v0.26.1 +# github.com/go-openapi/swag/conv v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/conv -# github.com/go-openapi/swag/fileutils v0.26.1 +# github.com/go-openapi/swag/fileutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/fileutils -# github.com/go-openapi/swag/jsonname v0.26.1 +# github.com/go-openapi/swag/jsonname v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/jsonname -# github.com/go-openapi/swag/jsonutils v0.26.1 +# github.com/go-openapi/swag/jsonutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/jsonutils github.com/go-openapi/swag/jsonutils/adapters github.com/go-openapi/swag/jsonutils/adapters/ifaces github.com/go-openapi/swag/jsonutils/adapters/stdlib/json -# github.com/go-openapi/swag/loading v0.26.1 +# github.com/go-openapi/swag/loading v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/loading -# github.com/go-openapi/swag/mangling v0.26.1 +# github.com/go-openapi/swag/mangling v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/mangling -# github.com/go-openapi/swag/netutils v0.26.1 +# github.com/go-openapi/swag/netutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/netutils -# github.com/go-openapi/swag/stringutils v0.26.1 +# github.com/go-openapi/swag/stringutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/stringutils -# github.com/go-openapi/swag/typeutils v0.26.1 +# github.com/go-openapi/swag/typeutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/typeutils -# github.com/go-openapi/swag/yamlutils v0.26.1 +# github.com/go-openapi/swag/yamlutils v0.27.0 ## explicit; go 1.25.0 github.com/go-openapi/swag/yamlutils # github.com/go-openapi/validate v0.26.0 @@ -248,7 +249,7 @@ github.com/jackc/pgx/v5/stdlib ## explicit; go 1.19 github.com/jackc/puddle/v2 github.com/jackc/puddle/v2/internal/genstack -# github.com/jedib0t/go-pretty/v6 v6.8.1 +# github.com/jedib0t/go-pretty/v6 v6.8.2 ## explicit; go 1.18 github.com/jedib0t/go-pretty/v6/table github.com/jedib0t/go-pretty/v6/text @@ -272,7 +273,7 @@ github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.24 ## explicit; go 1.20 github.com/mattn/go-runewidth -# github.com/mattn/go-sqlite3 v1.14.45 => github.com/gabriel-samfira/go-sqlite3 v0.0.0-20251005121134-bc61ecf9b4c7 +# github.com/mattn/go-sqlite3 v1.14.47 => github.com/gabriel-samfira/go-sqlite3 v0.0.0-20251005121134-bc61ecf9b4c7 ## explicit; go 1.19 github.com/mattn/go-sqlite3 # github.com/minio/sio v0.5.1 @@ -312,11 +313,11 @@ github.com/prometheus/client_golang/prometheus/promhttp/internal # github.com/prometheus/client_model v0.6.2 ## explicit; go 1.22.0 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.68.1 +# github.com/prometheus/common v0.69.0 ## explicit; go 1.25.0 github.com/prometheus/common/expfmt github.com/prometheus/common/model -# github.com/prometheus/procfs v0.20.1 +# github.com/prometheus/procfs v0.21.0 ## explicit; go 1.25.0 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs @@ -480,7 +481,7 @@ gorm.io/driver/postgres # gorm.io/driver/sqlite v1.6.0 ## explicit; go 1.20 gorm.io/driver/sqlite -# gorm.io/gorm v1.31.1 +# gorm.io/gorm v1.31.2 ## explicit; go 1.18 gorm.io/gorm gorm.io/gorm/callbacks diff --git a/webapp/src/lib/api/client.ts b/webapp/src/lib/api/client.ts index 08ccb5651..0dea23702 100644 --- a/webapp/src/lib/api/client.ts +++ b/webapp/src/lib/api/client.ts @@ -4,6 +4,8 @@ import { type Repository, type Organization, type Enterprise, + type ForgeInstance, + type CreateForgeInstanceParams, type Endpoint, type Pool, type ScaleSet, @@ -42,6 +44,8 @@ export type { Repository, Organization, Enterprise, + ForgeInstance, + CreateForgeInstanceParams, Endpoint, Pool, ScaleSet, diff --git a/webapp/src/lib/api/generated-client.ts b/webapp/src/lib/api/generated-client.ts index 7d20fe805..218f58681 100644 --- a/webapp/src/lib/api/generated-client.ts +++ b/webapp/src/lib/api/generated-client.ts @@ -10,6 +10,7 @@ import { RepositoriesApi, OrganizationsApi, EnterprisesApi, + ForgeInstancesApi, PoolsApi, ScalesetsApi, InstancesApi, @@ -21,6 +22,8 @@ import { type Repository, type Organization, type Enterprise, + type ForgeInstance, + type CreateForgeInstanceParams, type ForgeEndpoint, type Pool, type ScaleSet, @@ -64,6 +67,8 @@ export type { Repository, Organization, Enterprise, + ForgeInstance, + CreateForgeInstanceParams, ForgeEndpoint as Endpoint, Pool, ScaleSet, @@ -127,6 +132,7 @@ export class GeneratedGarmApiClient { private repositoriesApi: RepositoriesApi; private organizationsApi: OrganizationsApi; private enterprisesApi: EnterprisesApi; + private forgeInstancesApi: ForgeInstancesApi; private poolsApi: PoolsApi; private scaleSetsApi: ScalesetsApi; private instancesApi: InstancesApi; @@ -160,6 +166,7 @@ export class GeneratedGarmApiClient { this.repositoriesApi = new RepositoriesApi(this.config); this.organizationsApi = new OrganizationsApi(this.config); this.enterprisesApi = new EnterprisesApi(this.config); + this.forgeInstancesApi = new ForgeInstancesApi(this.config); this.poolsApi = new PoolsApi(this.config); this.scaleSetsApi = new ScalesetsApi(this.config); this.instancesApi = new InstancesApi(this.config); @@ -195,6 +202,7 @@ export class GeneratedGarmApiClient { this.repositoriesApi = new RepositoriesApi(this.config); this.organizationsApi = new OrganizationsApi(this.config); this.enterprisesApi = new EnterprisesApi(this.config); + this.forgeInstancesApi = new ForgeInstancesApi(this.config); this.poolsApi = new PoolsApi(this.config); this.scaleSetsApi = new ScalesetsApi(this.config); this.instancesApi = new InstancesApi(this.config); @@ -494,6 +502,46 @@ export class GeneratedGarmApiClient { return response.data; } + // Forge Instances + async listForgeInstances(): Promise { + const response = await this.forgeInstancesApi.listForgeInstances(); + return response.data || []; + } + + async getForgeInstance(id: string): Promise { + const response = await this.forgeInstancesApi.getForgeInstance(id); + return response.data; + } + + async createForgeInstance(params: CreateForgeInstanceParams): Promise { + const response = await this.forgeInstancesApi.createForgeInstance(params); + return response.data; + } + + async updateForgeInstance(id: string, params: UpdateEntityParams): Promise { + const response = await this.forgeInstancesApi.updateForgeInstance(id, params); + return response.data; + } + + async deleteForgeInstance(id: string): Promise { + await this.forgeInstancesApi.deleteForgeInstance(id); + } + + async listForgeInstancePools(id: string): Promise { + const response = await this.forgeInstancesApi.listForgeInstancePools(id); + return response.data || []; + } + + async listForgeInstanceInstances(id: string): Promise { + const response = await this.forgeInstancesApi.listForgeInstanceInstances(id); + return response.data || []; + } + + async createForgeInstancePool(id: string, params: CreatePoolParams): Promise { + const response = await this.forgeInstancesApi.createForgeInstancePool(id, params); + return response.data; + } + // Scale sets for repositories, organizations, and enterprises async createRepositoryScaleSet(id: string, params: CreateScaleSetParams): Promise { const response = await this.repositoriesApi.createRepoScaleSet(id, params); diff --git a/webapp/src/lib/api/generated/.openapi-generator/FILES b/webapp/src/lib/api/generated/.openapi-generator/FILES index d6780720b..3ee8d3636 100644 --- a/webapp/src/lib/api/generated/.openapi-generator/FILES +++ b/webapp/src/lib/api/generated/.openapi-generator/FILES @@ -13,6 +13,7 @@ docs/ControllerInfo.md docs/ControllerInfoApi.md docs/CreateEnterpriseParams.md docs/CreateFileObjectParams.md +docs/CreateForgeInstanceParams.md docs/CreateGARMToolParams.md docs/CreateGiteaCredentialsParams.md docs/CreateGiteaEndpointParams.md @@ -35,6 +36,8 @@ docs/FirstRunApi.md docs/ForgeCredentials.md docs/ForgeEndpoint.md docs/ForgeEntity.md +docs/ForgeInstance.md +docs/ForgeInstancesApi.md docs/GARMAgentTool.md docs/GARMAgentToolsPaginatedResponse.md docs/GARMAgentToolsPaginatedResponseResultsInner.md diff --git a/webapp/src/lib/api/generated/api.ts b/webapp/src/lib/api/generated/api.ts index ec3daea77..9cc91baab 100644 --- a/webapp/src/lib/api/generated/api.ts +++ b/webapp/src/lib/api/generated/api.ts @@ -227,6 +227,49 @@ export interface CreateFileObjectParams { */ 'tags'?: Array; } +/** + * + * @export + * @interface CreateForgeInstanceParams + */ +export interface CreateForgeInstanceParams { + /** + * + * @type {boolean} + * @memberof CreateForgeInstanceParams + */ + 'agent_mode'?: boolean; + /** + * + * @type {string} + * @memberof CreateForgeInstanceParams + */ + 'credentials_name'?: string; + /** + * + * @type {string} + * @memberof CreateForgeInstanceParams + */ + 'endpoint_name'?: string; + /** + * + * @type {string} + * @memberof CreateForgeInstanceParams + */ + 'forge_type'?: string; + /** + * + * @type {string} + * @memberof CreateForgeInstanceParams + */ + 'pool_balancer_type'?: string; + /** + * + * @type {string} + * @memberof CreateForgeInstanceParams + */ + 'webhook_secret'?: string; +} /** * * @export @@ -1294,6 +1337,12 @@ export interface ForgeEntity { * @memberof ForgeEntity */ 'entity_type'?: string; + /** + * + * @type {ForgeEndpoint} + * @memberof ForgeEntity + */ + 'forge'?: ForgeEndpoint; /** * * @type {string} @@ -1331,6 +1380,85 @@ export interface ForgeEntity { */ 'updated_at'?: string; } +/** + * + * @export + * @interface ForgeInstance + */ +export interface ForgeInstance { + /** + * + * @type {boolean} + * @memberof ForgeInstance + */ + 'agent_mode'?: boolean; + /** + * + * @type {string} + * @memberof ForgeInstance + */ + 'created_at'?: string; + /** + * + * @type {ForgeCredentials} + * @memberof ForgeInstance + */ + 'credentials'?: ForgeCredentials; + /** + * + * @type {number} + * @memberof ForgeInstance + */ + 'credentials_id'?: number; + /** + * CredentialName is the name of the credentials associated with the forge instance. This field is now deprecated. Use CredentialsID instead. This field will be removed in v0.2.0. + * @type {string} + * @memberof ForgeInstance + */ + 'credentials_name'?: string; + /** + * + * @type {ForgeEndpoint} + * @memberof ForgeInstance + */ + 'endpoint'?: ForgeEndpoint; + /** + * + * @type {Array} + * @memberof ForgeInstance + */ + 'events'?: Array; + /** + * + * @type {string} + * @memberof ForgeInstance + */ + 'id'?: string; + /** + * + * @type {Array} + * @memberof ForgeInstance + */ + 'pool'?: Array; + /** + * + * @type {string} + * @memberof ForgeInstance + */ + 'pool_balancing_type'?: string; + /** + * + * @type {PoolManagerStatus} + * @memberof ForgeInstance + */ + 'pool_manager_status'?: PoolManagerStatus; + /** + * + * @type {string} + * @memberof ForgeInstance + */ + 'updated_at'?: string; +} /** * * @export @@ -1960,6 +2088,12 @@ export interface Job { * @memberof Job */ 'enterprise_id'?: string; + /** + * + * @type {string} + * @memberof Job + */ + 'forge_instance_id'?: string; /** * ID is the ID of the job. * @type {number} @@ -2289,6 +2423,12 @@ export interface Pool { * @memberof Pool */ 'flavor'?: string; + /** + * + * @type {string} + * @memberof Pool + */ + 'forge_instance_id'?: string; /** * Generation holds the numeric generation of the pool. This number will be incremented, every time certain settings of the pool, which may influence how runners are created (flavor, specs, image) are changed. When a runner is created, this generation will be copied to the runners as well. That way if some settings diverge, we can target those runners to be recreated. * @type {number} @@ -6467,23 +6607,22 @@ export class FirstRunApi extends BaseAPI { /** - * HooksApi - axios parameter creator + * ForgeInstancesApi - axios parameter creator * @export */ -export const HooksApiAxiosParamCreator = function (configuration?: Configuration) { +export const ForgeInstancesApiAxiosParamCreator = function (configuration?: Configuration) { return { /** * - * @summary Get information about the GARM installed webhook on an organization. - * @param {string} orgID Organization ID. + * @summary Create forge instance with the given parameters. + * @param {CreateForgeInstanceParams} body Parameters used to create the forge instance. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getOrgWebhookInfo: async (orgID: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'orgID' is not null or undefined - assertParamExists('getOrgWebhookInfo', 'orgID', orgID) - const localVarPath = `/organizations/{orgID}/webhook` - .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + createForgeInstance: async (body: CreateForgeInstanceParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'body' is not null or undefined + assertParamExists('createForgeInstance', 'body', body) + const localVarPath = `/forge-instances`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6491,7 +6630,7 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -6500,9 +6639,12 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -6511,16 +6653,19 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration }, /** * - * @summary Get information about the GARM installed webhook on a repository. - * @param {string} repoID Repository ID. + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getRepoWebhookInfo: async (repoID: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'repoID' is not null or undefined - assertParamExists('getRepoWebhookInfo', 'repoID', repoID) - const localVarPath = `/repositories/{repoID}/webhook` - .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + createForgeInstancePool: async (forgeInstanceID: string, body: CreatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('createForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'body' is not null or undefined + assertParamExists('createForgeInstancePool', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6528,7 +6673,7 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -6537,9 +6682,12 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -6547,19 +6695,18 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration }; }, /** - * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. - * @param {string} orgID Organization ID. - * @param {InstallWebhookParams} body Parameters used when creating the organization webhook. + * + * @summary Delete forge instance by ID. + * @param {string} forgeInstanceID ID of the forge instance to delete. + * @param {boolean} [keepWebhook] If true and a webhook is installed for this forge instance, it will not be removed. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - installOrgWebhook: async (orgID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'orgID' is not null or undefined - assertParamExists('installOrgWebhook', 'orgID', orgID) - // verify required parameter 'body' is not null or undefined - assertParamExists('installOrgWebhook', 'body', body) - const localVarPath = `/organizations/{orgID}/webhook` - .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + deleteForgeInstance: async (forgeInstanceID: string, keepWebhook?: boolean, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('deleteForgeInstance', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6567,21 +6714,22 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; // authentication Bearer required await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + if (keepWebhook !== undefined) { + localVarQueryParameter['keepWebhook'] = keepWebhook; + } + - localVarHeaderParameter['Content-Type'] = 'application/json'; - setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -6589,19 +6737,21 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration }; }, /** - * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. - * @param {string} repoID Repository ID. - * @param {InstallWebhookParams} body Parameters used when creating the repository webhook. + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - installRepoWebhook: async (repoID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'repoID' is not null or undefined - assertParamExists('installRepoWebhook', 'repoID', repoID) - // verify required parameter 'body' is not null or undefined - assertParamExists('installRepoWebhook', 'body', body) - const localVarPath = `/repositories/{repoID}/webhook` - .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + deleteForgeInstancePool: async (forgeInstanceID: string, poolID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('deleteForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('deleteForgeInstancePool', 'poolID', poolID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6609,7 +6759,7 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -6618,12 +6768,9 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration - localVarHeaderParameter['Content-Type'] = 'application/json'; - setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -6632,16 +6779,16 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration }, /** * - * @summary Uninstall organization webhook. - * @param {string} orgID Organization ID. + * @summary Get forge instance by ID. + * @param {string} forgeInstanceID The ID of the forge instance to fetch. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - uninstallOrgWebhook: async (orgID: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'orgID' is not null or undefined - assertParamExists('uninstallOrgWebhook', 'orgID', orgID) - const localVarPath = `/organizations/{orgID}/webhook` - .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + getForgeInstance: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('getForgeInstance', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6649,7 +6796,7 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -6669,16 +6816,20 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration }, /** * - * @summary Uninstall organization webhook. - * @param {string} repoID Repository ID. + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - uninstallRepoWebhook: async (repoID: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'repoID' is not null or undefined - assertParamExists('uninstallRepoWebhook', 'repoID', repoID) - const localVarPath = `/repositories/{repoID}/webhook` - .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + getForgeInstancePool: async (forgeInstanceID: string, poolID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('getForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('getForgeInstancePool', 'poolID', poolID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -6686,7 +6837,7 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -6704,48 +6855,1290 @@ export const HooksApiAxiosParamCreator = function (configuration?: Configuration options: localVarRequestOptions, }; }, - } -}; - -/** - * HooksApi - functional programming interface - * @export - */ -export const HooksApiFp = function(configuration?: Configuration) { - const localVarAxiosParamCreator = HooksApiAxiosParamCreator(configuration) - return { /** * - * @summary Get information about the GARM installed webhook on an organization. - * @param {string} orgID Organization ID. + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getOrgWebhookInfo(orgID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getOrgWebhookInfo(orgID, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['HooksApi.getOrgWebhookInfo']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + getForgeInstanceWebhookInfo: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('getForgeInstanceWebhookInfo', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; }, /** - * - * @summary Get information about the GARM installed webhook on a repository. - * @param {string} repoID Repository ID. + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getRepoWebhookInfo(repoID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getRepoWebhookInfo(repoID, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['HooksApi.getRepoWebhookInfo']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. - * @param {string} orgID Organization ID. - * @param {InstallWebhookParams} body Parameters used when creating the organization webhook. - * @param {*} [options] Override http request option. - * @throws {RequiredError} + installForgeInstanceWebhook: async (forgeInstanceID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('installForgeInstanceWebhook', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'body' is not null or undefined + assertParamExists('installForgeInstanceWebhook', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary List forge instance runner instances. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstanceInstances: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('listForgeInstanceInstances', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/instances` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstancePools: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('listForgeInstancePools', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary List all forge instances. + * @param {string} [endpoint] Exact endpoint name to filter by + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstances: async (endpoint?: string, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/forge-instances`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + if (endpoint !== undefined) { + localVarQueryParameter['endpoint'] = endpoint; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallForgeInstanceWebhook: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('uninstallForgeInstanceWebhook', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Update forge instance with the given parameters. + * @param {string} forgeInstanceID The ID of the forge instance to update. + * @param {UpdateEntityParams} body Parameters used when updating the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstance: async (forgeInstanceID: string, body: UpdateEntityParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('updateForgeInstance', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'body' is not null or undefined + assertParamExists('updateForgeInstance', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstancePool: async (forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('updateForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('updateForgeInstancePool', 'poolID', poolID) + // verify required parameter 'body' is not null or undefined + assertParamExists('updateForgeInstancePool', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ForgeInstancesApi - functional programming interface + * @export + */ +export const ForgeInstancesApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = ForgeInstancesApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Create forge instance with the given parameters. + * @param {CreateForgeInstanceParams} body Parameters used to create the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createForgeInstance(body: CreateForgeInstanceParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createForgeInstance(body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.createForgeInstance']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createForgeInstancePool(forgeInstanceID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.createForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Delete forge instance by ID. + * @param {string} forgeInstanceID ID of the forge instance to delete. + * @param {boolean} [keepWebhook] If true and a webhook is installed for this forge instance, it will not be removed. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteForgeInstance(forgeInstanceID: string, keepWebhook?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteForgeInstance(forgeInstanceID, keepWebhook, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.deleteForgeInstance']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteForgeInstancePool(forgeInstanceID, poolID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.deleteForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get forge instance by ID. + * @param {string} forgeInstanceID The ID of the forge instance to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getForgeInstance(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getForgeInstance(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.getForgeInstance']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getForgeInstancePool(forgeInstanceID, poolID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.getForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getForgeInstanceWebhookInfo(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.getForgeInstanceWebhookInfo']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.installForgeInstanceWebhook(forgeInstanceID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.installForgeInstanceWebhook']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary List forge instance runner instances. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listForgeInstanceInstances(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listForgeInstanceInstances(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.listForgeInstanceInstances']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listForgeInstancePools(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.listForgeInstancePools']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary List all forge instances. + * @param {string} [endpoint] Exact endpoint name to filter by + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listForgeInstances(endpoint?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listForgeInstances(endpoint, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.listForgeInstances']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.uninstallForgeInstanceWebhook(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.uninstallForgeInstanceWebhook']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Update forge instance with the given parameters. + * @param {string} forgeInstanceID The ID of the forge instance to update. + * @param {UpdateEntityParams} body Parameters used when updating the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateForgeInstance(forgeInstanceID: string, body: UpdateEntityParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateForgeInstance(forgeInstanceID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.updateForgeInstance']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateForgeInstancePool(forgeInstanceID, poolID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ForgeInstancesApi.updateForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * ForgeInstancesApi - factory interface + * @export + */ +export const ForgeInstancesApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = ForgeInstancesApiFp(configuration) + return { + /** + * + * @summary Create forge instance with the given parameters. + * @param {CreateForgeInstanceParams} body Parameters used to create the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createForgeInstance(body: CreateForgeInstanceParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createForgeInstance(body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createForgeInstancePool(forgeInstanceID, body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Delete forge instance by ID. + * @param {string} forgeInstanceID ID of the forge instance to delete. + * @param {boolean} [keepWebhook] If true and a webhook is installed for this forge instance, it will not be removed. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteForgeInstance(forgeInstanceID: string, keepWebhook?: boolean, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.deleteForgeInstance(forgeInstanceID, keepWebhook, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.deleteForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get forge instance by ID. + * @param {string} forgeInstanceID The ID of the forge instance to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstance(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getForgeInstance(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getForgeInstanceWebhookInfo(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.installForgeInstanceWebhook(forgeInstanceID, body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary List forge instance runner instances. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstanceInstances(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listForgeInstanceInstances(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listForgeInstancePools(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary List all forge instances. + * @param {string} [endpoint] Exact endpoint name to filter by + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstances(endpoint?: string, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listForgeInstances(endpoint, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.uninstallForgeInstanceWebhook(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Update forge instance with the given parameters. + * @param {string} forgeInstanceID The ID of the forge instance to update. + * @param {UpdateEntityParams} body Parameters used when updating the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstance(forgeInstanceID: string, body: UpdateEntityParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.updateForgeInstance(forgeInstanceID, body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.updateForgeInstancePool(forgeInstanceID, poolID, body, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * ForgeInstancesApi - object-oriented interface + * @export + * @class ForgeInstancesApi + * @extends {BaseAPI} + */ +export class ForgeInstancesApi extends BaseAPI { + /** + * + * @summary Create forge instance with the given parameters. + * @param {CreateForgeInstanceParams} body Parameters used to create the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public createForgeInstance(body: CreateForgeInstanceParams, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).createForgeInstance(body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).createForgeInstancePool(forgeInstanceID, body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Delete forge instance by ID. + * @param {string} forgeInstanceID ID of the forge instance to delete. + * @param {boolean} [keepWebhook] If true and a webhook is installed for this forge instance, it will not be removed. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public deleteForgeInstance(forgeInstanceID: string, keepWebhook?: boolean, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).deleteForgeInstance(forgeInstanceID, keepWebhook, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).deleteForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get forge instance by ID. + * @param {string} forgeInstanceID The ID of the forge instance to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public getForgeInstance(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).getForgeInstance(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).getForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).getForgeInstanceWebhookInfo(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).installForgeInstanceWebhook(forgeInstanceID, body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary List forge instance runner instances. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public listForgeInstanceInstances(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).listForgeInstanceInstances(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).listForgeInstancePools(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary List all forge instances. + * @param {string} [endpoint] Exact endpoint name to filter by + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public listForgeInstances(endpoint?: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).listForgeInstances(endpoint, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).uninstallForgeInstanceWebhook(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Update forge instance with the given parameters. + * @param {string} forgeInstanceID The ID of the forge instance to update. + * @param {UpdateEntityParams} body Parameters used when updating the forge instance. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public updateForgeInstance(forgeInstanceID: string, body: UpdateEntityParams, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).updateForgeInstance(forgeInstanceID, body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ForgeInstancesApi + */ + public updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig) { + return ForgeInstancesApiFp(this.configuration).updateForgeInstancePool(forgeInstanceID, poolID, body, options).then((request) => request(this.axios, this.basePath)); + } +} + + + +/** + * HooksApi - axios parameter creator + * @export + */ +export const HooksApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstanceWebhookInfo: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('getForgeInstanceWebhookInfo', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get information about the GARM installed webhook on an organization. + * @param {string} orgID Organization ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getOrgWebhookInfo: async (orgID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'orgID' is not null or undefined + assertParamExists('getOrgWebhookInfo', 'orgID', orgID) + const localVarPath = `/organizations/{orgID}/webhook` + .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get information about the GARM installed webhook on a repository. + * @param {string} repoID Repository ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getRepoWebhookInfo: async (repoID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'repoID' is not null or undefined + assertParamExists('getRepoWebhookInfo', 'repoID', repoID) + const localVarPath = `/repositories/{repoID}/webhook` + .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + installForgeInstanceWebhook: async (forgeInstanceID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('installForgeInstanceWebhook', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'body' is not null or undefined + assertParamExists('installForgeInstanceWebhook', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. + * @param {string} orgID Organization ID. + * @param {InstallWebhookParams} body Parameters used when creating the organization webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + installOrgWebhook: async (orgID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'orgID' is not null or undefined + assertParamExists('installOrgWebhook', 'orgID', orgID) + // verify required parameter 'body' is not null or undefined + assertParamExists('installOrgWebhook', 'body', body) + const localVarPath = `/organizations/{orgID}/webhook` + .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. + * @param {string} repoID Repository ID. + * @param {InstallWebhookParams} body Parameters used when creating the repository webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + installRepoWebhook: async (repoID: string, body: InstallWebhookParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'repoID' is not null or undefined + assertParamExists('installRepoWebhook', 'repoID', repoID) + // verify required parameter 'body' is not null or undefined + assertParamExists('installRepoWebhook', 'body', body) + const localVarPath = `/repositories/{repoID}/webhook` + .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallForgeInstanceWebhook: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('uninstallForgeInstanceWebhook', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/webhook` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Uninstall organization webhook. + * @param {string} orgID Organization ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallOrgWebhook: async (orgID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'orgID' is not null or undefined + assertParamExists('uninstallOrgWebhook', 'orgID', orgID) + const localVarPath = `/organizations/{orgID}/webhook` + .replace(`{${"orgID"}}`, encodeURIComponent(String(orgID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Uninstall organization webhook. + * @param {string} repoID Repository ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallRepoWebhook: async (repoID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'repoID' is not null or undefined + assertParamExists('uninstallRepoWebhook', 'repoID', repoID) + const localVarPath = `/repositories/{repoID}/webhook` + .replace(`{${"repoID"}}`, encodeURIComponent(String(repoID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * HooksApi - functional programming interface + * @export + */ +export const HooksApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = HooksApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getForgeInstanceWebhookInfo(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['HooksApi.getForgeInstanceWebhookInfo']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get information about the GARM installed webhook on an organization. + * @param {string} orgID Organization ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getOrgWebhookInfo(orgID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getOrgWebhookInfo(orgID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['HooksApi.getOrgWebhookInfo']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get information about the GARM installed webhook on a repository. + * @param {string} repoID Repository ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getRepoWebhookInfo(repoID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getRepoWebhookInfo(repoID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['HooksApi.getRepoWebhookInfo']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.installForgeInstanceWebhook(forgeInstanceID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['HooksApi.installForgeInstanceWebhook']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. + * @param {string} orgID Organization ID. + * @param {InstallWebhookParams} body Parameters used when creating the organization webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} */ async installOrgWebhook(orgID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.installOrgWebhook(orgID, body, options); @@ -6766,6 +8159,19 @@ export const HooksApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['HooksApi.installRepoWebhook']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.uninstallForgeInstanceWebhook(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['HooksApi.uninstallForgeInstanceWebhook']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary Uninstall organization webhook. @@ -6802,6 +8208,16 @@ export const HooksApiFp = function(configuration?: Configuration) { export const HooksApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = HooksApiFp(configuration) return { + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getForgeInstanceWebhookInfo(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, /** * * @summary Get information about the GARM installed webhook on an organization. @@ -6822,6 +8238,16 @@ export const HooksApiFactory = function (configuration?: Configuration, basePath getRepoWebhookInfo(repoID: string, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.getRepoWebhookInfo(repoID, options).then((request) => request(axios, basePath)); }, + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.installForgeInstanceWebhook(forgeInstanceID, body, options).then((request) => request(axios, basePath)); + }, /** * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. * @param {string} orgID Organization ID. @@ -6842,6 +8268,16 @@ export const HooksApiFactory = function (configuration?: Configuration, basePath installRepoWebhook(repoID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.installRepoWebhook(repoID, body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.uninstallForgeInstanceWebhook(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, /** * * @summary Uninstall organization webhook. @@ -6872,6 +8308,18 @@ export const HooksApiFactory = function (configuration?: Configuration, basePath * @extends {BaseAPI} */ export class HooksApi extends BaseAPI { + /** + * + * @summary Get information about the GARM installed webhook on a forge instance. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof HooksApi + */ + public getForgeInstanceWebhookInfo(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return HooksApiFp(this.configuration).getForgeInstanceWebhookInfo(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Get information about the GARM installed webhook on an organization. @@ -6896,6 +8344,18 @@ export class HooksApi extends BaseAPI { return HooksApiFp(this.configuration).getRepoWebhookInfo(repoID, options).then((request) => request(this.axios, this.basePath)); } + /** + * Install the GARM webhook for a forge instance. The secret configured on the forge instance will be used to validate the requests. + * @param {string} forgeInstanceID Forge instance ID. + * @param {InstallWebhookParams} body Parameters used when creating the forge instance webhook. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof HooksApi + */ + public installForgeInstanceWebhook(forgeInstanceID: string, body: InstallWebhookParams, options?: RawAxiosRequestConfig) { + return HooksApiFp(this.configuration).installForgeInstanceWebhook(forgeInstanceID, body, options).then((request) => request(this.axios, this.basePath)); + } + /** * Install the GARM webhook for an organization. The secret configured on the organization will be used to validate the requests. * @param {string} orgID Organization ID. @@ -6920,6 +8380,18 @@ export class HooksApi extends BaseAPI { return HooksApiFp(this.configuration).installRepoWebhook(repoID, body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Uninstall forge instance webhook. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof HooksApi + */ + public uninstallForgeInstanceWebhook(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return HooksApiFp(this.configuration).uninstallForgeInstanceWebhook(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Uninstall organization webhook. @@ -9541,19 +11013,62 @@ export const PoolsApiAxiosParamCreator = function (configuration?: Configuration return { /** * - * @summary Create enterprise pool with the parameters given. - * @param {string} enterpriseID Enterprise ID. - * @param {CreatePoolParams} body Parameters used when creating the enterprise pool. + * @summary Create enterprise pool with the parameters given. + * @param {string} enterpriseID Enterprise ID. + * @param {CreatePoolParams} body Parameters used when creating the enterprise pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createEnterprisePool: async (enterpriseID: string, body: CreatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'enterpriseID' is not null or undefined + assertParamExists('createEnterprisePool', 'enterpriseID', enterpriseID) + // verify required parameter 'body' is not null or undefined + assertParamExists('createEnterprisePool', 'body', body) + const localVarPath = `/enterprises/{enterpriseID}/pools` + .replace(`{${"enterpriseID"}}`, encodeURIComponent(String(enterpriseID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - createEnterprisePool: async (enterpriseID: string, body: CreatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'enterpriseID' is not null or undefined - assertParamExists('createEnterprisePool', 'enterpriseID', enterpriseID) + createForgeInstancePool: async (forgeInstanceID: string, body: CreatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('createForgeInstancePool', 'forgeInstanceID', forgeInstanceID) // verify required parameter 'body' is not null or undefined - assertParamExists('createEnterprisePool', 'body', body) - const localVarPath = `/enterprises/{enterpriseID}/pools` - .replace(`{${"enterpriseID"}}`, encodeURIComponent(String(enterpriseID))); + assertParamExists('createForgeInstancePool', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -9700,6 +11215,47 @@ export const PoolsApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteForgeInstancePool: async (forgeInstanceID: string, poolID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('deleteForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('deleteForgeInstancePool', 'poolID', poolID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -9860,6 +11416,47 @@ export const PoolsApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstancePool: async (forgeInstanceID: string, poolID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('getForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('getForgeInstancePool', 'poolID', poolID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -10016,6 +11613,43 @@ export const PoolsApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstancePools: async (forgeInstanceID: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('listForgeInstancePools', 'forgeInstanceID', forgeInstanceID) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -10167,6 +11801,53 @@ export const PoolsApiAxiosParamCreator = function (configuration?: Configuration + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstancePool: async (forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'forgeInstanceID' is not null or undefined + assertParamExists('updateForgeInstancePool', 'forgeInstanceID', forgeInstanceID) + // verify required parameter 'poolID' is not null or undefined + assertParamExists('updateForgeInstancePool', 'poolID', poolID) + // verify required parameter 'body' is not null or undefined + assertParamExists('updateForgeInstancePool', 'body', body) + const localVarPath = `/forge-instances/{forgeInstanceID}/pools/{poolID}` + .replace(`{${"forgeInstanceID"}}`, encodeURIComponent(String(forgeInstanceID))) + .replace(`{${"poolID"}}`, encodeURIComponent(String(poolID))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + localVarHeaderParameter['Content-Type'] = 'application/json'; setSearchParams(localVarUrlObj, localVarQueryParameter); @@ -10340,6 +12021,20 @@ export const PoolsApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['PoolsApi.createEnterprisePool']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createForgeInstancePool(forgeInstanceID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['PoolsApi.createForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary Create organization pool with the parameters given. @@ -10382,6 +12077,20 @@ export const PoolsApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['PoolsApi.deleteEnterprisePool']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteForgeInstancePool(forgeInstanceID, poolID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['PoolsApi.deleteForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary Delete organization pool by ID. @@ -10437,6 +12146,20 @@ export const PoolsApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['PoolsApi.getEnterprisePool']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getForgeInstancePool(forgeInstanceID, poolID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['PoolsApi.getForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary Get organization pool by ID. @@ -10491,6 +12214,19 @@ export const PoolsApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['PoolsApi.listEnterprisePools']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listForgeInstancePools(forgeInstanceID, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['PoolsApi.listForgeInstancePools']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary List organization pools. @@ -10544,6 +12280,21 @@ export const PoolsApiFp = function(configuration?: Configuration) { const localVarOperationServerBasePath = operationServerMap['PoolsApi.updateEnterprisePool']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateForgeInstancePool(forgeInstanceID, poolID, body, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['PoolsApi.updateForgeInstancePool']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, /** * * @summary Update organization pool with the parameters given. @@ -10609,6 +12360,17 @@ export const PoolsApiFactory = function (configuration?: Configuration, basePath createEnterprisePool(enterpriseID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.createEnterprisePool(enterpriseID, body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createForgeInstancePool(forgeInstanceID, body, options).then((request) => request(axios, basePath)); + }, /** * * @summary Create organization pool with the parameters given. @@ -10642,6 +12404,17 @@ export const PoolsApiFactory = function (configuration?: Configuration, basePath deleteEnterprisePool(enterpriseID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.deleteEnterprisePool(enterpriseID, poolID, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.deleteForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(axios, basePath)); + }, /** * * @summary Delete organization pool by ID. @@ -10685,6 +12458,17 @@ export const PoolsApiFactory = function (configuration?: Configuration, basePath getEnterprisePool(enterpriseID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.getEnterprisePool(enterpriseID, poolID, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(axios, basePath)); + }, /** * * @summary Get organization pool by ID. @@ -10727,6 +12511,16 @@ export const PoolsApiFactory = function (configuration?: Configuration, basePath listEnterprisePools(enterpriseID: string, options?: RawAxiosRequestConfig): AxiosPromise> { return localVarFp.listEnterprisePools(enterpriseID, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listForgeInstancePools(forgeInstanceID, options).then((request) => request(axios, basePath)); + }, /** * * @summary List organization pools. @@ -10768,6 +12562,18 @@ export const PoolsApiFactory = function (configuration?: Configuration, basePath updateEnterprisePool(enterpriseID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.updateEnterprisePool(enterpriseID, poolID, body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.updateForgeInstancePool(forgeInstanceID, poolID, body, options).then((request) => request(axios, basePath)); + }, /** * * @summary Update organization pool with the parameters given. @@ -10826,6 +12632,19 @@ export class PoolsApi extends BaseAPI { return PoolsApiFp(this.configuration).createEnterprisePool(enterpriseID, body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Create forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {CreatePoolParams} body Parameters used when creating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PoolsApi + */ + public createForgeInstancePool(forgeInstanceID: string, body: CreatePoolParams, options?: RawAxiosRequestConfig) { + return PoolsApiFp(this.configuration).createForgeInstancePool(forgeInstanceID, body, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Create organization pool with the parameters given. @@ -10865,6 +12684,19 @@ export class PoolsApi extends BaseAPI { return PoolsApiFp(this.configuration).deleteEnterprisePool(enterpriseID, poolID, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Delete forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to delete. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PoolsApi + */ + public deleteForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig) { + return PoolsApiFp(this.configuration).deleteForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Delete organization pool by ID. @@ -10916,6 +12748,19 @@ export class PoolsApi extends BaseAPI { return PoolsApiFp(this.configuration).getEnterprisePool(enterpriseID, poolID, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get forge instance pool by ID. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID Pool ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PoolsApi + */ + public getForgeInstancePool(forgeInstanceID: string, poolID: string, options?: RawAxiosRequestConfig) { + return PoolsApiFp(this.configuration).getForgeInstancePool(forgeInstanceID, poolID, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Get organization pool by ID. @@ -10966,6 +12811,18 @@ export class PoolsApi extends BaseAPI { return PoolsApiFp(this.configuration).listEnterprisePools(enterpriseID, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary List forge instance pools. + * @param {string} forgeInstanceID Forge instance ID. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PoolsApi + */ + public listForgeInstancePools(forgeInstanceID: string, options?: RawAxiosRequestConfig) { + return PoolsApiFp(this.configuration).listForgeInstancePools(forgeInstanceID, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary List organization pools. @@ -11015,6 +12872,20 @@ export class PoolsApi extends BaseAPI { return PoolsApiFp(this.configuration).updateEnterprisePool(enterpriseID, poolID, body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Update forge instance pool with the parameters given. + * @param {string} forgeInstanceID Forge instance ID. + * @param {string} poolID ID of the forge instance pool to update. + * @param {UpdatePoolParams} body Parameters used when updating the forge instance pool. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PoolsApi + */ + public updateForgeInstancePool(forgeInstanceID: string, poolID: string, body: UpdatePoolParams, options?: RawAxiosRequestConfig) { + return PoolsApiFp(this.configuration).updateForgeInstancePool(forgeInstanceID, poolID, body, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Update organization pool with the parameters given. diff --git a/webapp/src/lib/components/CreateForgeInstanceModal.svelte b/webapp/src/lib/components/CreateForgeInstanceModal.svelte new file mode 100644 index 000000000..387804b55 --- /dev/null +++ b/webapp/src/lib/components/CreateForgeInstanceModal.svelte @@ -0,0 +1,183 @@ + + + dispatch('close')}> +
+

Create Forge Instance

+

+ Create an instance-level runner pool target for a Gitea server. +

+ + {#if error} +
+

{error}

+
+ {/if} + + {#if loading} +
+
+

Creating...

+
+ {:else} +
+ +
+ + {#if giteaEndpoints.length === 0} +

No Gitea endpoints configured. Please create one first.

+ {:else} + + {/if} +
+ + + + +
+ + +
+ + {/if} +
+
diff --git a/webapp/src/lib/components/CreatePoolModal.svelte b/webapp/src/lib/components/CreatePoolModal.svelte index 8e771750a..c9654819e 100644 --- a/webapp/src/lib/components/CreatePoolModal.svelte +++ b/webapp/src/lib/components/CreatePoolModal.svelte @@ -24,7 +24,7 @@ }>(); // Export props for pre-populating the modal - export let initialEntityType: 'repository' | 'organization' | 'enterprise' | '' = ''; + export let initialEntityType: 'repository' | 'organization' | 'enterprise' | 'forge_instance' | '' = ''; export let initialEntityId: string = ''; let loading = false; @@ -128,6 +128,9 @@ case 'enterprise': entities = await garmApi.listEnterprises(); break; + case 'forge_instance': + entities = await garmApi.listForgeInstances(); + break; } } catch (err) { error = extractAPIError(err); @@ -136,7 +139,7 @@ } } - function selectEntityLevel(level: 'repository' | 'organization' | 'enterprise') { + function selectEntityLevel(level: 'repository' | 'organization' | 'enterprise' | 'forge_instance') { if (entityLevel === level) return; entityLevel = level; selectedEntityId = ''; @@ -267,6 +270,9 @@ case 'enterprise': await garmApi.createEnterprisePool(selectedEntityId, params); break; + case 'forge_instance': + await garmApi.createForgeInstancePool(selectedEntityId, params); + break; default: throw new Error('Invalid entity level'); } @@ -297,12 +303,12 @@ }); // Re-subscribe when entity level changes - $: if (entityLevel && (entityLevel === 'repository' || entityLevel === 'organization' || entityLevel === 'enterprise')) { + $: if (entityLevel && (entityLevel === 'repository' || entityLevel === 'organization' || entityLevel === 'enterprise' || entityLevel === 'forge_instance')) { if (unsubscribeWebsocket) { unsubscribeWebsocket(); } unsubscribeWebsocket = websocketStore.subscribeToEntity( - entityLevel as 'repository' | 'organization' | 'enterprise', + entityLevel as 'repository' | 'organization' | 'enterprise' | 'forge_instance', ['update'], handleEntityWebSocketEvent ); @@ -359,6 +365,16 @@ Enterprise + @@ -387,6 +403,8 @@