Add enterprise support to garm-cli

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2022-10-13 18:32:21 +00:00
parent fb344ab2f2
commit 3e3b91ee59
No known key found for this signature in database
GPG key ID: 7D073DCC2C074CB5
16 changed files with 479 additions and 62 deletions

View file

@ -158,7 +158,7 @@ func (a *APIController) ListEnterpriseInstancesHandler(w http.ResponseWriter, r
return
}
instances, err := a.r.ListOrgInstances(ctx, enterpriseID)
instances, err := a.r.ListEnterpriseInstances(ctx, enterpriseID)
if err != nil {
log.Printf("listing instances: %s", err)
handleError(w, err)

View file

@ -0,0 +1,203 @@
// Copyright 2022 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 client
import (
"encoding/json"
"fmt"
"garm/params"
"github.com/pkg/errors"
)
func (c *Client) ListEnterprises() ([]params.Enterprise, error) {
var enterprises []params.Enterprise
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
resp, err := c.client.R().
SetResult(&enterprises).
Get(url)
if err != nil || resp.IsError() {
apiErr, decErr := c.decodeAPIError(resp.Body())
if decErr != nil {
return nil, errors.Wrap(decErr, "sending request")
}
return nil, fmt.Errorf("error fetching enterprises: %s", apiErr.Details)
}
return enterprises, nil
}
func (c *Client) CreateEnterprise(param params.CreateEnterpriseParams) (params.Enterprise, error) {
var response params.Enterprise
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
body, err := json.Marshal(param)
if err != nil {
return params.Enterprise{}, err
}
resp, err := c.client.R().
SetBody(body).
SetResult(&response).
Post(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 creating enterprise: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) GetEnterprise(enterpriseID string) (params.Enterprise, error) {
var response params.Enterprise
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
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 fetching enterprise: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) DeleteEnterprise(enterpriseID string) error {
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
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 fetching removing enterprise: %s", apiErr.Details)
}
return nil
}
func (c *Client) CreateEnterprisePool(enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
var response params.Pool
body, err := json.Marshal(param)
if err != nil {
return response, err
}
resp, err := c.client.R().
SetBody(body).
SetResult(&response).
Post(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 creating enterprise pool: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) ListEnterprisePools(enterpriseID string) ([]params.Pool, error) {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
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 listing enterprise pools: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) GetEnterprisePool(enterpriseID, poolID string) (params.Pool, error) {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, 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 fetching enterprise pool: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) DeleteEnterprisePool(enterpriseID, poolID string) error {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, 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 enterprise pool: %s", apiErr.Details)
}
return nil
}
func (c *Client) UpdateEnterprisePool(enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, 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 updating enterprise pool: %s", apiErr.Details)
}
return response, nil
}
func (c *Client) ListEnterpriseInstances(enterpriseID string) ([]params.Instance, error) {
url := fmt.Sprintf("%s/api/v1/enterprises/%s/instances", c.Config.BaseURL, enterpriseID)
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 listing enterprise instances: %s", apiErr.Details)
}
return response, nil
}

View file

@ -56,7 +56,7 @@ func (c *Client) CreateOrganization(param params.CreateOrgParams) (params.Organi
if decErr != nil {
return response, errors.Wrap(decErr, "sending request")
}
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
return response, fmt.Errorf("error creating org: %s", apiErr.Details)
}
return response, nil
}
@ -72,7 +72,7 @@ func (c *Client) GetOrganization(orgID string) (params.Organization, error) {
if decErr != nil {
return response, errors.Wrap(decErr, "sending request")
}
return response, fmt.Errorf("error fetching orgs: %s", apiErr.Details)
return response, fmt.Errorf("error fetching org: %s", apiErr.Details)
}
return response, nil
}
@ -86,7 +86,7 @@ func (c *Client) DeleteOrganization(orgID string) error {
if decErr != nil {
return errors.Wrap(decErr, "sending request")
}
return fmt.Errorf("error fetching orgs: %s", apiErr.Details)
return fmt.Errorf("error removing org: %s", apiErr.Details)
}
return nil
}

View file

