@@ -28,30 +28,20 @@ import (
2828
2929 "github.com/adevinta/vulcan-local/pkg/checktypes"
3030 "github.com/adevinta/vulcan-local/pkg/config"
31+ "github.com/adevinta/vulcan-local/pkg/dockerutil"
3132 "github.com/adevinta/vulcan-local/pkg/generator"
3233 "github.com/adevinta/vulcan-local/pkg/gitservice"
3334 "github.com/adevinta/vulcan-local/pkg/reporting"
3435 "github.com/adevinta/vulcan-local/pkg/results"
3536)
3637
37- const defaultDockerHost = "host.docker.internal"
38+ const dockerHostname = "host.docker.internal"
3839
39- var localRegex = regexp .MustCompile (`(?i)\b(localhost|127.0.0.1)\b` )
40- var dockerHost = ""
41- var execCommand = exec .Command
42-
43- func GetFreePort () (int , error ) {
44- addr , err := net .ResolveTCPAddr ("tcp" , ":0" )
45- if err != nil {
46- return 0 , err
47- }
48- l , err := net .ListenTCP ("tcp" , addr )
49- if err != nil {
50- return 0 , err
51- }
52- defer l .Close ()
53- return l .Addr ().(* net.TCPAddr ).Port , nil
54- }
40+ var (
41+ localRegex = regexp .MustCompile (`(?i)\b(localhost|127.0.0.1)\b` )
42+ dockerHost = ""
43+ execCommand = exec .Command
44+ )
5545
5646func Run (cfg * config.Config , log * logrus.Logger ) (int , error ) {
5747 var err error
@@ -103,20 +93,10 @@ func Run(cfg *config.Config, log *logrus.Logger) (int, error) {
10393 dockerHost = cli .DaemonHost ()
10494 log .Debugf ("Using docker host=%s" , dockerHost )
10595
106- agentIP := getAgentIP (cfg .Conf .IfName , log )
107- if agentIP == "" {
108- return config .ErrorExitCode , fmt .Errorf ("unable to get the agent ip %s" , cfg .Conf .IfName )
109- }
110-
111- hostIP := getHostIP (log )
112- if hostIP == "" {
113- return config .ErrorExitCode , fmt .Errorf ("unable to infer host ip" )
114- }
115-
11696 gs := gitservice .New (log )
11797 defer gs .Shutdown ()
11898 log .Debug ("Generating jobs" )
119- jobs , err := generator .GenerateJobs (cfg , agentIP , hostIP , gs , log )
99+ jobs , err := generator .GenerateJobs (cfg , log )
120100 if err != nil {
121101 return config .ErrorExitCode , fmt .Errorf ("unable to generate checks %+v" , err )
122102 }
@@ -151,10 +131,15 @@ func Run(cfg *config.Config, log *logrus.Logger) (int, error) {
151131 })
152132 }
153133
154- agentPort , err := GetFreePort ()
134+ listenAddr , err := getListenAddr (cli )
135+ if err != nil {
136+ return config .ErrorExitCode , fmt .Errorf ("could not get listen addr: %w" , err )
137+ }
138+ ln , err := net .Listen ("tcp" , listenAddr )
155139 if err != nil {
156- return config .ErrorExitCode , fmt .Errorf ("unable to get a free port for agent %+v" , err )
140+ return config .ErrorExitCode , fmt .Errorf ("unable to listen on %v: %w" , listenAddr , err )
157141 }
142+
158143 agentConfig := agentconfig.Config {
159144 Agent : agentconfig.AgentConfig {
160145 ConcurrentJobs : cfg .Conf .Concurrency ,
@@ -163,8 +148,8 @@ func Run(cfg *config.Config, log *logrus.Logger) (int, error) {
163148 Timeout : 180 ,
164149 },
165150 API : agentconfig.APIConfig {
166- Host : agentIP ,
167- Port : fmt . Sprintf ( ":%d" , agentPort ) ,
151+ Host : dockerHostname ,
152+ Listener : ln ,
168153 },
169154 Check : agentconfig.CheckConfig {
170155 Vars : cfg .Conf .Vars ,
@@ -182,7 +167,7 @@ func Run(cfg *config.Config, log *logrus.Logger) (int, error) {
182167 },
183168 }
184169 beforeRun := func (params backend.RunParams , rc * docker.RunConfig ) error {
185- return beforeCheckRun (params , rc , agentIP , gs , hostIP , cfg .Checks , log )
170+ return beforeCheckRun (params , rc , gs , cfg .Checks , log )
186171 }
187172 backend , err := docker .NewBackend (log , agentConfig , beforeRun )
188173 if err != nil {
@@ -262,79 +247,13 @@ func checkDependencies(cfg *config.Config, log agentlog.Logger) error {
262247 return nil
263248}
264249
265- func GetInterfaceAddr (ifaceName string ) (string , error ) {
266- iface , err := net .InterfaceByName (ifaceName )
267- if err != nil {
268- return "" , err
269- }
270- addrs , err := iface .Addrs ()
271- if err != nil {
272- return "" , err
273- }
274-
275- for _ , addr := range addrs {
276- ip , _ , err := net .ParseCIDR (addr .String ())
277- if err != nil {
278- return "" , err
279- }
280-
281- // Check if it is IPv4.
282- if ip .To4 () != nil {
283- return ip .To4 ().String (), nil
284- }
285- }
286-
287- return "" , fmt .Errorf ("failed to determine Docker agent IP address" )
288- }
289-
290- func getAgentIP (ifacename string , log agentlog.Logger ) string {
291- ip , err := GetInterfaceAddr (ifacename )
292- if err == nil {
293- log .Debugf ("Agent address iface=%s ip=%s" , ifacename , ip )
294- return ip
295- }
296-
297- os := runtime .GOOS
298- switch os {
299- case "darwin" :
300- log .Debugf ("Agent address os=%s ip=%s" , os , defaultDockerHost )
301- return defaultDockerHost
302- case "linux" :
303- // Perhaps the agent is running in a container...
304- ip , err = GetInterfaceAddr ("eth0" )
305- if err == nil {
306- log .Debugf ("Agent address iface=eth0 os=%s ip=%s" , os , ip )
307- return ip
308- }
309- }
310- log .Errorf ("Unable to get agent address iface=%s os=%s" , ifacename , os )
311- return ""
312- }
313-
314- func getHostIP (l agentlog.Logger ) string {
315- if runtime .GOOS == "darwin" {
316- return defaultDockerHost
317- }
318-
319- cmd := exec .Command ("docker" , "run" , "--rm" , "busybox:1.34.1" , "sh" , "-c" , "ip route|awk '/default/ { print $3 }'" )
320- var cmdOut bytes.Buffer
321- cmd .Stdout = & cmdOut
322- err := cmd .Run ()
323- if err != nil {
324- l .Errorf ("unable to get Hostip %v %v" , err , cmdOut .String ())
325- return ""
326- }
327- ip := strings .TrimSuffix (cmdOut .String (), "\n " )
328- l .Debugf ("Hostip=%s" , ip )
329- return ip
330- }
331-
332250// beforeCheckRun is a hook executed by the agent just before a check is run
333251// in. it's used to do some extra configuration needed for some checks to run
334252// properly when they are executed locally.
335- func beforeCheckRun (params backend.RunParams , rc * docker.RunConfig ,
336- agentIP string , gs gitservice.GitService , hostIP string ,
253+ func beforeCheckRun (params backend.RunParams , rc * docker.RunConfig , gs gitservice.GitService ,
337254 checks []config.Check , log * logrus.Logger ) error {
255+ rc .HostConfig .ExtraHosts = []string {dockerHostname + ":host-gateway" }
256+
338257 newTarget := params .Target
339258 // If the asset type is a DockerImage mount the docker socket in case the image is already there,
340259 // and the check can access it.
@@ -345,8 +264,8 @@ func beforeCheckRun(params backend.RunParams, rc *docker.RunConfig,
345264 // Mount the volume in the standard location.
346265 rc .HostConfig .Binds = append (rc .HostConfig .Binds , fmt .Sprintf ("%s:/var/run/docker.sock" , dockerVol ))
347266 } else {
348- // for ssh / http / https just set DOCKER_HOST replacing localhost with the docker host IP .
349- h := localRegex .ReplaceAllString (dockerHost , hostIP )
267+ // for ssh / http / https just set DOCKER_HOST replacing localhost with the docker host hostname .
268+ h := localRegex .ReplaceAllString (dockerHost , dockerHostname )
350269 rc .ContainerConfig .Env = upsertEnv (rc .ContainerConfig .Env , "DOCKER_HOST" , h )
351270 }
352271
@@ -364,12 +283,12 @@ func beforeCheckRun(params backend.RunParams, rc *docker.RunConfig,
364283 log .Errorf ("Unable to create local git server check %v" , err )
365284 return nil
366285 }
367- newTarget = fmt .Sprintf ("http://%s:%d/" , agentIP , port )
286+ newTarget = fmt .Sprintf ("http://%s:%d/" , dockerHostname , port )
368287 }
369288
370289 }
371290
372- newTarget = localRegex .ReplaceAllString (newTarget , hostIP )
291+ newTarget = localRegex .ReplaceAllString (newTarget , dockerHostname )
373292
374293 if params .Target != newTarget {
375294 check := getCheckByID (checks , params .CheckID )
@@ -398,3 +317,24 @@ func getCheckByID(checks []config.Check, id string) *config.Check {
398317 }
399318 return nil
400319}
320+
321+ func getListenAddr (cli * client.Client ) (string , error ) {
322+ if ! inLinux () {
323+ return "127.0.0.1:0" , nil
324+ }
325+
326+ gws , err := dockerutil .GetGateways (context .Background (), cli , "bridge" )
327+ if err != nil {
328+ return "" , fmt .Errorf ("could not get Docker network gateway: %w" , err )
329+ }
330+ if len (gws ) != 1 {
331+ return "" , fmt .Errorf ("unexpected number of gateways: %v" , len (gws ))
332+ }
333+
334+ listenAddr := gws [0 ].String () + ":0"
335+ return listenAddr , nil
336+ }
337+
338+ func inLinux () bool {
339+ return runtime .GOOS == "linux"
340+ }
0 commit comments