Added more CLI commands and API endpoints
This commit is contained in:
parent
1e2e96ccb5
commit
d9c65872e8
24 changed files with 901 additions and 116 deletions
|
|
@ -27,7 +27,7 @@ func (a *APIController) ListPoolInstancesHandler(w http.ResponseWriter, r *http.
|
|||
|
||||
instances, err := a.r.ListPoolInstances(ctx, poolID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
log.Printf("listing pool instances: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
|
@ -60,6 +60,68 @@ func (a *APIController) GetInstanceHandler(w http.ResponseWriter, r *http.Reques
|
|||
json.NewEncoder(w).Encode(instance)
|
||||
}
|
||||
|
||||
func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
repoID, ok := vars["repoID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No repo ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListRepoInstances(ctx, repoID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
orgID, ok := vars["orgID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No org ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListOrgInstances(ctx, orgID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) ListAllInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
instances, err := a.r.ListAllInstances(ctx)
|
||||
if err != nil {
|
||||
log.Printf("listing instances: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) InstanceStatusMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
|
|
|
|||
|
|
@ -266,27 +266,3 @@ func (a *APIController) UpdateOrgPoolHandler(w http.ResponseWriter, r *http.Requ
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
orgID, ok := vars["orgID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No org ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListOrgInstances(ctx, orgID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
|
|
|||
111
apiserver/controllers/pools.go
Normal file
111
apiserver/controllers/pools.go
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"garm/apiserver/params"
|
||||
gErrors "garm/errors"
|
||||
runnerParams "garm/params"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (a *APIController) ListAllPoolsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
pools, err := a.r.ListAllPools(ctx)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pools)
|
||||
}
|
||||
|
||||
func (a *APIController) GetPoolByIDHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
poolID, ok := vars["poolID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.r.GetPoolByID(ctx, poolID)
|
||||
if err != nil {
|
||||
log.Printf("fetching pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) DeletePoolByIDHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
poolID, ok := vars["poolID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.r.DeletePoolByID(ctx, poolID); err != nil {
|
||||
log.Printf("removing pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
}
|
||||
|
||||
func (a *APIController) UpdatePoolByIDHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
poolID, ok := vars["poolID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var poolData runnerParams.UpdatePoolParams
|
||||
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
|
||||
log.Printf("failed to decode: %s", err)
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.r.UpdatePoolByID(ctx, poolID, poolData)
|
||||
if err != nil {
|
||||
log.Printf("fetching pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
|
||||
}
|
||||
|
|
@ -266,27 +266,3 @@ func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Req
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
repoID, ok := vars["repoID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No repo ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListRepoInstances(ctx, repoID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,16 +42,34 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
apiRouter.Use(initMiddleware.Middleware)
|
||||
apiRouter.Use(authMiddleware.Middleware)
|
||||
|
||||
// Runners (instances)
|
||||
///////////
|
||||
// Pools //
|
||||
///////////
|
||||
// List all pools
|
||||
apiRouter.Handle("/pools/", log(os.Stdout, http.HandlerFunc(han.ListAllPoolsHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools", log(os.Stdout, http.HandlerFunc(han.ListAllPoolsHandler))).Methods("GET", "OPTIONS")
|
||||
// Get one pool
|
||||
apiRouter.Handle("/pools/{poolID}/", log(os.Stdout, http.HandlerFunc(han.GetPoolByIDHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools/{poolID}", log(os.Stdout, http.HandlerFunc(han.GetPoolByIDHandler))).Methods("GET", "OPTIONS")
|
||||
// Delete one pool
|
||||
apiRouter.Handle("/pools/{poolID}/", log(os.Stdout, http.HandlerFunc(han.DeletePoolByIDHandler))).Methods("DELETE", "OPTIONS")
|
||||
apiRouter.Handle("/pools/{poolID}", log(os.Stdout, http.HandlerFunc(han.DeletePoolByIDHandler))).Methods("DELETE", "OPTIONS")
|
||||
// Update one pool
|
||||
apiRouter.Handle("/pools/{poolID}/", log(os.Stdout, http.HandlerFunc(han.UpdatePoolByIDHandler))).Methods("PUT", "OPTIONS")
|
||||
apiRouter.Handle("/pools/{poolID}", log(os.Stdout, http.HandlerFunc(han.UpdatePoolByIDHandler))).Methods("PUT", "OPTIONS")
|
||||
// List pool instances
|
||||
apiRouter.Handle("/pools/instances/{poolID}/", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools/instances/{poolID}", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools/{poolID}/instances/", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools/{poolID}/instances", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
|
||||
/////////////
|
||||
// Runners //
|
||||
/////////////
|
||||
// List runners
|
||||
apiRouter.Handle("/instances/", log(os.Stdout, http.HandlerFunc(han.ListAllInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/instances", log(os.Stdout, http.HandlerFunc(han.ListAllInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
// Get instance
|
||||
apiRouter.Handle("/instances/{instanceName}/", log(os.Stdout, http.HandlerFunc(han.GetInstanceHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/instances/{instanceName}", log(os.Stdout, http.HandlerFunc(han.GetInstanceHandler))).Methods("GET", "OPTIONS")
|
||||
// Delete instance
|
||||
// apiRouter.Handle("/instances/{instanceName}/", log(os.Stdout, http.HandlerFunc(han.CatchAll))).Methods("DELETE", "OPTIONS")
|
||||
// apiRouter.Handle("/instances/{instanceName}", log(os.Stdout, http.HandlerFunc(han.CatchAll))).Methods("DELETE", "OPTIONS")
|
||||
|
||||
/////////////////////
|
||||
// Repos and pools //
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ func (c *Client) GetInstanceByName(instanceName string) (params.Instance, error)
|
|||
}
|
||||
|
||||
func (c *Client) ListPoolInstances(poolID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/instances/%s", c.Config.BaseURL, poolID)
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s/instances", c.Config.BaseURL, poolID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
|
|
@ -153,3 +153,90 @@ func (c *Client) ListPoolInstances(poolID string) ([]params.Instance, error) {
|
|||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllInstances() ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/instances", c.Config.BaseURL)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetPoolByID(poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllPools() ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools", c.Config.BaseURL)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeletePoolByID(poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error deleting pool by ID: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdatePoolByID(poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ var orgPoolAddCmd = &cobra.Command{
|
|||
Use: "add",
|
||||
Aliases: []string{"create"},
|
||||
Short: "Add pool",
|
||||
Long: `Add a new pool organization to the manager.`,
|
||||
Long: `Add a new pool to an organization.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
|
|
|
|||
297
cmd/garm-cli/cmd/pool.go
Normal file
297
cmd/garm-cli/cmd/pool.go
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"garm/config"
|
||||
"garm/params"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
poolRepository string
|
||||
poolOrganization string
|
||||
poolAll bool
|
||||
)
|
||||
|
||||
// runnerCmd represents the runner command
|
||||
var poolCmd = &cobra.Command{
|
||||
Use: "pool",
|
||||
SilenceUsage: true,
|
||||
Short: "List pools",
|
||||
Long: `Query information or perform operations on pools.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
var poolListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List pools",
|
||||
Long: `List pools of repositories, orgs or all of the above.
|
||||
|
||||
This command will list pools from one repo, one org or all pools
|
||||
on the system. The list flags are mutually exclusive. You must however
|
||||
specify one of them.
|
||||
|
||||
Example:
|
||||
|
||||
List pools from one repo:
|
||||
garm-cli pool list --repo=05e7eac6-4705-486d-89c9-0170bbb576af
|
||||
|
||||
List pools from one org:
|
||||
garm-cli pool list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
|
||||
|
||||
List all pools from all repos and orgs:
|
||||
garm-cli pool list --all
|
||||
|
||||
`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
var pools []params.Pool
|
||||
var err error
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
if cmd.Flags().Changed("repo") {
|
||||
pools, err = cli.ListRepoPools(poolRepository)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pools, err = cli.ListOrgPools(poolOrganization)
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
pools, err = cli.ListAllPools()
|
||||
} else {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
}
|
||||
default:
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatPools(pools)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var poolShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show details for a runner",
|
||||
Long: `Displays a detailed view of a single runner.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a pool ID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
pool, err := cli.GetPoolByID(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOnePool(pool)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var poolDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Delete pool by ID",
|
||||
Long: `Delete one pool by referencing it's ID, regardless of repo or org.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a pool ID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
if err := cli.DeletePoolByID(args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var poolAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Aliases: []string{"create"},
|
||||
Short: "Add pool",
|
||||
Long: `Add a new pool to a repository or organization.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
tags := strings.Split(poolTags, ",")
|
||||
newPoolParams := params.CreatePoolParams{
|
||||
ProviderName: poolProvider,
|
||||
MaxRunners: poolMaxRunners,
|
||||
MinIdleRunners: poolMinIdleRunners,
|
||||
Image: poolImage,
|
||||
Flavor: poolFlavor,
|
||||
OSType: config.OSType(poolOSType),
|
||||
OSArch: config.OSArch(poolOSArch),
|
||||
Tags: tags,
|
||||
Enabled: poolEnabled,
|
||||
}
|
||||
if err := newPoolParams.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pool params.Pool
|
||||
var err error
|
||||
|
||||
if cmd.Flags().Changed("repo") {
|
||||
pool, err = cli.CreateRepoPool(poolRepository, newPoolParams)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pool, err = cli.CreateOrgPool(poolOrganization, newPoolParams)
|
||||
} else {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOnePool(pool)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var poolUpdateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update one pool",
|
||||
Long: `Updates pool characteristics.
|
||||
|
||||
This command updates the pool characteristics. Runners already created prior to updating
|
||||
the pool, will not be recreated. IF they no longer suit your needs, you will need to
|
||||
explicitly remove them using the runner delete command.
|
||||
`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("command requires a poolID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
poolUpdateParams := params.UpdatePoolParams{}
|
||||
|
||||
if cmd.Flags().Changed("image") {
|
||||
poolUpdateParams.Image = poolImage
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("flavor") {
|
||||
poolUpdateParams.Flavor = poolFlavor
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("tags") {
|
||||
poolUpdateParams.Tags = strings.Split(poolTags, ",")
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("os-type") {
|
||||
poolUpdateParams.OSType = config.OSType(poolOSType)
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("os-arch") {
|
||||
poolUpdateParams.OSArch = config.OSArch(poolOSArch)
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("max-runners") {
|
||||
poolUpdateParams.MaxRunners = &poolMaxRunners
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("min-idle-runners") {
|
||||
poolUpdateParams.MinIdleRunners = &poolMinIdleRunners
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("enabled") {
|
||||
poolUpdateParams.Enabled = &poolEnabled
|
||||
}
|
||||
|
||||
pool, err := cli.UpdatePoolByID(args[0], poolUpdateParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
formatOnePool(pool)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
poolListCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "List all pools within this repository.")
|
||||
poolListCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "List all pools withing this organization.")
|
||||
poolListCmd.Flags().BoolVarP(&poolAll, "all", "a", false, "List all pools, regardless of org or repo.")
|
||||
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
|
||||
|
||||
poolUpdateCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
poolUpdateCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
poolUpdateCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
poolUpdateCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
poolUpdateCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
|
||||
poolAddCmd.Flags().StringVar(&poolProvider, "provider-name", "", "The name of the provider where runners will be created.")
|
||||
poolAddCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
poolAddCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
poolAddCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
poolAddCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
poolAddCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
poolAddCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
poolAddCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
poolAddCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
poolAddCmd.MarkFlagRequired("provider-name")
|
||||
poolAddCmd.MarkFlagRequired("image")
|
||||
poolAddCmd.MarkFlagRequired("flavor")
|
||||
poolAddCmd.MarkFlagRequired("tags")
|
||||
|
||||
poolAddCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "Add the new pool within this repository.")
|
||||
poolAddCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "Add the new pool withing this organization.")
|
||||
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org")
|
||||
|
||||
poolCmd.AddCommand(
|
||||
poolListCmd,
|
||||
poolShowCmd,
|
||||
poolDeleteCmd,
|
||||
poolUpdateCmd,
|
||||
poolAddCmd,
|
||||
)
|
||||
|
||||
rootCmd.AddCommand(poolCmd)
|
||||
}
|
||||
|
|
@ -43,11 +43,11 @@ spin up instances with access to a GPU, on the desired provider.`,
|
|||
Run: nil,
|
||||
}
|
||||
|
||||
var poolAddCmd = &cobra.Command{
|
||||
var repoPoolAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Aliases: []string{"create"},
|
||||
Short: "Add pool",
|
||||
Long: `Add a new pool repository to the manager.`,
|
||||
Long: `Add a new pool to a repository.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
|
|
@ -86,7 +86,7 @@ var poolAddCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var poolListCmd = &cobra.Command{
|
||||
var repoPoolListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List repository pools",
|
||||
|
|
@ -114,7 +114,7 @@ var poolListCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var poolShowCmd = &cobra.Command{
|
||||
var repoPoolShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show details for one pool",
|
||||
Long: `Displays detailed information about a single pool.`,
|
||||
|
|
@ -137,7 +137,7 @@ var poolShowCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var poolDeleteCmd = &cobra.Command{
|
||||
var repoPoolDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Removes one pool",
|
||||
|
|
@ -158,7 +158,7 @@ var poolDeleteCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var poolUpdateCmd = &cobra.Command{
|
||||
var repoPoolUpdateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update one pool",
|
||||
Long: `Updates pool characteristics.
|
||||
|
|
@ -222,35 +222,35 @@ explicitly remove them using the runner delete command.
|
|||
}
|
||||
|
||||
func init() {
|
||||
poolAddCmd.Flags().StringVar(&poolProvider, "provider-name", "", "The name of the provider where runners will be created.")
|
||||
poolAddCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
poolAddCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
poolAddCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
poolAddCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
poolAddCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
poolAddCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
poolAddCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
poolAddCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
poolAddCmd.MarkFlagRequired("provider-name")
|
||||
poolAddCmd.MarkFlagRequired("image")
|
||||
poolAddCmd.MarkFlagRequired("flavor")
|
||||
poolAddCmd.MarkFlagRequired("tags")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolProvider, "provider-name", "", "The name of the provider where runners will be created.")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
repoPoolAddCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
repoPoolAddCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
repoPoolAddCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
repoPoolAddCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
repoPoolAddCmd.MarkFlagRequired("provider-name")
|
||||
repoPoolAddCmd.MarkFlagRequired("image")
|
||||
repoPoolAddCmd.MarkFlagRequired("flavor")
|
||||
repoPoolAddCmd.MarkFlagRequired("tags")
|
||||
|
||||
poolUpdateCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
poolUpdateCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
poolUpdateCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
poolUpdateCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
poolUpdateCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
repoPoolUpdateCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
repoPoolUpdateCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
repoPoolUpdateCmd.Flags().StringVar(&poolTags, "tags", "", "A comma separated list of tags to assign to this runner.")
|
||||
repoPoolUpdateCmd.Flags().StringVar(&poolOSType, "os-type", "linux", "Operating system type (windows, linux, etc).")
|
||||
repoPoolUpdateCmd.Flags().StringVar(&poolOSArch, "os-arch", "amd64", "Operating system architecture (amd64, arm, etc).")
|
||||
repoPoolUpdateCmd.Flags().UintVar(&poolMaxRunners, "max-runners", 5, "The maximum number of runner this pool will create.")
|
||||
repoPoolUpdateCmd.Flags().UintVar(&poolMinIdleRunners, "min-idle-runners", 1, "Attempt to maintain a minimum of idle self-hosted runners of this type.")
|
||||
repoPoolUpdateCmd.Flags().BoolVar(&poolEnabled, "enabled", false, "Enable this pool.")
|
||||
|
||||
repoPoolCmd.AddCommand(
|
||||
poolListCmd,
|
||||
poolAddCmd,
|
||||
poolShowCmd,
|
||||
poolDeleteCmd,
|
||||
poolUpdateCmd,
|
||||
repoPoolAddCmd,
|
||||
repoPoolShowCmd,
|
||||
repoPoolDeleteCmd,
|
||||
repoPoolUpdateCmd,
|
||||
)
|
||||
|
||||
repositoryCmd.AddCommand(repoPoolCmd)
|
||||
|
|
@ -258,7 +258,7 @@ func init() {
|
|||
|
||||
func formatPools(pools []params.Pool) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"ID", "Image", "Flavor", "Tags", "Enabled"}
|
||||
header := table.Row{"ID", "Image", "Flavor", "Tags", "Belongs to", "Level", "Enabled"}
|
||||
t.AppendHeader(header)
|
||||
|
||||
for _, pool := range pools {
|
||||
|
|
@ -266,7 +266,17 @@ func formatPools(pools []params.Pool) {
|
|||
for _, tag := range pool.Tags {
|
||||
tags = append(tags, tag.Name)
|
||||
}
|
||||
t.AppendRow(table.Row{pool.ID, pool.Image, pool.Flavor, strings.Join(tags, " "), pool.Enabled})
|
||||
var belongsTo string
|
||||
var level string
|
||||
|
||||
if pool.RepoID != "" && pool.RepoName != "" {
|
||||
belongsTo = pool.RepoName
|
||||
level = "repo"
|
||||
} else if pool.OrgID != "" && pool.OrgName != "" {
|
||||
belongsTo = pool.OrgName
|
||||
level = "org"
|
||||
}
|
||||
t.AppendRow(table.Row{pool.ID, pool.Image, pool.Flavor, strings.Join(tags, " "), belongsTo, level, pool.Enabled})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
|
|
@ -283,6 +293,17 @@ func formatOnePool(pool params.Pool) {
|
|||
tags = append(tags, tag.Name)
|
||||
}
|
||||
|
||||
var belongsTo string
|
||||
var level string
|
||||
|
||||
if pool.RepoID != "" && pool.RepoName != "" {
|
||||
belongsTo = pool.RepoName
|
||||
level = "repo"
|
||||
} else if pool.OrgID != "" && pool.OrgName != "" {
|
||||
belongsTo = pool.OrgName
|
||||
level = "org"
|
||||
}
|
||||
|
||||
t.AppendHeader(header)
|
||||
t.AppendRow(table.Row{"ID", pool.ID})
|
||||
t.AppendRow(table.Row{"Provider Name", pool.ProviderName})
|
||||
|
|
@ -293,6 +314,8 @@ func formatOnePool(pool params.Pool) {
|
|||
t.AppendRow(table.Row{"Max Runners", pool.MaxRunners})
|
||||
t.AppendRow(table.Row{"Min Idle Runners", pool.MinIdleRunners})
|
||||
t.AppendRow(table.Row{"Tags", strings.Join(tags, ", ")})
|
||||
t.AppendRow(table.Row{"Belongs to", belongsTo})
|
||||
t.AppendRow(table.Row{"Level", level})
|
||||
t.AppendRow(table.Row{"Enabled", pool.Enabled})
|
||||
|
||||
if len(pool.Instances) > 0 {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,22 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"garm/params"
|
||||
"os"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
runnerRepository string
|
||||
runnerOrganization string
|
||||
runnerAll bool
|
||||
)
|
||||
|
||||
// runnerCmd represents the runner command
|
||||
var runnerCmd = &cobra.Command{
|
||||
Use: "runner",
|
||||
Aliases: []string{"run"},
|
||||
SilenceUsage: true,
|
||||
Short: "List runners in a pool",
|
||||
Long: `Given a pool ID, of either a repository or an organization,
|
||||
|
|
@ -23,25 +31,63 @@ list all instances.`,
|
|||
}
|
||||
|
||||
var runnerListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List pool runners",
|
||||
Long: `List all configured pools for a given repository.`,
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List runners",
|
||||
Long: `List runners of pools, repositories, orgs or all of the above.
|
||||
|
||||
This command expects to get either a pool ID as a positional parameter, or it expects
|
||||
that one of the supported switches be used to fetch runners of --repo, --org or --all
|
||||
|
||||
Example:
|
||||
|
||||
List runners from one pool:
|
||||
garm-cli runner list e87e70bd-3d0d-4b25-be9a-86b85e114bcb
|
||||
|
||||
List runners from one repo:
|
||||
garm-cli runner list --repo=05e7eac6-4705-486d-89c9-0170bbb576af
|
||||
|
||||
List runners from one org:
|
||||
garm-cli runner list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
|
||||
|
||||
List all runners from all pools belonging to all repos and orgs:
|
||||
garm-cli runner list --all
|
||||
|
||||
`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a pool ID")
|
||||
var instances []params.Instance
|
||||
var err error
|
||||
|
||||
switch len(args) {
|
||||
case 1:
|
||||
if cmd.Flags().Changed("repo") ||
|
||||
cmd.Flags().Changed("org") ||
|
||||
cmd.Flags().Changed("all") {
|
||||
|
||||
return fmt.Errorf("specifying a pool ID and any of [all org repo] are mutually exclusive")
|
||||
}
|
||||
instances, err = cli.ListPoolInstances(args[0])
|
||||
case 0:
|
||||
if cmd.Flags().Changed("repo") {
|
||||
instances, err = cli.ListRepoInstances(runnerRepository)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
instances, err = cli.ListOrgInstances(runnerOrganization)
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
instances, err = cli.ListAllInstances()
|
||||
} else {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
}
|
||||
default:
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
instances, err := cli.ListPoolInstances(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -78,6 +124,11 @@ var runnerShowCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func init() {
|
||||
runnerListCmd.Flags().StringVarP(&runnerRepository, "repo", "r", "", "List all runners from all pools within this repository.")
|
||||
runnerListCmd.Flags().StringVarP(&runnerOrganization, "org", "o", "", "List all runners from all pools withing this organization.")
|
||||
runnerListCmd.Flags().BoolVarP(&runnerAll, "all", "a", false, "List all runners, regardless of org or repo.")
|
||||
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
|
||||
|
||||
runnerCmd.AddCommand(
|
||||
runnerListCmd,
|
||||
runnerShowCmd,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ type Store interface {
|
|||
|
||||
ListRepoPools(ctx context.Context, repoID string) ([]params.Pool, error)
|
||||
ListOrgPools(ctx context.Context, orgID string) ([]params.Pool, error)
|
||||
// Probably a bad idea without some king of filter or at least pagination
|
||||
// TODO: add filter/pagination
|
||||
ListAllPools(ctx context.Context) ([]params.Pool, error)
|
||||
GetPoolByID(ctx context.Context, poolID string) (params.Pool, error)
|
||||
DeletePoolByID(ctx context.Context, poolID string) error
|
||||
|
||||
DeleteRepositoryPool(ctx context.Context, repoID, poolID string) error
|
||||
DeleteOrganizationPool(ctx context.Context, orgID, poolID string) error
|
||||
|
|
@ -42,10 +47,14 @@ type Store interface {
|
|||
DeleteInstance(ctx context.Context, poolID string, instanceID string) error
|
||||
UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error)
|
||||
|
||||
ListInstances(ctx context.Context, poolID string) ([]params.Instance, error)
|
||||
ListPoolInstances(ctx context.Context, poolID string) ([]params.Instance, error)
|
||||
ListRepoInstances(ctx context.Context, repoID string) ([]params.Instance, error)
|
||||
ListOrgInstances(ctx context.Context, orgID string) ([]params.Instance, error)
|
||||
|
||||
// Probably a bad idea without some king of filter or at least pagination
|
||||
// TODO: add filter/pagination
|
||||
ListAllInstances(ctx context.Context) ([]params.Instance, error)
|
||||
|
||||
GetPoolInstanceByName(ctx context.Context, poolID string, instanceName string) (params.Instance, error)
|
||||
GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error)
|
||||
AddInstanceStatusMessage(ctx context.Context, instanceID string, statusMessage string) error
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceID string, par
|
|||
return s.sqlToParamsInstance(instance), nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListInstances(ctx context.Context, poolID string) ([]params.Instance, error) {
|
||||
func (s *sqlDatabase) ListPoolInstances(ctx context.Context, poolID string) ([]params.Instance, error) {
|
||||
pool, err := s.getPoolByID(ctx, poolID, "Tags", "Instances")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pool")
|
||||
|
|
@ -194,3 +194,17 @@ func (s *sqlDatabase) ListInstances(ctx context.Context, poolID string) ([]param
|
|||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListAllInstances(ctx context.Context) ([]params.Instance, error) {
|
||||
var instances []Instance
|
||||
|
||||
q := s.conn.Model(&Instance{}).Find(&instances)
|
||||
if q.Error != nil {
|
||||
return nil, errors.Wrap(q.Error, "fetching instances")
|
||||
}
|
||||
ret := make([]params.Instance, len(instances))
|
||||
for idx, instance := range instances {
|
||||
ret[idx] = s.sqlToParamsInstance(instance)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgId string,
|
|||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags")
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ func (s *sqlDatabase) ListOrgInstances(ctx context.Context, orgID string) ([]par
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateOrganizationPool(ctx context.Context, orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
pool, err := s.getOrgPool(ctx, orgID, poolID, "Tags")
|
||||
pool, err := s.getOrgPool(ctx, orgID, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
|
|||
49
database/sql/pools.go
Normal file
49
database/sql/pools.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"garm/params"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (s *sqlDatabase) ListAllPools(ctx context.Context) ([]params.Pool, error) {
|
||||
var pools []Pool
|
||||
|
||||
q := s.conn.Model(&Pool{}).
|
||||
Preload("Tags").
|
||||
Preload("Organization").
|
||||
Preload("Repository").
|
||||
Find(&pools)
|
||||
if q.Error != nil {
|
||||
return nil, errors.Wrap(q.Error, "fetching all pools")
|
||||
}
|
||||
|
||||
ret := make([]params.Pool, len(pools))
|
||||
for idx, val := range pools {
|
||||
ret[idx] = s.sqlToCommonPool(val)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) GetPoolByID(ctx context.Context, poolID string) (params.Pool, error) {
|
||||
pool, err := s.getPoolByID(ctx, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool by ID")
|
||||
}
|
||||
return s.sqlToCommonPool(pool), nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) DeletePoolByID(ctx context.Context, poolID string) error {
|
||||
pool, err := s.getPoolByID(ctx, poolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching pool by ID")
|
||||
}
|
||||
|
||||
if q := s.conn.Unscoped().Delete(&pool); q.Error != nil {
|
||||
return errors.Wrap(q.Error, "removing pool")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -190,7 +190,7 @@ func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, p
|
|||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags")
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ func (s *sqlDatabase) ListRepoInstances(ctx context.Context, repoID string) ([]p
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateRepositoryPool(ctx context.Context, repoID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
pool, err := s.getRepoPool(ctx, repoID, poolID, "Tags")
|
||||
pool, err := s.getRepoPool(ctx, repoID, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"garm/params"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
|
@ -73,6 +75,18 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) params.Pool {
|
|||
Instances: make([]params.Instance, len(pool.Instances)),
|
||||
}
|
||||
|
||||
if pool.RepoID != uuid.Nil {
|
||||
ret.RepoID = pool.RepoID.String()
|
||||
if pool.Repository.Owner != "" && pool.Repository.Name != "" {
|
||||
ret.RepoName = fmt.Sprintf("%s/%s", pool.Repository.Owner, pool.Repository.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if pool.OrgID != uuid.Nil && pool.Organization.Name != "" {
|
||||
ret.OrgID = pool.OrgID.String()
|
||||
ret.OrgName = pool.Organization.Name
|
||||
}
|
||||
|
||||
for idx, val := range pool.Tags {
|
||||
ret.Tags[idx] = s.sqlToCommonTags(*val)
|
||||
}
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -16,7 +16,7 @@ require (
|
|||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/cobra v1.4.1-0.20220504202302-9e88759b19cd
|
||||
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -219,6 +219,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
|
|||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/cobra v1.4.1-0.20220504202302-9e88759b19cd h1:0Hv1DPpsKWp/xjP1sQRfLDIymRDu79mErd9H9+l0uaE=
|
||||
github.com/spf13/cobra v1.4.1-0.20220504202302-9e88759b19cd/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ type Pool struct {
|
|||
Tags []Tag `json:"tags"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Instances []Instance `json:"instances"`
|
||||
RepoID string `json:"repo_id,omitempty"`
|
||||
RepoName string `json:"repo_name,omitempty"`
|
||||
OrgID string `json:"org_id,omitempty"`
|
||||
OrgName string `json:"org_name,omitempty"`
|
||||
}
|
||||
|
||||
type Internal struct {
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ func (r *Runner) DeleteOrgPool(ctx context.Context, orgID, poolID string) error
|
|||
return errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
instances, err := r.store.ListInstances(ctx, pool.ID)
|
||||
instances, err := r.store.ListPoolInstances(ctx, pool.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func (r *basePool) acquireNewInstance(job params.WorkflowJob) error {
|
|||
}
|
||||
|
||||
// TODO: implement count
|
||||
poolInstances, err := r.store.ListInstances(r.ctx, pool.ID)
|
||||
poolInstances, err := r.store.ListPoolInstances(r.ctx, pool.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
|
|
@ -365,7 +365,7 @@ func (r *basePool) ensureIdleRunnersForOnePool(pool params.Pool) {
|
|||
log.Printf("pool %s is disabled, skipping", pool.ID)
|
||||
return
|
||||
}
|
||||
existingInstances, err := r.store.ListInstances(r.ctx, pool.ID)
|
||||
existingInstances, err := r.store.ListPoolInstances(r.ctx, pool.ID)
|
||||
if err != nil {
|
||||
log.Printf("failed to ensure minimum idle workers for pool %s: %s", pool.ID, err)
|
||||
return
|
||||
|
|
|
|||
83
runner/pools.go
Normal file
83
runner/pools.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"garm/auth"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (r *Runner) ListAllPools(ctx context.Context) ([]params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return []params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
pools, err := r.store.ListAllPools(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pools")
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetPoolByID(ctx context.Context, poolID string) (params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
pool, err := r.store.GetPoolByID(ctx, poolID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) DeletePoolByID(ctx context.Context, poolID string) error {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
if err := r.store.DeletePoolByID(ctx, poolID); err != nil {
|
||||
return errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
pool, err := r.store.GetPoolByID(ctx, poolID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
var newPool params.Pool
|
||||
|
||||
if pool.RepoID != "" {
|
||||
newPool, err = r.store.UpdateRepositoryPool(ctx, pool.RepoID, poolID, param)
|
||||
} else if pool.OrgID != "" {
|
||||
newPool, err = r.store.UpdateOrganizationPool(ctx, pool.OrgID, poolID, param)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "updating pool")
|
||||
}
|
||||
return newPool, nil
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ func (r *Runner) DeleteRepoPool(ctx context.Context, repoID, poolID string) erro
|
|||
return errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
instances, err := r.store.ListInstances(ctx, pool.ID)
|
||||
instances, err := r.store.ListPoolInstances(ctx, pool.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
|
|
@ -254,7 +254,7 @@ func (r *Runner) ListPoolInstances(ctx context.Context, poolID string) ([]params
|
|||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instances, err := r.store.ListInstances(ctx, poolID)
|
||||
instances, err := r.store.ListPoolInstances(ctx, poolID)
|
||||
if err != nil {
|
||||
return []params.Instance{}, errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -483,6 +483,18 @@ func (r *Runner) GetInstance(ctx context.Context, instanceName string) (params.I
|
|||
return instance, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListAllInstances(ctx context.Context) ([]params.Instance, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instances, err := r.store.ListAllInstances(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetcing instances")
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func (r *Runner) AddInstanceStatusMessage(ctx context.Context, param params.InstanceUpdateMessage) error {
|
||||
instanceID := auth.InstanceID(ctx)
|
||||
if instanceID == "" {
|
||||
|
|
@ -493,9 +505,6 @@ func (r *Runner) AddInstanceStatusMessage(ctx context.Context, param params.Inst
|
|||
return errors.Wrap(err, "adding status update")
|
||||
}
|
||||
|
||||
// if param.Status == providerCommon.RunnerIdle {
|
||||
// }
|
||||
|
||||
updateParams := params.UpdateInstanceParams{
|
||||
RunnerStatus: param.Status,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue