diff --git a/cmd/input.go b/cmd/input.go index 74b5653..a7ccae8 100644 --- a/cmd/input.go +++ b/cmd/input.go @@ -46,6 +46,7 @@ type Input struct { artifactServerPort string noCacheServer bool cacheServerPath string + cacheServerExternalURL string cacheServerAddr string cacheServerPort uint16 jsonLogger bool diff --git a/cmd/root.go b/cmd/root.go index 7cc98a3..3dbc83c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -118,6 +118,7 @@ func createRootCommand(ctx context.Context, input *Input, version string) *cobra rootCmd.PersistentFlags().BoolVarP(&input.noSkipCheckout, "no-skip-checkout", "", false, "Use actions/checkout instead of copying local files into container") rootCmd.PersistentFlags().BoolVarP(&input.noCacheServer, "no-cache-server", "", false, "Disable cache server") rootCmd.PersistentFlags().StringVarP(&input.cacheServerPath, "cache-server-path", "", filepath.Join(CacheHomeDir, "actcache"), "Defines the path where the cache server stores caches.") + rootCmd.PersistentFlags().StringVarP(&input.cacheServerExternalURL, "cache-server-external-url", "", "", "Defines the external URL for if the cache server is behind a proxy. e.g.: https://act-cache-server.example.com. Be careful that there is no trailing slash.") rootCmd.PersistentFlags().StringVarP(&input.cacheServerAddr, "cache-server-addr", "", common.GetOutboundIP().String(), "Defines the address to which the cache server binds.") rootCmd.PersistentFlags().Uint16VarP(&input.cacheServerPort, "cache-server-port", "", 0, "Defines the port where the artifact server listens. 0 means a randomly available port.") rootCmd.PersistentFlags().StringVarP(&input.actionCachePath, "action-cache-path", "", filepath.Join(CacheHomeDir, "act"), "Defines the path where the actions get cached and host workspaces created.") @@ -667,7 +668,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str var cacheHandler *artifactcache.Handler if !input.noCacheServer && envs[cacheURLKey] == "" { var err error - cacheHandler, err = artifactcache.StartHandler(input.cacheServerPath, input.cacheServerAddr, input.cacheServerPort, common.Logger(ctx)) + cacheHandler, err = artifactcache.StartHandler(input.cacheServerPath, input.cacheServerExternalURL, input.cacheServerAddr, input.cacheServerPort, common.Logger(ctx)) if err != nil { return err } diff --git a/pkg/artifactcache/handler.go b/pkg/artifactcache/handler.go index cd0daaa..90d4218 100644 --- a/pkg/artifactcache/handler.go +++ b/pkg/artifactcache/handler.go @@ -38,10 +38,11 @@ type Handler struct { gcing atomic.Bool gcAt time.Time - outboundIP string + outboundIP string + customExternalURL string } -func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger) (*Handler, error) { +func StartHandler(dir, customExternalURL string, outboundIP string, port uint16, logger logrus.FieldLogger) (*Handler, error) { h := &Handler{} if logger == nil { @@ -71,6 +72,10 @@ func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger } h.storage = storage + if customExternalURL != "" { + h.customExternalURL = customExternalURL + } + if outboundIP != "" { h.outboundIP = outboundIP } else if ip := common.GetOutboundIP(); ip == nil { @@ -95,6 +100,7 @@ func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger if err != nil { return nil, err } + server := &http.Server{ ReadHeaderTimeout: 2 * time.Second, Handler: router, @@ -110,11 +116,15 @@ func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger return h, nil } +func (h *Handler) GetActualPort() int { + return h.listener.Addr().(*net.TCPAddr).Port +} + func (h *Handler) ExternalURL() string { - // TODO: make the external url configurable if necessary - return fmt.Sprintf("http://%s:%d", - h.outboundIP, - h.listener.Addr().(*net.TCPAddr).Port) + if h.customExternalURL != "" { + return h.customExternalURL + } + return fmt.Sprintf("http://%s:%d", h.outboundIP, h.GetActualPort()) } func (h *Handler) Close() error { diff --git a/pkg/artifactcache/handler_test.go b/pkg/artifactcache/handler_test.go index 252c420..88f6dab 100644 --- a/pkg/artifactcache/handler_test.go +++ b/pkg/artifactcache/handler_test.go @@ -20,7 +20,7 @@ import ( func TestHandler(t *testing.T) { dir := filepath.Join(t.TempDir(), "artifactcache") - handler, err := StartHandler(dir, "", 0, nil) + handler, err := StartHandler(dir, "", "", 0, nil) require.NoError(t, err) base := fmt.Sprintf("%s%s", handler.ExternalURL(), urlBase) @@ -587,9 +587,43 @@ func uploadCacheNormally(t *testing.T, base, key, version string, content []byte } } +func TestHandler_CustomExternalURL(t *testing.T) { + dir := filepath.Join(t.TempDir(), "artifactcache") + handler, err := StartHandler(dir, "", "", 0, nil) + require.NoError(t, err) + + defer func() { + require.NoError(t, handler.Close()) + }() + + handler.customExternalURL = fmt.Sprintf("http://%s:%d", "127.0.0.1", handler.GetActualPort()) + + assert.Equal(t, fmt.Sprintf("http://%s:%d", "127.0.0.1", handler.GetActualPort()), handler.ExternalURL()) + + base := fmt.Sprintf("%s%s", handler.ExternalURL(), urlBase) + + t.Run("advertise url set wrong", func(t *testing.T) { + original := handler.customExternalURL + defer func() { + handler.customExternalURL = original + }() + handler.customExternalURL = "http://127.0.0.999:1234" + assert.Equal(t, "http://127.0.0.999:1234", handler.ExternalURL()) + }) + + t.Run("reserve and upload", func(t *testing.T) { + key := strings.ToLower(t.Name()) + version := "c19da02a2bd7e77277f1ac29ab45c09b7d46a4ee758284e26bb3045ad11d9d20" + content := make([]byte, 100) + _, err := rand.Read(content) + require.NoError(t, err) + uploadCacheNormally(t, base, key, version, content) + }) +} + func TestHandler_gcCache(t *testing.T) { dir := filepath.Join(t.TempDir(), "artifactcache") - handler, err := StartHandler(dir, "", 0, nil) + handler, err := StartHandler(dir, "", "", 0, nil) require.NoError(t, err) defer func() {