Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Let a job declare the network it needs

d79580247b8f33f7ffdf2f05847733cad12c187a · Keenan Nemetz · 7d ago · parent 4ac42680

Let a job declare the network it needs

A runner's --container-network decided the network for every job it took, so a
machine that could reach the network gave it to builds that never asked, and a
job that did need one could be handed to a machine that had none. The docs said
"add bridge only when a job needs it", which no workflow could express.

A job now says `network: none` or `network: bridge`. The request is pinned with
the run, and the lease only hands a bridge job to a runner that advertises the
capability, so a job waits for a capable machine instead of failing on one that
never could. The runner applies the job's request to its container, which means a
bridge runner can still withhold the network from a job that asked for none.

A job that declares nothing keeps the runner's own setting, which is what every
workflow meant before this field existed. The local run applies the same rule and
refuses a bridge job when it was started without one, so `vole workflow run` either
matches CI or says what to change on the command line.

The workflows page, the run page, and the runner's log line now say what a job
asked for and what it ran with. verify.yaml and release.yaml are deliberately not
in this change: the instance validates a pushed workflow with the binary it is
running, so they can declare the field once that binary knows it.

Closes #159.

ci/agent/sandbox.go +23

@@ -24,6 +24,7 @@ import (
24 24 "strings"
25 25 "syscall"
26 26
27 "github.com/rodent-software/vole/ci"
27 28 "github.com/rodent-software/vole/ci/container"
28 29 )
29 30
@@ -63,6 +64,28 @@ func containerOptions(opts Options, cache string) (runnerBox, error) {
63 64 }, nil
64 65 }
65 66
67 // networkFor is the container settings for one job. A job that names a network gets
68 // exactly that: `network: none` withholds the network even on a runner that could
69 // give one, and `network: bridge` is refused here on a runner that cannot, because
70 // running it without the network it asked for would fail later and less clearly than
71 // saying so at the start. A job that names nothing gets the runner's own default,
72 // which is what every workflow meant before the field existed.
73 func (b runnerBox) networkFor(job *runnerJob) (container.Config, error) {
74 cfg := b.Config
75 if job.Network == "" {
76 return cfg, nil
77 }
78 if err := ci.ValidNetwork(job.Network); err != nil {
79 return cfg, fmt.Errorf("job %s: %w", job.ID, err)
80 }
81 if job.Network == ci.NetworkBridge && cfg.Network != ci.NetworkBridge {
82 return cfg, fmt.Errorf("job %s asks for network: bridge but this runner was started with "+
83 "--container-network %s, so it cannot provide one", job.ID, cfg.Network)
84 }
85 cfg.Network = job.Network
86 return cfg, nil
87 }
88
66 89 // labels are how a container says which runner and run it belongs to.
67 90 func (b runnerBox) labels(job *runnerJob) map[string]string {
68 91 return map[string]string{