@ -0,0 +1,186 @@
// Copyright 2022 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"
"garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
var (
enterpriseName string
enterpriseWebhookSecret string
enterpriseCreds string
)
// enterpriseCmd represents the enterprise command
var enterpriseCmd = &cobra.Command{
Use: "enterprise",
Aliases: []string{"ent"},
SilenceUsage: true,
Short: "Manage enterprise",
Long: `Add, remove or update enterprise for which we manage
self hosted runners.
This command allows you to define a new enterprise or manage an existing
enterprise for which garm maintains pools of self hosted runners.`,
Run: nil,
}
var enterpriseAddCmd = &cobra.Command{
Use: "add",
Aliases: []string{"create"},
Short: "Add enterprise",
Long: `Add a new enterprise to the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
newEnterpriseReq := params.CreateEnterpriseParams{
Name: enterpriseName,
WebhookSecret: enterpriseWebhookSecret,
CredentialsName: enterpriseCreds,
}
enterprise, err := cli.CreateEnterprise(newEnterpriseReq)
if err != nil {
return err
}
formatOneEnterprise(enterprise)
return nil
},
}
var enterpriseListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List enterprises",
Long: `List all configured enterprises that are currently managed.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
enterprises, err := cli.ListEnterprises()
if err != nil {
return err
}
formatEnterprises(enterprises)
return nil
},
}
var enterpriseShowCmd = &cobra.Command{
Use: "show",
Short: "Show details for one enterprise",
Long: `Displays detailed information about a single enterprise.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires a enterprise ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
enterprise, err := cli.GetEnterprise(args[0])
if err != nil {
return err
}
formatOneEnterprise(enterprise)
return nil
},
}
var enterpriseDeleteCmd = &cobra.Command{
Use: "delete",
Aliases: []string{"remove", "rm", "del"},
Short: "Removes one enterprise",
Long: `Delete one enterprise from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires a enterprise ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
if err := cli.DeleteEnterprise(args[0]); err != nil {
return err
}
return nil
},
}
func init() {
enterpriseAddCmd.Flags().StringVar(&enterpriseName, "name", "", "The name of the enterprise")
enterpriseAddCmd.Flags().StringVar(&enterpriseWebhookSecret, "webhook-secret", "", "The webhook secret for this enterprise")
enterpriseAddCmd.Flags().StringVar(&enterpriseCreds, "credentials", "", "Credentials name. See credentials list.")
enterpriseAddCmd.MarkFlagRequired("credentials")
enterpriseAddCmd.MarkFlagRequired("name")
enterpriseCmd.AddCommand(
enterpriseListCmd,
enterpriseAddCmd,
enterpriseShowCmd,
enterpriseDeleteCmd,
)
rootCmd.AddCommand(enterpriseCmd)
}
func formatEnterprises(enterprises []params.Enterprise) {
t := table.NewWriter()
header := table.Row{"ID", "Name", "Credentials name"}
t.AppendHeader(header)
for _, val := range enterprises {
t.AppendRow(table.Row{val.ID, val.Name, val.CredentialsName})
t.AppendSeparator()
}
fmt.Println(t.Render())
}
func formatOneEnterprise(enterprise params.Enterprise) {
t := table.NewWriter()
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
header := table.Row{"Field", "Value"}
t.AppendHeader(header)
t.AppendRow(table.Row{"ID", enterprise.ID})
t.AppendRow(table.Row{"Name", enterprise.Name})
t.AppendRow(table.Row{"Credentials", enterprise.CredentialsName})
if len(enterprise.Pools) > 0 {
for _, pool := range enterprise.Pools {
t.AppendRow(table.Row{"Pools", pool.ID}, rowConfigAutoMerge)
}
}
t.SetColumnConfigs([]table.ColumnConfig{
{Number: 1, AutoMerge: true},
{Number: 2, AutoMerge: true},
})
fmt.Println(t.Render())
}

View file

