mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-11 03:57:01 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
427cc506e1 | ||
|
|
13616ba1b2 | ||
|
|
d8327e9ab8 | ||
|
|
fd1b72e4ed | ||
|
|
79f15b4906 | ||
|
|
5714459c24 | ||
|
|
ab28dde0ec | ||
|
|
3ccc51433f | ||
|
|
5f608058cd | ||
|
|
a91df5c564 | ||
|
|
0bb6f64470 | ||
|
|
ce40635d1e | ||
|
|
52c0f2e4f3 |
@@ -13,6 +13,7 @@ RUN go mod download
|
|||||||
COPY main.go main.go
|
COPY main.go main.go
|
||||||
COPY api/ api/
|
COPY api/ api/
|
||||||
COPY controllers/ controllers/
|
COPY controllers/ controllers/
|
||||||
|
COPY github/ github/
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -16,12 +16,61 @@ First, install *actions-runner-controller* with a manifest file. This will creat
|
|||||||
$ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml
|
$ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, from an account that has `admin` privileges for the repository, create a [personal access token](https://github.com/settings/tokens) with `repo` scope. This token is used to register a self-hosted runner by *actions-runner-controller*.
|
Next, set up a GitHub App or personal access token for *actions-runner-controller* to access the GitHub API.
|
||||||
|
|
||||||
Then, create a Kubernetes secret, replacing `${GITHUB_TOKEN}` with your token.
|
### Using GitHub App
|
||||||
|
|
||||||
|
You can create a GitHub App for either your account or any organization. If you want to create a GitHub App for your account, open the following link to the creation page, enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page.
|
||||||
|
|
||||||
|
- [Create GitHub Apps on your account](https://github.com/settings/apps/new?url=http://github.com/summerwind/actions-runner-controller&webhook_active=false&public=false&administration=write)
|
||||||
|
|
||||||
|
If you want to create a GitHub App for your organization, replace the `:org` part of the following URL with your organization name before opening it. Then enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page to create a GitHub App.
|
||||||
|
|
||||||
|
- [Create GitHub Apps on your organization](https://github.com/organizations/:org/settings/apps/new?url=http://github.com/summerwind/actions-runner-controller&webhook_active=false&public=false&administration=write)
|
||||||
|
|
||||||
|
You will see an *App ID* on the page of the GitHub App you created as follows, the value of this App ID will be used later.
|
||||||
|
|
||||||
|
<img width="750" alt="App ID" src="https://user-images.githubusercontent.com/230145/78968802-6e7c8880-7b40-11ea-8b08-0c1b8e6a15f0.png">
|
||||||
|
|
||||||
|
Download the private key file by pushing the "Generate a private key" button at the bottom of the GitHub App page. This file will also be used later.
|
||||||
|
|
||||||
|
<img width="750" alt="Generate a private key" src="https://user-images.githubusercontent.com/230145/78968805-71777900-7b40-11ea-97e6-55c48dfc44ac.png">
|
||||||
|
|
||||||
|
Go to the "Install App" tab on the left side of the page and install the GitHub App that you created for your account or organization.
|
||||||
|
|
||||||
|
<img width="750" alt="Install App" src="https://user-images.githubusercontent.com/230145/78968806-72100f80-7b40-11ea-810d-2bd3261e9d40.png">
|
||||||
|
|
||||||
|
When the installation is complete, you will be taken to a URL in one of the following formats, the last number of the URL will be used as the Installation ID later (For example, if the URL ends in `settings/installations/12345`, then the Installation ID is `12345`).
|
||||||
|
|
||||||
|
- `https://github.com/settings/installations/${INSTALLATION_ID}`
|
||||||
|
- `https://github.com/organizations/eventreactor/settings/installations/${INSTALLATION_ID}`
|
||||||
|
|
||||||
|
Finally, register the App ID (`APP_ID`), Installation ID (`INSTALLATION_ID`), and downloaded private key file (`PRIVATE_KEY_FILE_PATH`) to Kubernetes as Secret.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ kubectl create secret generic controller-manager --from-literal=github_token=${GITHUB_TOKEN} -n actions-runner-system
|
$ kubectl create secret generic controller-manager \
|
||||||
|
-n actions-runner-system \
|
||||||
|
--from-literal=github_app_id=${APP_ID} \
|
||||||
|
--from-literal=github_app_installation_id=${INSTALLATION_ID} \
|
||||||
|
--from-file=github_app_private_key=${PRIVATE_KEY_FILE_PATH}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using personal access token
|
||||||
|
|
||||||
|
Next, from an account that has `admin` privileges for the repository, create a [personal access token](https://github.com/settings/tokens) with `repo` scope. This token is used to register a self-hosted runner by *actions-runner-controller*.
|
||||||
|
|
||||||
|
To use a Personal Access Token, you must issue the token with an account that has `admin` privileges.
|
||||||
|
|
||||||
|
Open the Create Token page from the following link, grant the `repo` scope, and press the "Generate Token" button at the bottom of the page to create the token.
|
||||||
|
|
||||||
|
- [Create personal access token](https://github.com/settings/tokens/new)
|
||||||
|
|
||||||
|
Register the created token (`GITHUB_TOKEN`) as a Kubernetes secret.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ kubectl create secret generic controller-manager \
|
||||||
|
-n actions-runner-system \
|
||||||
|
--from-literal=github_token=${GITHUB_TOKEN}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
@@ -20,10 +20,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/google/go-github/v29/github"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
@@ -34,6 +32,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/summerwind/actions-runner-controller/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -41,23 +40,6 @@ const (
|
|||||||
finalizerName = "runner.actions.summerwind.dev"
|
finalizerName = "runner.actions.summerwind.dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GitHubRunnerList struct {
|
|
||||||
TotalCount int `json:"total_count"`
|
|
||||||
Runners []GitHubRunner `json:"runners,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GitHubRunner struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
OS string `json:"os"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GitHubRegistrationToken struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
ExpiresAt string `json:"expires_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunnerReconciler reconciles a Runner object
|
// RunnerReconciler reconciles a Runner object
|
||||||
type RunnerReconciler struct {
|
type RunnerReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
@@ -126,7 +108,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !runner.IsRegisterable() {
|
if !runner.IsRegisterable() {
|
||||||
reg, err := r.newRegistration(ctx, runner.Spec.Repository)
|
rt, err := r.GitHubClient.GetRegistrationToken(ctx, runner.Spec.Repository, runner.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Recorder.Event(&runner, corev1.EventTypeWarning, "FailedUpdateRegistrationToken", "Updating registration token failed")
|
r.Recorder.Event(&runner, corev1.EventTypeWarning, "FailedUpdateRegistrationToken", "Updating registration token failed")
|
||||||
log.Error(err, "Failed to get new registration token")
|
log.Error(err, "Failed to get new registration token")
|
||||||
@@ -134,7 +116,11 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated := runner.DeepCopy()
|
updated := runner.DeepCopy()
|
||||||
updated.Status.Registration = reg
|
updated.Status.Registration = v1alpha1.RunnerStatusRegistration{
|
||||||
|
Repository: runner.Spec.Repository,
|
||||||
|
Token: rt.GetToken(),
|
||||||
|
ExpiresAt: metav1.NewTime(rt.GetExpiresAt().Time),
|
||||||
|
}
|
||||||
|
|
||||||
if err := r.Status().Update(ctx, updated); err != nil {
|
if err := r.Status().Update(ctx, updated); err != nil {
|
||||||
log.Error(err, "Failed to update runner status")
|
log.Error(err, "Failed to update runner status")
|
||||||
@@ -226,109 +212,31 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunnerReconciler) newRegistration(ctx context.Context, repo string) (v1alpha1.RunnerStatusRegistration, error) {
|
|
||||||
var reg v1alpha1.RunnerStatusRegistration
|
|
||||||
|
|
||||||
rt, err := r.getRegistrationToken(ctx, repo)
|
|
||||||
if err != nil {
|
|
||||||
return reg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
expiresAt, err := time.Parse(time.RFC3339, rt.ExpiresAt)
|
|
||||||
if err != nil {
|
|
||||||
return reg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reg.Repository = repo
|
|
||||||
reg.Token = rt.Token
|
|
||||||
reg.ExpiresAt = metav1.NewTime(expiresAt)
|
|
||||||
|
|
||||||
return reg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RunnerReconciler) getRegistrationToken(ctx context.Context, repo string) (GitHubRegistrationToken, error) {
|
|
||||||
var regToken GitHubRegistrationToken
|
|
||||||
|
|
||||||
req, err := r.GitHubClient.NewRequest("POST", fmt.Sprintf("/repos/%s/actions/runners/registration-token", repo), nil)
|
|
||||||
if err != nil {
|
|
||||||
return regToken, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := r.GitHubClient.Do(ctx, req, ®Token)
|
|
||||||
if err != nil {
|
|
||||||
return regToken, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode != 201 {
|
|
||||||
return regToken, fmt.Errorf("unexpected status: %d", res.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return regToken, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RunnerReconciler) unregisterRunner(ctx context.Context, repo, name string) (bool, error) {
|
func (r *RunnerReconciler) unregisterRunner(ctx context.Context, repo, name string) (bool, error) {
|
||||||
runners, err := r.listRunners(ctx, repo)
|
runners, err := r.GitHubClient.ListRunners(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id := 0
|
id := int64(0)
|
||||||
for _, runner := range runners.Runners {
|
for _, runner := range runners {
|
||||||
if runner.Name == name {
|
if runner.GetName() == name {
|
||||||
id = runner.ID
|
id = runner.GetID()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if id == 0 {
|
if id == int64(0) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.removeRunner(ctx, repo, id); err != nil {
|
if err := r.GitHubClient.RemoveRunner(ctx, repo, id); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunnerReconciler) listRunners(ctx context.Context, repo string) (GitHubRunnerList, error) {
|
|
||||||
runners := GitHubRunnerList{}
|
|
||||||
|
|
||||||
req, err := r.GitHubClient.NewRequest("GET", fmt.Sprintf("/repos/%s/actions/runners", repo), nil)
|
|
||||||
if err != nil {
|
|
||||||
return runners, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := r.GitHubClient.Do(ctx, req, &runners)
|
|
||||||
if err != nil {
|
|
||||||
return runners, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return runners, fmt.Errorf("unexpected status: %d", res.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return runners, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RunnerReconciler) removeRunner(ctx context.Context, repo string, id int) error {
|
|
||||||
req, err := r.GitHubClient.NewRequest("DELETE", fmt.Sprintf("/repos/%s/actions/runners/%d", repo, id), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := r.GitHubClient.Do(ctx, req, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode != 204 {
|
|
||||||
return fmt.Errorf("unexpected status: %d", res.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
||||||
var (
|
var (
|
||||||
privileged bool = true
|
privileged bool = true
|
||||||
|
|||||||
86
github/fake/fake.go
Normal file
86
github/fake/fake.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package fake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegistrationToken = "fake-registration-token"
|
||||||
|
|
||||||
|
RunnersListBody = `
|
||||||
|
{
|
||||||
|
"total_count": 2,
|
||||||
|
"runners": [
|
||||||
|
{"id": 1, "name": "test1", "os": "linux", "status": "online"},
|
||||||
|
{"id": 2, "name": "test2", "os": "linux", "status": "offline"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
Status int
|
||||||
|
Body string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(h.Status)
|
||||||
|
fmt.Fprintf(w, h.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer() *httptest.Server {
|
||||||
|
routes := map[string]handler{
|
||||||
|
// For CreateRegistrationToken
|
||||||
|
"/repos/test/valid/actions/runners/registration-token": handler{
|
||||||
|
Status: http.StatusCreated,
|
||||||
|
Body: fmt.Sprintf("{\"token\": \"%s\", \"expires_at\": \"%s\"}", RegistrationToken, time.Now().Add(time.Hour*1).Format(time.RFC3339)),
|
||||||
|
},
|
||||||
|
"/repos/test/invalid/actions/runners/registration-token": handler{
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Body: fmt.Sprintf("{\"token\": \"%s\", \"expires_at\": \"%s\"}", RegistrationToken, time.Now().Add(time.Hour*1).Format(time.RFC3339)),
|
||||||
|
},
|
||||||
|
"/repos/test/error/actions/runners/registration-token": handler{
|
||||||
|
Status: http.StatusBadRequest,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// For ListRunners
|
||||||
|
"/repos/test/valid/actions/runners": handler{
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Body: RunnersListBody,
|
||||||
|
},
|
||||||
|
"/repos/test/invalid/actions/runners": handler{
|
||||||
|
Status: http.StatusNoContent,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
"/repos/test/error/actions/runners": handler{
|
||||||
|
Status: http.StatusBadRequest,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// For RemoveRunner
|
||||||
|
"/repos/test/valid/actions/runners/1": handler{
|
||||||
|
Status: http.StatusNoContent,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
"/repos/test/invalid/actions/runners/1": handler{
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
"/repos/test/error/actions/runners/1": handler{
|
||||||
|
Status: http.StatusBadRequest,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
for path, handler := range routes {
|
||||||
|
h := handler
|
||||||
|
mux.Handle(path, &h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return httptest.NewServer(mux)
|
||||||
|
}
|
||||||
147
github/github.go
Normal file
147
github/github.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bradleyfalzon/ghinstallation"
|
||||||
|
"github.com/google/go-github/v31/github"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
*github.Client
|
||||||
|
regTokens map[string]*github.RegistrationToken
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a client authenticated as a GitHub App.
|
||||||
|
func NewClient(appID, installationID int64, privateKeyPath string) (*Client, error) {
|
||||||
|
tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, appID, installationID, privateKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("authentication failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
Client: github.NewClient(&http.Client{Transport: tr}),
|
||||||
|
regTokens: map[string]*github.RegistrationToken{},
|
||||||
|
mu: sync.Mutex{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a client authenticated with personal access token.
|
||||||
|
func NewClientWithAccessToken(token string) (*Client, error) {
|
||||||
|
tc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
|
||||||
|
&oauth2.Token{AccessToken: token},
|
||||||
|
))
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
Client: github.NewClient(tc),
|
||||||
|
regTokens: map[string]*github.RegistrationToken{},
|
||||||
|
mu: sync.Mutex{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegistrationToken returns a registration token tied with the name of repository and runner.
|
||||||
|
func (c *Client) GetRegistrationToken(ctx context.Context, repository, name string) (*github.RegistrationToken, error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
owner, repo, err := splitOwnerAndRepo(repository)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf("%s/%s", repo, name)
|
||||||
|
rt, ok := c.regTokens[key]
|
||||||
|
if ok && rt.GetExpiresAt().After(time.Now().Add(-10*time.Minute)) {
|
||||||
|
return rt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rt, res, err := c.Client.Actions.CreateRegistrationToken(ctx, owner, repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create registration token: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != 201 {
|
||||||
|
return nil, fmt.Errorf("unexpected status: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.regTokens[key] = rt
|
||||||
|
go func() {
|
||||||
|
c.cleanup()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return rt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveRunner removes a runner with specified runner ID from repocitory.
|
||||||
|
func (c *Client) RemoveRunner(ctx context.Context, repository string, runnerID int64) error {
|
||||||
|
owner, repo, err := splitOwnerAndRepo(repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.Client.Actions.RemoveRunner(ctx, owner, repo, runnerID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to remove runner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != 204 {
|
||||||
|
return fmt.Errorf("unexpected status: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRunners returns a list of runners of specified repository name.
|
||||||
|
func (c *Client) ListRunners(ctx context.Context, repository string) ([]*github.Runner, error) {
|
||||||
|
var runners []*github.Runner
|
||||||
|
|
||||||
|
owner, repo, err := splitOwnerAndRepo(repository)
|
||||||
|
if err != nil {
|
||||||
|
return runners, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := github.ListOptions{PerPage: 10}
|
||||||
|
for {
|
||||||
|
list, res, err := c.Client.Actions.ListRunners(ctx, owner, repo, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return runners, fmt.Errorf("failed to remove runner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
runners = append(runners, list.Runners...)
|
||||||
|
if res.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opts.Page = res.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
return runners, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup removes expired registration tokens.
|
||||||
|
func (c *Client) cleanup() {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
for key, rt := range c.regTokens {
|
||||||
|
if rt.GetExpiresAt().Before(time.Now()) {
|
||||||
|
delete(c.regTokens, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitOwnerAndRepo splits specified repository name to the owner and repo name.
|
||||||
|
func splitOwnerAndRepo(repo string) (string, string, error) {
|
||||||
|
chunk := strings.Split(repo, "/")
|
||||||
|
if len(chunk) != 2 {
|
||||||
|
return "", "", errors.New("invalid repository name")
|
||||||
|
}
|
||||||
|
return chunk[0], chunk[1], nil
|
||||||
|
}
|
||||||
124
github/github_test.go
Normal file
124
github/github_test.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v31/github"
|
||||||
|
"github.com/summerwind/actions-runner-controller/github/fake"
|
||||||
|
)
|
||||||
|
|
||||||
|
var server *httptest.Server
|
||||||
|
|
||||||
|
func newTestClient() *Client {
|
||||||
|
client, err := NewClientWithAccessToken("token")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL, err := url.Parse(server.URL + "/")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
client.Client.BaseURL = baseURL
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
server = fake.NewServer()
|
||||||
|
defer server.Close()
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRegistrationToken(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
repo string
|
||||||
|
token string
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{repo: "test/valid", token: fake.RegistrationToken, err: false},
|
||||||
|
{repo: "test/invalid", token: "", err: true},
|
||||||
|
{repo: "test/error", token: "", err: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
client := newTestClient()
|
||||||
|
for i, tt := range tests {
|
||||||
|
rt, err := client.GetRegistrationToken(context.Background(), tt.repo, "test")
|
||||||
|
if !tt.err && err != nil {
|
||||||
|
t.Errorf("[%d] unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
if tt.token != rt.GetToken() {
|
||||||
|
t.Errorf("[%d] unexpected token: %v", i, rt.GetToken())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListRunners(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
repo string
|
||||||
|
length int
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{repo: "test/valid", length: 2, err: false},
|
||||||
|
{repo: "test/invalid", length: 0, err: true},
|
||||||
|
{repo: "test/error", length: 0, err: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
client := newTestClient()
|
||||||
|
for i, tt := range tests {
|
||||||
|
runners, err := client.ListRunners(context.Background(), tt.repo)
|
||||||
|
if !tt.err && err != nil {
|
||||||
|
t.Errorf("[%d] unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
if tt.length != len(runners) {
|
||||||
|
t.Errorf("[%d] unexpected runners list: %v", i, runners)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveRunner(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
repo string
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{repo: "test/valid", err: false},
|
||||||
|
{repo: "test/invalid", err: true},
|
||||||
|
{repo: "test/error", err: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
client := newTestClient()
|
||||||
|
for i, tt := range tests {
|
||||||
|
err := client.RemoveRunner(context.Background(), tt.repo, int64(1))
|
||||||
|
if !tt.err && err != nil {
|
||||||
|
t.Errorf("[%d] unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCleanup(t *testing.T) {
|
||||||
|
token := "token"
|
||||||
|
|
||||||
|
client := newTestClient()
|
||||||
|
client.regTokens = map[string]*github.RegistrationToken{
|
||||||
|
"active": &github.RegistrationToken{
|
||||||
|
Token: &token,
|
||||||
|
ExpiresAt: &github.Timestamp{Time: time.Now().Add(time.Hour * 1)},
|
||||||
|
},
|
||||||
|
"expired": &github.RegistrationToken{
|
||||||
|
Token: &token,
|
||||||
|
ExpiresAt: &github.Timestamp{Time: time.Now().Add(-time.Hour * 1)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client.cleanup()
|
||||||
|
if _, ok := client.regTokens["active"]; !ok {
|
||||||
|
t.Errorf("active token was accidentally removed")
|
||||||
|
}
|
||||||
|
if _, ok := client.regTokens["expired"]; ok {
|
||||||
|
t.Errorf("expired token still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
8
go.mod
8
go.mod
@@ -3,18 +3,14 @@ module github.com/summerwind/actions-runner-controller
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
|
||||||
github.com/bradleyfalzon/ghinstallation v1.1.1
|
github.com/bradleyfalzon/ghinstallation v1.1.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/go-logr/logr v0.1.0
|
github.com/go-logr/logr v0.1.0
|
||||||
github.com/google/go-github v17.0.0+incompatible
|
github.com/google/go-github/v31 v31.0.0
|
||||||
github.com/google/go-github/v29 v29.0.3
|
|
||||||
github.com/onsi/ginkgo v1.8.0
|
github.com/onsi/ginkgo v1.8.0
|
||||||
github.com/onsi/gomega v1.5.0
|
github.com/onsi/gomega v1.5.0
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275
|
github.com/stretchr/testify v1.4.0 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
|
||||||
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
|
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
|
||||||
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
|
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
|
||||||
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
|
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
|
||||||
|
|||||||
13
go.sum
13
go.sum
@@ -18,10 +18,6 @@ github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
|||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
@@ -120,12 +116,10 @@ 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.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
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-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 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
||||||
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
||||||
github.com/google/go-github/v29 v29.0.3 h1:IktKCTwU//aFHnpA+2SLIi7Oo9uhAzgsdZNbcAqhgdc=
|
github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo=
|
||||||
github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
@@ -237,6 +231,7 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
@@ -343,8 +338,6 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn
|
|||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
|||||||
29
main.go
29
main.go
@@ -17,18 +17,14 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/bradleyfalzon/ghinstallation"
|
|
||||||
"github.com/google/go-github/v29/github"
|
|
||||||
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/summerwind/actions-runner-controller/controllers"
|
"github.com/summerwind/actions-runner-controller/controllers"
|
||||||
"golang.org/x/oauth2"
|
"github.com/summerwind/actions-runner-controller/github"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||||
@@ -38,8 +34,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultRunnerImage = "summerwind/actions-runner:v2.165.2"
|
defaultRunnerImage = "summerwind/actions-runner:latest"
|
||||||
defaultDockerImage = "docker:19.03.6-dind"
|
defaultDockerImage = "docker:dind"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -56,6 +52,9 @@ func init() {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
|
err error
|
||||||
|
ghClient *github.Client
|
||||||
|
|
||||||
metricsAddr string
|
metricsAddr string
|
||||||
enableLeaderElection bool
|
enableLeaderElection bool
|
||||||
|
|
||||||
@@ -66,8 +65,6 @@ func main() {
|
|||||||
ghAppID int64
|
ghAppID int64
|
||||||
ghAppInstallationID int64
|
ghAppInstallationID int64
|
||||||
ghAppPrivateKey string
|
ghAppPrivateKey string
|
||||||
|
|
||||||
ghClient *github.Client
|
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
||||||
@@ -111,17 +108,17 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, ghAppID, ghAppInstallationID, ghAppPrivateKey)
|
ghClient, err = github.NewClient(ghAppID, ghAppInstallationID, ghAppPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: Invalid GitHub App credentials: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error: Failed to create GitHub client: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
ghClient = github.NewClient(&http.Client{Transport: tr})
|
|
||||||
} else if ghToken != "" {
|
} else if ghToken != "" {
|
||||||
tc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
|
ghClient, err = github.NewClientWithAccessToken(ghToken)
|
||||||
&oauth2.Token{AccessToken: ghToken},
|
if err != nil {
|
||||||
))
|
fmt.Fprintf(os.Stderr, "Error: Failed to create GitHub client: %v\n", err)
|
||||||
ghClient = github.NewClient(tc)
|
os.Exit(1)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(os.Stderr, "Error: GitHub App credentials or personal access token must be specified.")
|
fmt.Fprintln(os.Stderr, "Error: GitHub App credentials or personal access token must be specified.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
NAME ?= summerwind/actions-runner
|
NAME ?= summerwind/actions-runner
|
||||||
|
|
||||||
RUNNER_VERSION ?= 2.168.0
|
RUNNER_VERSION ?= 2.169.1
|
||||||
DOCKER_VERSION ?= 19.03.8
|
DOCKER_VERSION ?= 19.03.8
|
||||||
|
|
||||||
docker-build:
|
docker-build:
|
||||||
|
|||||||
Reference in New Issue
Block a user