-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathrunner.go
200 lines (162 loc) · 5.92 KB
/
runner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package main
import (
"context"
"fmt"
"path/filepath"
"strings"
)
type Runner struct {
RunnerOpts *RunnerOpts
EventOpts *EventOpts
SecretOpts *SecretOpts
Repo *RepoInfo
Workflow *Workflow
}
func NewRunner(
repo *RepoInfo,
workflow *Workflow,
runnerOpts *RunnerOpts,
eventOpts *EventOpts,
secretOpts *SecretOpts,
) *Runner {
return &Runner{
RunnerOpts: runnerOpts,
EventOpts: eventOpts,
SecretOpts: secretOpts,
Repo: repo,
Workflow: workflow,
}
}
type RunnerContainer struct {
RunID string
Ctr *Container
}
func (r *Runner) Container(runID string) (*RunnerContainer, error) {
var (
repo = r.Repo
workflow = r.Workflow
ctr = r.RunnerOpts.Ctr
)
// configure internal components
ctr = ctr.With(dag.Ghx().Binary)
ctr = ctr.With(dag.ActionsArtifactService().BindAsService)
ctr = ctr.With(dag.ActionsArtifactcacheService().BindAsService)
// configure docker using docker host when docker is enabled and dind is not enabled
if r.RunnerOpts.UseNativeDocker && !r.RunnerOpts.UseDind {
switch {
case strings.HasPrefix(r.RunnerOpts.DockerHost, "unix://"):
dh := strings.TrimPrefix(r.RunnerOpts.DockerHost, "unix://")
ctr = ctr.WithUnixSocket("/var/run/docker.sock", dag.Host().UnixSocket(dh))
ctr = ctr.WithEnvVariable("DOCKER_HOST", "unix:///var/run/docker.sock")
case strings.HasPrefix(r.RunnerOpts.DockerHost, "tcp://"):
ctr = ctr.WithEnvVariable("DOCKER_HOST", r.RunnerOpts.DockerHost)
default:
return nil, fmt.Errorf("unsupported docker host: %s", r.RunnerOpts.DockerHost)
}
}
// configure docker-in-dagger service
if r.RunnerOpts.UseDind {
ctr = ctr.With(dag.Docker().BindAsService)
}
// GHX specific directory configuration -- TODO: refactor this later to be more generic for runners
var (
metadata = "/home/runner/_temp/gale/metadata"
actions = "/home/runner/_temp/gale/actions"
cacheOpts = ContainerWithMountedCacheOpts{Sharing: Shared}
)
ctr = ctr.WithEnvVariable("GHX_METADATA_DIR", metadata)
ctr = ctr.WithMountedCache(metadata, dag.CacheVolume("gale-metadata"), cacheOpts)
ctr = ctr.WithEnvVariable("GHX_ACTIONS_DIR", actions)
ctr = ctr.WithMountedCache(actions, dag.CacheVolume("gale-actions"), cacheOpts)
// Configure repository
workdir := fmt.Sprintf("/home/runner/work/%s/%s", repo.Name, repo.Name)
ctr = ctr.WithMountedDirectory(workdir, repo.Source).WithWorkdir(workdir)
ctr = ctr.WithEnvVariable("GH_REPO", repo.NameWithOwner)
ctr = ctr.WithEnvVariable("GITHUB_WORKSPACE", workdir)
ctr = ctr.WithEnvVariable("GITHUB_REPOSITORY", repo.NameWithOwner)
ctr = ctr.WithEnvVariable("GITHUB_REPOSITORY_OWNER", repo.Owner)
ctr = ctr.WithEnvVariable("GITHUB_REPOSITORY_URL", repo.URL)
ctr = ctr.WithEnvVariable("GITHUB_REF", repo.Ref)
ctr = ctr.WithEnvVariable("GITHUB_REF_NAME", repo.RefName)
ctr = ctr.WithEnvVariable("GITHUB_REF_TYPE", repo.RefType)
ctr = ctr.WithEnvVariable("GITHUB_SHA", repo.SHA)
// Configure workflow context
home := filepath.Join("/home/runner/_temp/_gale/runs", runID)
ctr = ctr.WithMountedDirectory(home, dag.Directory())
ctr = ctr.WithEnvVariable("GHX_HOME", home)
// Configure GitHub token if provided
if r.SecretOpts.Token != nil {
ctr = ctr.WithSecretVariable("GITHUB_TOKEN", r.SecretOpts.Token)
}
// Configure runner debug mode if enabled
if r.RunnerOpts.Debug {
ctr = ctr.WithEnvVariable("RUNNER_DEBUG", "1")
}
// Configure event
eventPath := filepath.Join(home, "run", "event.json")
ctr = ctr.WithEnvVariable("GITHUB_EVENT_NAME", r.EventOpts.Name)
ctr = ctr.WithEnvVariable("GITHUB_EVENT_PATH", eventPath)
ctr = ctr.WithMountedFile(eventPath, r.EventOpts.File)
// Configure workflow
ctr = ctr.WithEnvVariable("GITHUB_RUN_ID", runID)
ctr = ctr.WithEnvVariable("GITHUB_RUN_NUMBER", "1")
ctr = ctr.WithEnvVariable("GITHUB_RUN_ATTEMPT", "1")
ctr = ctr.WithEnvVariable("GITHUB_RETENTION_DAYS", "90")
path := filepath.Join(home, "run", "workflow.yaml")
ctr = ctr.WithMountedFile(path, workflow.Src)
ctr = ctr.WithEnvVariable("GHX_WORKFLOW", workflow.Name)
ctr = ctr.WithEnvVariable("GITHUB_WORKFLOW", workflow.Name)
ctr = ctr.WithEnvVariable("GITHUB_WORKFLOW_REF", workflow.Ref)
ctr = ctr.WithEnvVariable("GITHUB_WORKFLOW_SHA", workflow.SHA)
// Finalize container configuration
ctr = ctr.WithEnvVariable("GALE_CONFIGURED", "true")
return &RunnerContainer{RunID: runID, Ctr: ctr}, nil
}
func (rc *RunnerContainer) RunJob(ctx context.Context, job *Job, conclusion string, needs ...*JobRun) (jr *JobRun,
err error) {
var (
home = filepath.Join("/home/runner/_temp/_gale/runs", rc.RunID)
current = filepath.Join(home, "run/jobs", job.JobID)
stdout = filepath.Join(current, "job_run.log")
)
// base container
ctr := rc.Ctr
// assign container with specific job id to new container to separate each job to its own container
ctr = ctr.WithEnvVariable("GHX_JOB", job.JobID)
// configure container with actual workflow conclusion status
ctr = ctr.WithEnvVariable("GHX_WORKFLOW_CONCLUSION", conclusion)
// mount data directories of the jobs this job depends on
for _, need := range needs {
path := filepath.Join(home, "run/jobs", need.Job.JobID)
ctr = ctr.WithMountedDirectory(path, need.Data)
}
// ensure the job directory exists
ctr = ctr.WithMountedDirectory(current, dag.Directory())
// enable focus mode for the job
ctr = ctr.WithFocus()
// execute the job
ctr = ctr.WithExec(
[]string{"ghx"},
ContainerWithExecOpts{
SkipEntrypoint: true,
RedirectStdout: stdout,
RedirectStderr: stdout,
ExperimentalPrivilegedNesting: true,
InsecureRootCapabilities: false,
},
)
// disable focus mode after the job is executed
ctr = ctr.WithoutFocus()
report, err := parseJobRunReport(ctx, ctr.Directory(current).File("job_run.json"))
if err != nil {
return nil, err
}
jr = &JobRun{
Job: job,
Ctr: ctr,
Data: ctr.Directory(current),
Report: report,
LogFile: ctr.Directory(current).File("job_run.log"),
}
return jr, nil
}