-
Notifications
You must be signed in to change notification settings - Fork 35
feat(ibmcloud): add GitHub Actions runner support for IBM Power and IBM Z #831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 14 commits
c9a4b05
9af3e13
f68b509
68f31f4
78d423b
753b7ef
9e03696
7829062
a6893f0
60e93b8
ef87753
265345e
de8fc1f
9f02ad6
246c1c0
28e55f7
107ab7f
43b2865
93c91ee
7c2ee65
a1d6416
baad7fb
d75b79c
9761706
a8e6f9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| name: s390x Runner Smoke Test | ||
| on: workflow_dispatch | ||
| jobs: | ||
| smoke-test: | ||
| runs-on: [self-hosted, S390X] | ||
| steps: | ||
| - name: Check architecture | ||
| run: | | ||
| echo "Architecture: $(uname -m)" | ||
| cat /etc/os-release | grep PRETTY_NAME | ||
| echo "Runner is alive on $(arch)" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| package params | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/redhat-developer/mapt/pkg/integrations/cirrus" | ||
| "github.com/redhat-developer/mapt/pkg/integrations/github" | ||
| "github.com/redhat-developer/mapt/pkg/integrations/gitlab" | ||
|
|
@@ -73,9 +77,14 @@ const ( | |
| CreateCmdName string = "create" | ||
| DestroyCmdName string = "destroy" | ||
|
|
||
| ghActionsRunnerToken string = "ghactions-runner-token" | ||
| ghActionsRunnerRepo string = "ghactions-runner-repo" | ||
| ghActionsRunnerLabels string = "ghactions-runner-labels" | ||
| ghActionsRunnerToken string = "ghactions-runner-token" | ||
| ghActionsRunnerRepo string = "ghactions-runner-repo" | ||
| ghActionsRunnerLabels string = "ghactions-runner-labels" | ||
| ghActionsRunnerImageRepo string = "ghactions-runner-image-repo" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably we dont want to expose this...you can set it in the logic (not in cmd) and also instead of download the zip pointing to main...use tags and download source from releases
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since the repo was moved into the |
||
| // TODO: once the RHEL script is merged to https://github.com/IBM/action-runner-image-pz, | ||
| // switch default from deekay2310 fork to IBM upstream. | ||
| ghActionsRunnerImageRepoDefault string = "https://github.com/deekay2310/action-runner-image-pz.git" | ||
| GHActionsRunnerImageRepoDesc string = "Git clone URL for the action-runner-image-pz repository, used to build the GitHub Actions runner from source on ppc64le/s390x (no official binaries exist for these architectures)" | ||
|
|
||
| cirrusPWToken string = "it-cirrus-pw-token" | ||
| cirrusPWTokenDesc string = "Add mapt target as a cirrus persistent worker. The value will hold a valid token to be used by cirrus cli to join the project." | ||
|
|
@@ -278,18 +287,54 @@ func AddGHActionsFlags(fs *pflag.FlagSet) { | |
| fs.StringP(ghActionsRunnerToken, "", "", GHActionsRunnerTokenDesc) | ||
| fs.StringP(ghActionsRunnerRepo, "", "", GHActionsRunnerRepoDesc) | ||
| fs.StringSlice(ghActionsRunnerLabels, nil, GHActionsRunnerLabelsDesc) | ||
| fs.StringP(ghActionsRunnerImageRepo, "", ghActionsRunnerImageRepoDefault, GHActionsRunnerImageRepoDesc) | ||
| } | ||
|
|
||
| func GithubRunnerArgs() *github.GithubRunnerArgs { | ||
| if viper.IsSet(ghActionsRunnerToken) { | ||
| return &github.GithubRunnerArgs{ | ||
| Token: viper.GetString(ghActionsRunnerToken), | ||
| RepoURL: viper.GetString(ghActionsRunnerRepo), | ||
| Labels: viper.GetStringSlice(ghActionsRunnerLabels), | ||
| Platform: &github.Linux, | ||
| Arch: linuxArchAsGithubActionsArch( | ||
| viper.GetString(LinuxArch)), | ||
| token := viper.GetString(ghActionsRunnerToken) | ||
| repoURL := viper.GetString(ghActionsRunnerRepo) | ||
| pat := os.Getenv("GITHUB_TOKEN") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user doesn't provide |
||
|
|
||
| if token == "" && pat == "" { | ||
| return nil | ||
| } | ||
|
|
||
| if token == "" && repoURL == "" { | ||
| logging.Error("--ghactions-runner-repo is required for GitHub Actions runner setup") | ||
| return nil | ||
| } | ||
|
|
||
| if token == "" { | ||
| logging.Info("no --ghactions-runner-token provided, auto-generating from GITHUB_TOKEN") | ||
| var err error | ||
| token, err = github.GenerateRegistrationToken(pat, repoURL) | ||
| if err != nil { | ||
| logging.Errorf("failed to auto-generate runner registration token: %v", err) | ||
| return nil | ||
| } | ||
| logging.Info("runner registration token generated successfully") | ||
| } | ||
|
|
||
| imageRepo := viper.GetString(ghActionsRunnerImageRepo) | ||
| if imageRepo != "" { | ||
| if err := validateRunnerImageRepo(imageRepo); err != nil { | ||
| logging.Errorf("invalid --ghactions-runner-image-repo: %v", err) | ||
| return nil | ||
| } | ||
| } | ||
| return &github.GithubRunnerArgs{ | ||
| Token: token, | ||
| RepoURL: repoURL, | ||
| Labels: viper.GetStringSlice(ghActionsRunnerLabels), | ||
| Platform: &github.Linux, | ||
| Arch: linuxArchAsGithubActionsArch(viper.GetString(LinuxArch)), | ||
| RunnerImageRepo: imageRepo, | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| func validateRunnerImageRepo(repo string) error { | ||
| if !strings.HasPrefix(repo, "https://") { | ||
| return fmt.Errorf("only HTTPS URLs are allowed, got: %s", repo) | ||
| } | ||
| return nil | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
@@ -359,6 +404,10 @@ func linuxArchAsGithubActionsArch(arch string) *github.Arch { | |
| switch arch { | ||
| case "x86_64": | ||
| return &github.Amd64 | ||
| case "ppc64le": | ||
| return &github.Ppc64le | ||
| case "s390x": | ||
| return &github.S390x | ||
| } | ||
| return &github.Arm64 | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package github | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
| "strings" | ||
| ) | ||
|
|
||
| type registrationTokenResponse struct { | ||
| Token string `json:"token"` | ||
| ExpiresAt string `json:"expires_at"` | ||
| } | ||
|
|
||
| // GenerateRegistrationToken calls the GitHub API to create a short-lived | ||
| // runner registration token for the given repository. | ||
| // pat is a Personal Access Token with repo admin scope. | ||
| // repoURL is in the form "owner/repo" or "https://github.com/owner/repo". | ||
| func GenerateRegistrationToken(pat, repoURL string) (string, error) { | ||
| ownerRepo := repoURL | ||
| ownerRepo = strings.TrimPrefix(ownerRepo, "https://github.com/") | ||
| ownerRepo = strings.TrimPrefix(ownerRepo, "http://github.com/") | ||
| ownerRepo = strings.TrimSuffix(ownerRepo, "/") | ||
|
|
||
| parts := strings.Split(ownerRepo, "/") | ||
| if len(parts) != 2 || parts[0] == "" || parts[1] == "" { | ||
| return "", fmt.Errorf("invalid repo format %q, expected owner/repo", repoURL) | ||
| } | ||
|
|
||
| url := fmt.Sprintf("https://api.github.com/repos/%s/%s/actions/runners/registration-token", parts[0], parts[1]) | ||
|
deekay2310 marked this conversation as resolved.
|
||
|
|
||
| req, err := http.NewRequest(http.MethodPost, url, nil) | ||
| if err != nil { | ||
| return "", fmt.Errorf("creating request: %w", err) | ||
| } | ||
| req.Header.Set("Authorization", "token "+pat) | ||
| req.Header.Set("Accept", "application/vnd.github+json") | ||
| req.Header.Set("X-GitHub-Api-Version", "2022-11-28") | ||
|
|
||
| resp, err := http.DefaultClient.Do(req) | ||
| if err != nil { | ||
| return "", fmt.Errorf("calling GitHub API: %w", err) | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| defer func() { _ = resp.Body.Close() }() | ||
|
|
||
| body, err := io.ReadAll(resp.Body) | ||
| if err != nil { | ||
| return "", fmt.Errorf("reading response: %w", err) | ||
| } | ||
|
|
||
| if resp.StatusCode != http.StatusCreated { | ||
| return "", fmt.Errorf("GitHub API returned %d: %s (ensure GITHUB_TOKEN has admin scope on the repo)", resp.StatusCode, string(body)) | ||
| } | ||
|
|
||
| var tokenResp registrationTokenResponse | ||
| if err := json.Unmarshal(body, &tokenResp); err != nil { | ||
| return "", fmt.Errorf("parsing response: %w", err) | ||
| } | ||
|
|
||
| if tokenResp.Token == "" { | ||
| return "", fmt.Errorf("empty token in GitHub API response") | ||
| } | ||
|
|
||
| return tokenResp.Token, nil | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.