Skip to content

Commit 40c5050

Browse files
authored
Added support for other than public GitHub URL (#146)
Refactoring a bit
1 parent 99a53a6 commit 40c5050

File tree

12 files changed

+101
-82
lines changed

12 files changed

+101
-82
lines changed

.github/workflows/build-runner.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
--platform linux/amd64,linux/arm64 \
5151
--tag ${DOCKERHUB_USERNAME}/actions-runner-dind:v${RUNNER_VERSION} \
5252
--tag ${DOCKERHUB_USERNAME}/actions-runner-dind:latest \
53-
-f Dockerfile.dindrunner .
53+
-f dindrunner.Dockerfile .
5454
5555
- name: Login to GitHub Docker Registry
5656
run: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
@@ -76,4 +76,4 @@ jobs:
7676
--platform linux/amd64,linux/arm64 \
7777
--tag ${DOCKERHUB_USERNAME}/actions-runner-dind:v${RUNNER_VERSION} \
7878
--tag ${DOCKERHUB_USERNAME}/actions-runner-dind:latest \
79-
-f Dockerfile.dindrunner . --push
79+
-f dindrunner.Dockerfile . --push

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ Install the custom resource and actions-runner-controller itself. This will crea
2020
$ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml
2121
```
2222

23+
### Github Enterprise support
24+
25+
If you use either Github Enterprise Cloud or Server (and have recent enought version supporting Actions), you can use **actions-runner-controller** with those, too. Authentication works same way as with public Github (repo and organization level).
26+
27+
```
28+
$ kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL>
29+
```
30+
31+
[Enterprise level](https://docs.github.com/en/enterprise-server@2.22/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-an-enterprise) runners are not working yet as there's no API definition for those.
32+
2333
## Setting up authentication with GitHub API
2434

2535
There are two ways for actions-runner-controller to authenticate with the GitHub API:

controllers/autoscaling_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ import (
1616
)
1717

1818
func newGithubClient(server *httptest.Server) *github.Client {
19-
client, err := github.NewClientWithAccessToken("token")
19+
c := github.Config{
20+
Token: "token",
21+
}
22+
client, err := c.NewClient()
2023
if err != nil {
2124
panic(err)
2225
}

controllers/runner_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
317317
Name: "DOCKERD_IN_RUNNER",
318318
Value: fmt.Sprintf("%v", dockerdInRunner),
319319
},
320+
{
321+
Name: "GITHUB_URL",
322+
Value: r.GitHubClient.GithubBaseURL,
323+
},
320324
}
321325

322326
env = append(env, runner.Spec.Env...)

github/github.go

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,66 @@ import (
99
"time"
1010

1111
"github.com/bradleyfalzon/ghinstallation"
12+
"github.com/go-logr/logr"
1213
"github.com/google/go-github/v32/github"
1314
"golang.org/x/oauth2"
1415
)
1516

17+
// Config contains configuration for Github client
18+
type Config struct {
19+
Log logr.Logger
20+
EnterpriseURL string `split_words:"true"`
21+
AppID int64 `split_words:"true"`
22+
AppInstallationID int64 `split_words:"true"`
23+
AppPrivateKey string `split_words:"true"`
24+
Token string
25+
}
26+
1627
// Client wraps GitHub client with some additional
1728
type Client struct {
1829
*github.Client
1930
regTokens map[string]*github.RegistrationToken
2031
mu sync.Mutex
32+
// GithubBaseURL to Github without API suffix.
33+
GithubBaseURL string
2134
}
2235

23-
// NewClient returns a client authenticated as a GitHub App.
24-
func NewClient(appID, installationID int64, privateKeyPath string) (*Client, error) {
25-
tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, appID, installationID, privateKeyPath)
26-
if err != nil {
27-
return nil, fmt.Errorf("authentication failed: %v", err)
36+
func (c *Config) NewClient() (*Client, error) {
37+
var (
38+
httpClient *http.Client
39+
client *github.Client
40+
)
41+
githubBaseURL := "https://github.com/"
42+
if len(c.Token) > 0 {
43+
httpClient = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
44+
&oauth2.Token{AccessToken: c.Token},
45+
))
46+
} else {
47+
tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, c.AppID, c.AppInstallationID, c.AppPrivateKey)
48+
if err != nil {
49+
c.Log.Error(err, "Authentication failed")
50+
return nil, fmt.Errorf("authentication failed: %v", err)
51+
}
52+
httpClient = &http.Client{Transport: tr}
2853
}
2954

30-
gh := github.NewClient(&http.Client{Transport: tr})
31-
32-
return &Client{
33-
Client: gh,
34-
regTokens: map[string]*github.RegistrationToken{},
35-
mu: sync.Mutex{},
36-
}, nil
37-
}
38-
39-
// NewClientWithAccessToken returns a client authenticated with personal access token.
40-
func NewClientWithAccessToken(token string) (*Client, error) {
41-
tc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
42-
&oauth2.Token{AccessToken: token},
43-
))
55+
if len(c.EnterpriseURL) > 0 {
56+
var err error
57+
client, err = github.NewEnterpriseClient(c.EnterpriseURL, c.EnterpriseURL, httpClient)
58+
if err != nil {
59+
c.Log.Error(err, "Enterprise client creation failed")
60+
return nil, fmt.Errorf("enterprise client creation failed: %v", err)
61+
}
62+
githubBaseURL = fmt.Sprintf("%s://%s%s", client.BaseURL.Scheme, client.BaseURL.Host, strings.TrimSuffix(client.BaseURL.Path, "api/v3/"))
63+
} else {
64+
client = github.NewClient(httpClient)
65+
}
4466

4567
return &Client{
46-
Client: github.NewClient(tc),
47-
regTokens: map[string]*github.RegistrationToken{},
48-
mu: sync.Mutex{},
68+
Client: client,
69+
regTokens: map[string]*github.RegistrationToken{},
70+
mu: sync.Mutex{},
71+
GithubBaseURL: githubBaseURL,
4972
}, nil
5073
}
5174

github/github_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import (
1414
var server *httptest.Server
1515

1616
func newTestClient() *Client {
17-
client, err := NewClientWithAccessToken("token")
17+
c := Config{
18+
Token: "token",
19+
}
20+
client, err := c.NewClient()
1821
if err != nil {
1922
panic(err)
2023
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04
1010
github.com/google/go-querystring v1.0.0
1111
github.com/gorilla/mux v1.8.0
12+
github.com/kelseyhightower/envconfig v1.4.0
1213
github.com/onsi/ginkgo v1.8.0
1314
github.com/onsi/gomega v1.5.0
1415
github.com/stretchr/testify v1.4.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
158158
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
159159
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
160160
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
161+
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
162+
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
161163
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
162164
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
163165
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=

main.go

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import (
2020
"flag"
2121
"fmt"
2222
"os"
23-
"strconv"
2423
"time"
2524

25+
"github.com/kelseyhightower/envconfig"
2626
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
2727
"github.com/summerwind/actions-runner-controller/controllers"
2828
"github.com/summerwind/actions-runner-controller/github"
@@ -62,68 +62,29 @@ func main() {
6262

6363
runnerImage string
6464
dockerImage string
65-
66-
ghToken string
67-
ghAppID int64
68-
ghAppInstallationID int64
69-
ghAppPrivateKey string
7065
)
7166

67+
var c github.Config
68+
err = envconfig.Process("github", &c)
69+
if err != nil {
70+
fmt.Fprintln(os.Stderr, "Error: Environment variable read failed.")
71+
}
72+
7273
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
7374
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
7475
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
7576
flag.StringVar(&runnerImage, "runner-image", defaultRunnerImage, "The image name of self-hosted runner container.")
7677
flag.StringVar(&dockerImage, "docker-image", defaultDockerImage, "The image name of docker sidecar container.")
77-
flag.StringVar(&ghToken, "github-token", "", "The personal access token of GitHub.")
78-
flag.Int64Var(&ghAppID, "github-app-id", 0, "The application ID of GitHub App.")
79-
flag.Int64Var(&ghAppInstallationID, "github-app-installation-id", 0, "The installation ID of GitHub App.")
80-
flag.StringVar(&ghAppPrivateKey, "github-app-private-key", "", "The path of a private key file to authenticate as a GitHub App")
78+
flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.")
79+
flag.Int64Var(&c.AppID, "github-app-id", c.AppID, "The application ID of GitHub App.")
80+
flag.Int64Var(&c.AppInstallationID, "github-app-installation-id", c.AppInstallationID, "The installation ID of GitHub App.")
81+
flag.StringVar(&c.AppPrivateKey, "github-app-private-key", c.AppPrivateKey, "The path of a private key file to authenticate as a GitHub App")
8182
flag.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, "Determines the minimum frequency at which K8s resources managed by this controller are reconciled. When you use autoscaling, set to a lower value like 10 minute, because this corresponds to the minimum time to react on demand change")
8283
flag.Parse()
8384

84-
if ghToken == "" {
85-
ghToken = os.Getenv("GITHUB_TOKEN")
86-
}
87-
if ghAppID == 0 {
88-
appID, err := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64)
89-
if err == nil {
90-
ghAppID = appID
91-
}
92-
}
93-
if ghAppInstallationID == 0 {
94-
appInstallationID, err := strconv.ParseInt(os.Getenv("GITHUB_APP_INSTALLATION_ID"), 10, 64)
95-
if err == nil {
96-
ghAppInstallationID = appInstallationID
97-
}
98-
}
99-
if ghAppPrivateKey == "" {
100-
ghAppPrivateKey = os.Getenv("GITHUB_APP_PRIVATE_KEY")
101-
}
102-
103-
if ghAppID != 0 {
104-
if ghAppInstallationID == 0 {
105-
fmt.Fprintln(os.Stderr, "Error: The installation ID must be specified.")
106-
os.Exit(1)
107-
}
108-
109-
if ghAppPrivateKey == "" {
110-
fmt.Fprintln(os.Stderr, "Error: The path of a private key file must be specified.")
111-
os.Exit(1)
112-
}
113-
114-
ghClient, err = github.NewClient(ghAppID, ghAppInstallationID, ghAppPrivateKey)
115-
if err != nil {
116-
fmt.Fprintf(os.Stderr, "Error: Failed to create GitHub client: %v\n", err)
117-
os.Exit(1)
118-
}
119-
} else if ghToken != "" {
120-
ghClient, err = github.NewClientWithAccessToken(ghToken)
121-
if err != nil {
122-
fmt.Fprintf(os.Stderr, "Error: Failed to create GitHub client: %v\n", err)
123-
os.Exit(1)
124-
}
125-
} else {
126-
fmt.Fprintln(os.Stderr, "Error: GitHub App credentials or personal access token must be specified.")
85+
ghClient, err = c.NewClient()
86+
if err != nil {
87+
fmt.Fprintln(os.Stderr, "Error: Client creation failed.", err)
12788
os.Exit(1)
12889
}
12990

runner/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ endif
2424

2525
docker-build:
2626
docker build --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${NAME}:${TAG} -t ${NAME}:v${RUNNER_VERSION} .
27-
docker build --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -t ${DIND_RUNNER_NAME}:v${RUNNER_VERSION} -f Dockerfile.dindrunner .
27+
docker build --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -t ${DIND_RUNNER_NAME}:v${RUNNER_VERSION} -f dindrunner.Dockerfile .
2828

2929

3030
docker-push:
@@ -48,5 +48,5 @@ docker-buildx:
4848
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
4949
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
5050
-t "${DIND_RUNNER_NAME}:latest" \
51-
-f Dockerfile.dindrunner \
51+
-f dindrunner.Dockerfile \
5252
. ${PUSH_ARG}

0 commit comments

Comments
 (0)