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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

Let a job start service containers beside it

c1929d2fceb5e9e65204d5eef907d0781b9a5391 · Keenan Nemetz · 5d ago · parent 1d06b008

ci/agent/agent.go +65−11

@@ -107,6 +107,10 @@ type runnerJob struct {
107 107 ImageSHA string `json:"image_sha,omitempty"`
108 108 // Env is the job's declared environment, pinned when the run was queued.
109 109 Env map[string]string `json:"env,omitempty"`
110 // Services are the containers started beside the job, in declaration order. A job
111 // with services asked for network: bridge, and the runner gives the job and its
112 // services one network for this attempt.
113 Services []runnerService `json:"services,omitempty"`
110 114 // Secrets are the declared secrets this repository has, and Missing are the
111 115 // names it declared that it does not. A missing one leaves its variable unset and
112 116 // gets a line in the log; it is not a failure, because a workflow is allowed an
@@ -131,6 +135,13 @@ type runnerCredential struct {
131 135 Fingerprint string `json:"fingerprint"`
132 136 }
133 137
138 // runnerService is one container the job asked to run beside it.
139 type runnerService struct {
140 ID string `json:"id"`
141 Image string `json:"image"`
142 Env map[string]string `json:"env,omitempty"`
143 }
144
134 145 // runnerSecret is one delivered value and the version it came from. The version is
135 146 // what the attempt record reports, so a result says which value ran without
136 147 // carrying it.
@@ -288,6 +299,7 @@ func Run(ctx context.Context, opts Options) error {
288 299 }
289 300 cleanupJobTrees(cache)
290 301 cleanupStaleContainers(box)
302 cleanupStaleNetworks(box)
291 303 // Bound the saved checkouts before work starts, the same way the job cache is
292 304 // bound below: a runner whose disk filled up while it was not watching should
293 305 // not start by failing a job.
@@ -601,7 +613,10 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
601 613 s.finish(remote, co, job, log, 1, nil, nil, nil, box)
602 614 return
603 615 }
616 jobBox := &jobSandbox{}
617 defer jobBox.Stop()
604 618 fail := func(format string, args ...any) {
619 jobBox.StopWithLogs(log)
605 620 msg := mask.String(fmt.Sprintf(format, args...))
606 621 fmt.Fprintf(os.Stderr, "vole runner: %s\n", msg)
607 622 fmt.Fprintf(log, "\n%s\n", msg)
@@ -650,6 +665,52 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
650 665 fail("%s", err)
651 666 return
652 667 }
668 // Services are containers beside the job on a network of their own. They start
669 // after the image is resolved so a slow build does not leave a database running,
670 // and before the job so their names resolve for the first step.
671 if len(job.Services) > 0 {
672 netName := serviceNetworkName(box, job)
673 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
674 net, err := container.CreateNetwork(ctx, box.Config, netName, box.labels(job))
675 cancel()
676 if err != nil {
677 fail("%s", err)
678 return
679 }
680 jobBox.network = net
681 serviceConfig := boxConfig
682 serviceConfig.Network = netName
683 boxConfig.Network = netName
684 ids := make([]string, 0, len(job.Services))
685 for _, svc := range job.Services {
686 c, err := container.StartService(serviceConfig, container.ServiceSpec{
687 Name: serviceContainerName(box, job, svc.ID),
688 Alias: svc.ID,
689 Image: svc.Image,
690 Env: svc.Env,
691 Labels: box.labels(job),
692 })
693 if err != nil {
694 fail("%s", err)
695 return
696 }
697 jobBox.services = append(jobBox.services, c)
698 jobBox.serviceIDs = append(jobBox.serviceIDs, svc.ID)
699 ids = append(ids, svc.ID+" ("+svc.Image+")")
700 }
701 fmt.Fprintf(log, "services: %s\n", strings.Join(ids, ", "))
702 for i, c := range jobBox.services {
703 running, err := c.Running(context.Background())
704 if err != nil {
705 fail("service %s: %s", job.Services[i].ID, err)
706 return
707 }
708 if !running {
709 fail("service %s exited before the steps started", job.Services[i].ID)
710 return
711 }
712 }
713 }
653 714 cacheMounts := s.cacheFor(job)
654 715 mounts := cacheMounts
655 716 // The run directory is mounted at /run/vole for the pinned event payload and for
@@ -744,11 +805,7 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
744 805 fail("%s", err)
745 806 return
746 807 }
747 defer func() {
748 if sandbox != nil {
749 sandbox.Stop()
750 }
751 }()
808 jobBox.job = sandbox
752 809
753 810 steps := make([]runs.StepResult, 0, len(job.Steps))
754 811 // The job's budget starts with its first step. An image build has its own cap, so a
@@ -790,8 +847,7 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
790 847 // already wrote the line to the log. Keep the partial attempt: the log and
791 848 // the timings are what a reader asks for first after "what had it done".
792 849 steps = append(steps, result)
793 sandbox.Stop()
794 sandbox = nil
850 jobBox.StopWithLogs(log)
795 851 s.finish(remote, co, job, log, code, steps, nil, nil, box)
796 852 return
797 853 }
@@ -800,8 +856,7 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
800 856 result.LogSize = log.Len() - logStart
801 857 result.Finished = time.Now().UTC()
802 858 steps = append(steps, result)
803 sandbox.Stop()
804 sandbox = nil
859 jobBox.StopWithLogs(log)
805 860 s.finish(remote, co, job, log, code, steps, nil, nil, box)
806 861 return
807 862 }
@@ -810,8 +865,7 @@ func (s *runnerSession) run(remote, cache string, job *runnerJob, lease time.Dur
810 865 // The steps are done. Stop the container before reading artifacts or deploying a
811 866 // site, so a process the workflow left in the background cannot change the files
812 867 // while the runner is publishing them.
813 sandbox.Stop()
814 sandbox = nil
868 jobBox.StopJob()
815 869 arts, releaseArts, err := publishArtifacts(remote, co.Work, job, log)
816 870 if err != nil {
817 871 fail("%s", err)