From c9e076db6810c0a80e6a737e05d5f4be56990919 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Fri, 24 Mar 2023 17:55:13 +0800 Subject: [PATCH] Get outbound IP in multiple ways or disable cache server if failed to init (#74) Fix #64 (incompletely). It's still not ideal. It makes more sense to use the gateway IP address of container network as outbound IP of cache server. However, this requires act to cooperate, some think like: - act creates the network for new container, and returns the network to runner. - runner extracts the gateway IP in the network. - runner uses the gateway IP as outbound IP, and pass it to act as cache server endpoint. - act It continues to create the container with the created network. Reviewed-on: https://gitea.com/gitea/act_runner/pulls/74 Reviewed-by: Lunny Xiao --- artifactcache/handler.go | 11 +++++++++-- artifactcache/util.go | 30 +++++++++++++++++++++++++++++- cmd/daemon.go | 14 +++++++------- runtime/runtime.go | 4 +++- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/artifactcache/handler.go b/artifactcache/handler.go index 7885a9b..d29a7ce 100644 --- a/artifactcache/handler.go +++ b/artifactcache/handler.go @@ -18,7 +18,6 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/render" - "github.com/nektos/act/pkg/common" log "github.com/sirupsen/logrus" _ "modernc.org/sqlite" "xorm.io/builder" @@ -39,6 +38,8 @@ type Handler struct { gc atomic.Bool gcAt time.Time + + outboundIP string } func NewHandler() (*Handler, error) { @@ -69,6 +70,12 @@ func NewHandler() (*Handler, error) { } h.storage = storage + if ip, err := getOutboundIP(); err != nil { + return nil, err + } else { + h.outboundIP = ip.String() + } + router := chi.NewRouter() router.Use(middleware.RequestLogger(&middleware.DefaultLogFormatter{Logger: logger})) router.Use(func(handler http.Handler) http.Handler { @@ -113,7 +120,7 @@ func NewHandler() (*Handler, error) { func (h *Handler) ExternalURL() string { // TODO: make the external url configurable if necessary return fmt.Sprintf("http://%s:%d", - common.GetOutboundIP().String(), + h.outboundIP, h.listener.Addr().(*net.TCPAddr).Port) } diff --git a/artifactcache/util.go b/artifactcache/util.go index 0f22c05..eca173a 100644 --- a/artifactcache/util.go +++ b/artifactcache/util.go @@ -5,6 +5,7 @@ package artifactcache import ( "fmt" + "net" "net/http" "strconv" "strings" @@ -44,8 +45,35 @@ func parseContentRange(s string) (int64, int64, error) { return start, stop, nil } +func getOutboundIP() (net.IP, error) { + // FIXME: It makes more sense to use the gateway IP address of container network + if conn, err := net.Dial("udp", "8.8.8.8:80"); err == nil { + defer conn.Close() + return conn.LocalAddr().(*net.UDPAddr).IP, nil + } + if ifaces, err := net.Interfaces(); err == nil { + for _, i := range ifaces { + if addrs, err := i.Addrs(); err == nil { + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip.IsGlobalUnicast() { + return ip, nil + } + } + } + } + } + return nil, fmt.Errorf("no outbound IP address found") +} + // engine is a wrapper of *xorm.Engine, with a lock. -// To avoid racing of sqlite, we don't careperformance here. +// To avoid racing of sqlite, we don't care performance here. type engine struct { e *xorm.Engine m sync.Mutex diff --git a/cmd/daemon.go b/cmd/daemon.go index e874b79..f24cd6c 100644 --- a/cmd/daemon.go +++ b/cmd/daemon.go @@ -52,12 +52,6 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg } } - handler, err := artifactcache.NewHandler() - if err != nil { - return err - } - log.Infof("cache handler listens on: %v", handler.ExternalURL()) - var g errgroup.Group cli := client.New( @@ -75,7 +69,13 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg Environ: cfg.Runner.Environ, Labels: cfg.Runner.Labels, Version: version, - CacheHandler: handler, + } + + if handler, err := artifactcache.NewHandler(); err != nil { + log.Errorf("cannot init cache server, it will be disabled: %v", err) + } else { + log.Infof("cache handler listens on: %v", handler.ExternalURL()) + runner.CacheHandler = handler } poller := poller.New( diff --git a/runtime/runtime.go b/runtime/runtime.go index 49cc3cf..37cc15b 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -31,7 +31,9 @@ func (s *Runner) Run(ctx context.Context, task *runnerv1.Task) error { for k, v := range s.Environ { env[k] = v } - env["ACTIONS_CACHE_URL"] = s.CacheHandler.ExternalURL() + "/" + if s.CacheHandler != nil { + env["ACTIONS_CACHE_URL"] = s.CacheHandler.ExternalURL() + "/" + } return NewTask(s.ForgeInstance, task.Id, s.Client, env, s.platformPicker).Run(ctx, task, s.Machine, s.Version) }