@ -38,7 +38,7 @@ var organizationCmd = &cobra.Command{
self hosted runners.
This command allows you to define a new organization or manage an existing
organization for which the garm maintains pools of self hosted runners.`,
organization for which garm maintains pools of self hosted runners.`,
Run: nil,
}
@ -71,7 +71,7 @@ var orgListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List organizations",
Long: `List all configured respositories that are currently managed.`,
Long: `List all configured organizations that are currently managed.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
@ -134,29 +134,6 @@ var orgDeleteCmd = &cobra.Command{
},
}
var orgInstanceListCmd = &cobra.Command{
Use: "delete",
Aliases: []string{"remove", "rm", "del"},
Short: "Removes one organization",
Long: `Delete one organization from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires a organization ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
if err := cli.DeleteOrganization(args[0]); err != nil {
return err
}
return nil
},
}
func init() {
orgAddCmd.Flags().StringVar(&orgName, "name", "", "The name of the organization")

View file

@ -27,6 +27,7 @@ import (
var (
poolRepository string
poolOrganization string
poolEnterprise string
poolAll bool
)
@ -57,6 +58,9 @@ Example:
List pools from one org:
garm-cli pool list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
List pools from one enterprise:
garm-cli pool list --org=a8ee4c66-e762-4cbe-a35d-175dba2c9e62
List all pools from all repos and orgs:
garm-cli pool list --all
@ -76,6 +80,8 @@ Example:
pools, err = cli.ListRepoPools(poolRepository)
} else if cmd.Flags().Changed("org") {
pools, err = cli.ListOrgPools(poolOrganization)
} else if cmd.Flags().Changed("enterprise") {
pools, err = cli.ListEnterprisePools(poolEnterprise)
} else if cmd.Flags().Changed("all") {
pools, err = cli.ListAllPools()
} else {
@ -183,6 +189,8 @@ var poolAddCmd = &cobra.Command{
pool, err = cli.CreateRepoPool(poolRepository, newPoolParams)
} else if cmd.Flags().Changed("org") {
pool, err = cli.CreateOrgPool(poolOrganization, newPoolParams)
} else if cmd.Flags().Changed("enterprise") {
pool, err = cli.CreateEnterprisePool(poolEnterprise, newPoolParams)
} else {
cmd.Help()
os.Exit(0)
@ -270,8 +278,9 @@ explicitly remove them using the runner delete command.
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().StringVarP(&poolEnterprise, "enterprise", "e", "", "List all pools withing this enterprise.")
poolListCmd.Flags().BoolVarP(&poolAll, "all", "a", false, "List all pools, regardless of org or repo.")
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all", "enterprise")
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.")
@ -300,7 +309,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 withing this organization.")
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org")
poolAddCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "Add the new pool withing this enterprise.")
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise")
poolCmd.AddCommand(
poolListCmd,

View file

@ -286,6 +286,9 @@ func formatPools(pools []params.Pool) {
} else if pool.OrgID != "" && pool.OrgName != "" {
belongsTo = pool.OrgName
level = "org"
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
belongsTo = pool.EnterpriseName
level = "enterprise"
}
t.AppendRow(table.Row{pool.ID, pool.Image, pool.Flavor, strings.Join(tags, " "), belongsTo, level, pool.Enabled})
t.AppendSeparator()
@ -313,6 +316,9 @@ func formatOnePool(pool params.Pool) {
} else if pool.OrgID != "" && pool.OrgName != "" {
belongsTo = pool.OrgName
level = "org"
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
belongsTo = pool.EnterpriseName
level = "enterprise"
}
t.AppendHeader(header)

View file

@ -136,29 +136,6 @@ var repoDeleteCmd = &cobra.Command{
},
}
var repoInstanceListCmd = &cobra.Command{
Use: "delete",
Aliases: []string{"remove", "rm", "del"},
Short: "Removes one repository",
Long: `Delete one repository from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return needsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires a repository ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
if err := cli.DeleteRepository(args[0]); err != nil {
return err
}
return nil
},
}
func init() {
repoAddCmd.Flags().StringVar(&repoOwner, "owner", "", "The owner of this repository")

View file

@ -26,6 +26,7 @@ import (
var (
runnerRepository string
runnerOrganization string
runnerEnterprise string
runnerAll bool
forceRemove bool
)
@ -61,6 +62,9 @@ Example:
List runners from one org:
garm-cli runner list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
List runners from one enterprise:
garm-cli runner list --enterprise=a966188b-0e05-4edc-9b82-bc81a1fd38ed
List all runners from all pools belonging to all repos and orgs:
garm-cli runner list --all
@ -78,9 +82,10 @@ Example:
case 1:
if cmd.Flags().Changed("repo") ||
cmd.Flags().Changed("org") ||
cmd.Flags().Changed("enterprise") ||
cmd.Flags().Changed("all") {
return fmt.Errorf("specifying a pool ID and any of [all org repo] are mutually exclusive")
return fmt.Errorf("specifying a pool ID and any of [all org repo enterprise] are mutually exclusive")
}
instances, err = cli.ListPoolInstances(args[0])
case 0:
@ -88,6 +93,8 @@ Example:
instances, err = cli.ListRepoInstances(runnerRepository)
} else if cmd.Flags().Changed("org") {
instances, err = cli.ListOrgInstances(runnerOrganization)
} else if cmd.Flags().Changed("enterprise") {
instances, err = cli.ListEnterpriseInstances(runnerEnterprise)
} else if cmd.Flags().Changed("all") {
instances, err = cli.ListAllInstances()
} else {
@ -172,8 +179,9 @@ to either cancel the workflow or wait for it to finish.
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().StringVarP(&runnerEnterprise, "enterprise", "e", "", "List all runners from all pools withing this enterprise.")
runnerListCmd.Flags().BoolVarP(&runnerAll, "all", "a", false, "List all runners, regardless of org or repo.")
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "all")
runnerDeleteCmd.Flags().BoolVarP(&forceRemove, "force-remove-runner", "f", false, "Confirm you want to delete a runner")
runnerDeleteCmd.MarkFlagsMutuallyExclusive("force-remove-runner")

View file

@ -229,7 +229,7 @@ func (s *sqlDatabase) FindEnterprisePoolByTags(ctx context.Context, enterpriseID
}
func (s *sqlDatabase) ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error) {
pools, err := s.getEnterprisePools(ctx, enterpriseID, "Tags")
pools, err := s.getEnterprisePools(ctx, enterpriseID, "Tags", "Enterprise")
if err != nil {
return nil, errors.Wrap(err, "fetching pools")
}

View file

@ -29,6 +29,7 @@ func (s *sqlDatabase) ListAllPools(ctx context.Context) ([]params.Pool, error) {
Preload("Tags").
Preload("Organization").
Preload("Repository").
Preload("Enterprise").
Find(&pools)
if q.Error != nil {
return nil, errors.Wrap(q.Error, "fetching all pools")

View file

@ -128,6 +128,11 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) params.Pool {
ret.OrgName = pool.Organization.Name
}
if pool.EnterpriseID != uuid.Nil && pool.Enterprise.Name != "" {
ret.EnterpriseID = pool.EnterpriseID.String()
ret.EnterpriseName = pool.Enterprise.Name
}
for idx, val := range pool.Tags {
ret.Tags[idx] = s.sqlToCommonTags(*val)
}

View file

@ -128,6 +128,8 @@ type Pool struct {
RepoName string `json:"repo_name,omitempty"`
OrgID string `json:"org_id,omitempty"`
OrgName string `json:"org_name,omitempty"`
EnterpriseID string `json:"enterprise_id,omitempty"`
EnterpriseName string `json:"enterprise_name,omitempty"`
RunnerBootstrapTimeout uint `json:"runner_bootstrap_timeout"`
}

View file

@ -353,7 +353,7 @@ func (r *basePool) loop() {
reapTimer := time.NewTicker(common.PoolReapTimeoutInterval)
toolUpdateTimer := time.NewTicker(common.PoolToolUpdateInterval)
defer func() {
log.Printf("repository %s loop exited", r.helper.String())
log.Printf("%s loop exited", r.helper.String())
consolidateTimer.Stop()
reapTimer.Stop()
toolUpdateTimer.Stop()
@ -896,6 +896,7 @@ func (r *basePool) ForceDeleteRunner(runner params.Instance) error {
}
}
}
log.Printf("setting instance status for: %v", runner.Name)
if err := r.setInstanceStatus(runner.Name, providerCommon.InstancePendingDelete, nil); err != nil {
log.Printf("failed to update runner %s status", runner.Name)

View file

@ -16,6 +16,7 @@ package runner
import (
"context"
"fmt"
"garm/auth"
runnerErrors "garm/errors"
@ -112,6 +113,10 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
newPool, err = r.store.UpdateRepositoryPool(ctx, pool.RepoID, poolID, param)
} else if pool.OrgID != "" {
newPool, err = r.store.UpdateOrganizationPool(ctx, pool.OrgID, poolID, param)
} else if pool.EnterpriseID != "" {
newPool, err = r.store.UpdateEnterprisePool(ctx, pool.EnterpriseID, poolID, param)
} else {
return params.Pool{}, fmt.Errorf("pool not bound to a repo, org or enterprise")
}
if err != nil {

View file

@ -71,6 +71,7 @@ func NewRunner(ctx context.Context, cfg config.Config) (*Runner, error) {
credentials: creds,
repositories: map[string]common.PoolManager{},
organizations: map[string]common.PoolManager{},
enterprises: map[string]common.PoolManager{},
}
runner := &Runner{
ctx: ctx,
@ -81,7 +82,7 @@ func NewRunner(ctx context.Context, cfg config.Config) (*Runner, error) {
credentials: creds,
}
if err := runner.loadReposAndOrgs(); err != nil {
if err := runner.loadReposOrgsAndEnterprises(); err != nil {
return nil, errors.Wrap(err, "loading pool managers")
}
@ -293,7 +294,7 @@ func (r *Runner) ListProviders(ctx context.Context) ([]params.Provider, error) {
return ret, nil
}
func (r *Runner) loadReposAndOrgs() error {
func (r *Runner) loadReposOrgsAndEnterprises() error {
r.mux.Lock()
defer r.mux.Unlock()
@ -307,7 +308,12 @@ func (r *Runner) loadReposAndOrgs() error {
return errors.Wrap(err, "fetching organizations")
}
expectedReplies := len(repos) + len(orgs)
enterprises, err := r.store.ListEnterprises(r.ctx)
if err != nil {
return errors.Wrap(err, "fetching enterprises")
}
expectedReplies := len(repos) + len(orgs) + len(enterprises)
errChan := make(chan error, expectedReplies)
for _, repo := range repos {
@ -326,6 +332,14 @@ func (r *Runner) loadReposAndOrgs() error {
}(org)
}
for _, enterprise := range enterprises {
go func(enterprise params.Enterprise) {
log.Printf("creating pool manager for enterprise %s", enterprise.Name)
_, err := r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store)
errChan <- err
}(enterprise)
}
for i := 0; i < expectedReplies; i++ {
select {
case err := <-errChan:
@ -354,7 +368,12 @@ func (r *Runner) Start() error {
return errors.Wrap(err, "fetch org pool managers")
}
expectedReplies := len(repositories) + len(organizations)
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
if err != nil {
return errors.Wrap(err, "fetch enterprise pool managers")
}
expectedReplies := len(repositories) + len(organizations) + len(enterprises)
errChan := make(chan error, expectedReplies)
for _, repo := range repositories {
@ -373,6 +392,14 @@ func (r *Runner) Start() error {
}
for _, enterprise := range enterprises {
go func(org common.PoolManager) {
err := org.Start()
errChan <- err
}(enterprise)
}
for i := 0; i < expectedReplies; i++ {
select {
case err := <-errChan:
@ -688,6 +715,15 @@ func (r *Runner) ForceDeleteRunner(ctx context.Context, instanceName string) err
if err != nil {
return errors.Wrapf(err, "fetching pool manager for org %s", pool.OrgName)
}
} else if pool.EnterpriseID != "" {
enterprise, err := r.store.GetEnterpriseByID(ctx, pool.EnterpriseID)
if err != nil {
return errors.Wrap(err, "fetching enterprise")
}
poolMgr, err = r.findEnterprisePoolManager(enterprise.Name)
if err != nil {
return errors.Wrapf(err, "fetching pool manager for enterprise %s", pool.EnterpriseName)
}
}
if err := poolMgr.ForceDeleteRunner(instance); err != nil {