diff --git a/cmd/garm-cli/cmd/runner.go b/cmd/garm-cli/cmd/runner.go index 248f3fc3..eafdf4ef 100644 --- a/cmd/garm-cli/cmd/runner.go +++ b/cmd/garm-cli/cmd/runner.go @@ -35,6 +35,7 @@ var ( runnerAll bool forceRemove bool bypassGHUnauthorized bool + long bool ) // runnerCmd represents the runner command @@ -130,7 +131,7 @@ Example: } instances := response.GetPayload() - formatInstances(instances) + formatInstances(instances, long) return nil }, } @@ -204,6 +205,7 @@ func init() { runnerListCmd.Flags().StringVarP(&runnerOrganization, "org", "o", "", "List all runners from all pools within this organization.") runnerListCmd.Flags().StringVarP(&runnerEnterprise, "enterprise", "e", "", "List all runners from all pools within this enterprise.") runnerListCmd.Flags().BoolVarP(&runnerAll, "all", "a", false, "List all runners, regardless of org or repo.") + runnerListCmd.Flags().BoolVarP(&long, "long", "l", false, "Include information about tasks.") runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "all") runnerDeleteCmd.Flags().BoolVarP(&forceRemove, "force-remove-runner", "f", false, "Forcefully remove a runner. If set to true, GARM will ignore provider errors when removing the runner.") @@ -219,13 +221,21 @@ func init() { rootCmd.AddCommand(runnerCmd) } -func formatInstances(param []params.Instance) { +func formatInstances(param []params.Instance, detailed bool) { t := table.NewWriter() header := table.Row{"Nr", "Name", "Status", "Runner Status", "Pool ID"} + if detailed { + header = append(header, "Job Name", "Started At", "Run ID", "Repository") + } t.AppendHeader(header) for idx, inst := range param { - t.AppendRow(table.Row{idx + 1, inst.Name, inst.Status, inst.RunnerStatus, inst.PoolID}) + row := table.Row{idx + 1, inst.Name, inst.Status, inst.RunnerStatus, inst.PoolID} + if detailed && inst.Job != nil { + repo := fmt.Sprintf("%s/%s", inst.Job.RepositoryOwner, inst.Job.RepositoryName) + row = append(row, inst.Job.Name, inst.Job.StartedAt, inst.Job.RunID, repo) + } + t.AppendRow(row) t.AppendSeparator() } fmt.Println(t.Render()) diff --git a/database/sql/enterprise.go b/database/sql/enterprise.go index 5133b255..2537557a 100644 --- a/database/sql/enterprise.go +++ b/database/sql/enterprise.go @@ -233,7 +233,7 @@ func (s *sqlDatabase) FindEnterprisePoolByTags(_ context.Context, enterpriseID s } func (s *sqlDatabase) ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error) { - pools, err := s.listEntityPools(ctx, params.EnterprisePool, enterpriseID, "Tags", "Instances") + pools, err := s.listEntityPools(ctx, params.EnterprisePool, enterpriseID, "Tags", "Instances", "Instances.Job") if err != nil { return nil, errors.Wrap(err, "fetching pools") } @@ -250,7 +250,7 @@ func (s *sqlDatabase) ListEnterprisePools(ctx context.Context, enterpriseID stri } func (s *sqlDatabase) ListEnterpriseInstances(ctx context.Context, enterpriseID string) ([]params.Instance, error) { - pools, err := s.listEntityPools(ctx, params.EnterprisePool, enterpriseID, "Instances", "Tags") + pools, err := s.listEntityPools(ctx, params.EnterprisePool, enterpriseID, "Instances", "Tags", "Instances.Job") if err != nil { return nil, errors.Wrap(err, "fetching enterprise") } diff --git a/database/sql/instances.go b/database/sql/instances.go index 4233f295..4c475bf2 100644 --- a/database/sql/instances.go +++ b/database/sql/instances.go @@ -303,7 +303,7 @@ func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]par } var instances []Instance - query := s.conn.Model(&Instance{}).Where("pool_id = ?", u) + query := s.conn.Model(&Instance{}).Preload("Job").Where("pool_id = ?", u) if err := query.Find(&instances); err.Error != nil { return nil, errors.Wrap(err.Error, "fetching instances") @@ -322,7 +322,7 @@ func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]par func (s *sqlDatabase) ListAllInstances(_ context.Context) ([]params.Instance, error) { var instances []Instance - q := s.conn.Model(&Instance{}).Find(&instances) + q := s.conn.Model(&Instance{}).Preload("Job").Find(&instances) if q.Error != nil { return nil, errors.Wrap(q.Error, "fetching instances") } diff --git a/database/sql/organizations.go b/database/sql/organizations.go index 214757cf..74075ffe 100644 --- a/database/sql/organizations.go +++ b/database/sql/organizations.go @@ -258,7 +258,7 @@ func (s *sqlDatabase) FindOrganizationPoolByTags(_ context.Context, orgID string } func (s *sqlDatabase) ListOrgInstances(ctx context.Context, orgID string) ([]params.Instance, error) { - pools, err := s.listEntityPools(ctx, params.OrganizationPool, orgID, "Tags", "Instances") + pools, err := s.listEntityPools(ctx, params.OrganizationPool, orgID, "Tags", "Instances", "Instances.Job") if err != nil { return nil, errors.Wrap(err, "fetching org") } diff --git a/database/sql/repositories.go b/database/sql/repositories.go index 27adff32..e88c4b9b 100644 --- a/database/sql/repositories.go +++ b/database/sql/repositories.go @@ -258,7 +258,7 @@ func (s *sqlDatabase) FindRepositoryPoolByTags(_ context.Context, repoID string, } func (s *sqlDatabase) ListRepoInstances(ctx context.Context, repoID string) ([]params.Instance, error) { - pools, err := s.listEntityPools(ctx, params.RepositoryPool, repoID, "Tags", "Instances") + pools, err := s.listEntityPools(ctx, params.RepositoryPool, repoID, "Tags", "Instances", "Instances.Job") if err != nil { return nil, errors.Wrap(err, "fetching repo") } diff --git a/database/sql/util.go b/database/sql/util.go index dd3a956b..e9ccc3e5 100644 --- a/database/sql/util.go +++ b/database/sql/util.go @@ -69,6 +69,14 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, e AditionalLabels: labels, } + if instance.Job != nil { + paramJob, err := sqlWorkflowJobToParamsJob(*instance.Job) + if err != nil { + return params.Instance{}, errors.Wrap(err, "converting job") + } + ret.Job = ¶mJob + } + if len(instance.ProviderFault) > 0 { ret.ProviderFault = instance.ProviderFault } diff --git a/params/params.go b/params/params.go index 873a7795..133da05b 100644 --- a/params/params.go +++ b/params/params.go @@ -163,6 +163,9 @@ type Instance struct { // The runner group must be created by someone with access to the enterprise. GitHubRunnerGroup string `json:"github-runner-group"` + // Job is the current job that is being serviced by this runner. + Job *Job `json:"job,omitempty"` + // Do not serialize sensitive info. CallbackURL string `json:"-"` MetadataURL string `json:"-"` diff --git a/runner/metrics/metrics.go b/runner/metrics/metrics.go index 24b01bab..f9f70864 100644 --- a/runner/metrics/metrics.go +++ b/runner/metrics/metrics.go @@ -21,7 +21,7 @@ func CollectObjectMetric(ctx context.Context, r *runner.Runner, duration time.Du // we do not want to wait until the first ticker happens // for that we start an initial collection immediately - slog.InfoContext(ctx, "collecting metrics") + slog.DebugContext(ctx, "collecting metrics") if err := collectMetrics(ctx, r, controllerInfo); err != nil { slog.With(slog.Any("error", err)).ErrorContext(ctx, "cannot collect metrics") } @@ -34,7 +34,7 @@ func CollectObjectMetric(ctx context.Context, r *runner.Runner, duration time.Du case <-ctx.Done(): return case <-ticker.C: - slog.InfoContext(ctx, "collecting metrics") + slog.DebugContext(ctx, "collecting metrics") if err := collectMetrics(ctx, r, controllerInfo); err != nil { slog.With(slog.Any("error", err)).ErrorContext(ctx, "cannot collect metrics") diff --git a/runner/pool/pool.go b/runner/pool/pool.go index 5c4a0a2a..bd9b3543 100644 --- a/runner/pool/pool.go +++ b/runner/pool/pool.go @@ -1128,7 +1128,7 @@ func (r *basePoolManager) scaleDownOnePool(ctx context.Context, pool params.Pool g.Go(func() error { slog.InfoContext( - ctx, "scaling down idle worker from pool %s", + ctx, "scaling down idle worker from pool", "runner_name", instanceToDelete.Name, "pool_id", pool.ID) if err := r.DeleteRunner(instanceToDelete, false, false); err != nil {