Skip to content

Commit

Permalink
Use ListEnabledRepos & check within sync-period time
Browse files Browse the repository at this point in the history
  • Loading branch information
erikkn committed Dec 7, 2020
1 parent bb70019 commit 2534945
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 29 deletions.
35 changes: 19 additions & 16 deletions controllers/autoscaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"fmt"
"log"
"strings"
"time"

"github.com/google/go-github/v32/github"
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
)

Expand All @@ -31,36 +31,39 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q: only supported value is %s", tpe, v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns)
}

// Github Enterprise API doesn't offer an endpoint for checking the Actions queue on org level, neither does it offer an endpoint for checking what repos Actions is enabled. This means that, in case of GH Enterprise, you must pass a slice of repositories.
if len(metrics[0].RepositoryNames) < 1 && r.GitHubClient.GithubEnterprise {
return nil, fmt.Errorf("[ERROR] user didn't pass any repository! Please pass a list of repositories the controller has to monitor")
}

// If the above conditionally didn't return an error, we automatically assume, in case on an empty repository slice, that an organization is used.
if len(metrics[0].RepositoryNames) == 0 {
options := &github.RepositoryListByOrgOptions{
Type: "private",
Sort: "pushed",
}
orgRepos, _, err := r.GitHubClient.Repositories.ListByOrg(context.Background(), orgName, options)
enabledRepos, _, err := r.GitHubClient.Actions.ListEnabledReposInOrg(context.Background(), orgName, nil)
if err != nil {
return nil, fmt.Errorf("[ERROR] error fetching a list of repositories for the %s organization with error message: %s", orgName, err)
return nil, fmt.Errorf("[ERROR] 'ListEnabledReposInOrg' failed with error message: %s", err)
}

if len(orgRepos) < 1 {
return nil, fmt.Errorf("[ERROR] ListByOrg returned empty slice! Does your PAT have enough access and is it authorized to list the organizational repositories?")
if len(enabledRepos.Repositories) < 1 {
return nil, fmt.Errorf("[ERROR] 'ListEnabledReposInOrg' returned an empty slice of repositories, check your permissions. Error message: %s", err)
}

for _, v := range orgRepos {
for _, v := range enabledRepos.Repositories {
repoName := fmt.Sprint(*v.Name)

// We kind of already make sure that we don't use these repo's by using the `ListByOrgOptions` field, this is just an extra safeguard.
if *v.Archived || *v.Disabled {
continue
}

// Some organizations have hundreds to thousands of repositories; we only need the X most recent ones.
if len(repos) >= 10 {
log.Printf("[INFO] Reached the limit of repos, performing check on these repositories: %s", repos)
break
lastChange := (int(time.Now().UTC().Sub(v.PushedAt.Time).Minutes()))
// We need a conditional here, since the `ListEnabledReposInOrg(ListOptions)` doesn't allow us to filter on `pushedAt`: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#list-selected-repositories-enabled-for-github-actions-in-an-organization
if lastChange > int(r.SyncPeriod.Minutes()) {
continue
} else if len(repos) < 20 {
repos = append(repos, []string{orgName, repoName})
}
repos = append(repos, []string{orgName, repoName})
}
log.Printf("[INFO] watching the following organizational repositories: %s", repos)

} else {
repoID := rd.Spec.Template.Spec.Repository
if repoID == "" {
Expand Down
1 change: 1 addition & 0 deletions controllers/horizontalrunnerautoscaler_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type HorizontalRunnerAutoscalerReconciler struct {
Log logr.Logger
Recorder record.EventRecorder
Scheme *runtime.Scheme
SyncPeriod *time.Duration
}

// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;update;patch
Expand Down
21 changes: 14 additions & 7 deletions github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@ type Client struct {
regTokens map[string]*github.RegistrationToken
mu sync.Mutex
// GithubBaseURL to Github without API suffix.
GithubBaseURL string
GithubBaseURL string
GithubEnterprise bool
}

// NewClient creates a Github Client
func (c *Config) NewClient() (*Client, error) {
var (
httpClient *http.Client
client *github.Client
httpClient *http.Client
client *github.Client
githubEnterprise bool
)
githubBaseURL := "https://github.com/"

if len(c.Token) > 0 {
httpClient = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: c.Token},
Expand All @@ -60,20 +63,24 @@ func (c *Config) NewClient() (*Client, error) {

if len(c.EnterpriseURL) > 0 {
var err error
githubEnterprise = true

client, err = github.NewEnterpriseClient(c.EnterpriseURL, c.EnterpriseURL, httpClient)
if err != nil {
return nil, fmt.Errorf("enterprise client creation failed: %v", err)
}
githubBaseURL = fmt.Sprintf("%s://%s%s", client.BaseURL.Scheme, client.BaseURL.Host, strings.TrimSuffix(client.BaseURL.Path, "api/v3/"))
} else {
client = github.NewClient(httpClient)
githubEnterprise = false
}

return &Client{
Client: client,
regTokens: map[string]*github.RegistrationToken{},
mu: sync.Mutex{},
GithubBaseURL: githubBaseURL,
Client: client,
regTokens: map[string]*github.RegistrationToken{},
mu: sync.Mutex{},
GithubBaseURL: githubBaseURL,
GithubEnterprise: githubEnterprise,
}, nil
}

Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ require (
github.com/bradleyfalzon/ghinstallation v1.1.1
github.com/davecgh/go-spew v1.1.1
github.com/go-logr/logr v0.1.0
github.com/google/go-github v17.0.0+incompatible // indirect
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04
github.com/google/go-github/v33 v33.0.0
github.com/google/go-querystring v1.0.0
github.com/gorilla/mux v1.8.0
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,8 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04 h1:wEYk2h/GwOhImcVjiTIceP88WxVbXw2F+ARYUQMEsfg=
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func main() {
Log: ctrl.Log.WithName("controllers").WithName("HorizontalRunnerAutoscaler"),
Scheme: mgr.GetScheme(),
GitHubClient: ghClient,
SyncPeriod: &syncPeriod,
}

if err = horizontalRunnerAutoscaler.SetupWithManager(mgr); err != nil {
Expand Down

0 comments on commit 2534945

Please sign in to comment.