• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

astronomer / astro-cli / 408796d1-867a-49d6-a9f1-470124cda0c8

04 Mar 2026 09:58PM UTC coverage: 35.914% (+0.2%) from 35.716%
408796d1-867a-49d6-a9f1-470124cda0c8

push

circleci

web-flow
feat: built-in reverse proxy for multi-instance local development (#2026)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

457 of 896 new or added lines in 10 files covered. (51.0%)

1 existing line in 1 file now uncovered.

24288 of 67629 relevant lines covered (35.91%)

8.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.27
/cmd/airflow_proxy.go
1
package cmd
2

3
import (
4
        "fmt"
5
        "os"
6
        "text/tabwriter"
7

8
        "github.com/astronomer/astro-cli/airflow/proxy"
9
        "github.com/astronomer/astro-cli/config"
10
        "github.com/astronomer/astro-cli/pkg/ansi"
11
        "github.com/spf13/cobra"
12
)
13

14
func newProxyRootCmd() *cobra.Command {
24✔
15
        cmd := &cobra.Command{
24✔
16
                Use:   "proxy",
24✔
17
                Short: "Manage the local development reverse proxy",
24✔
18
                Long:  "Manage the reverse proxy that routes <project>.localhost to the correct local Airflow instance.",
24✔
19
                // No runtime needed for proxy commands
24✔
20
                PersistentPreRunE: SetupLogging,
24✔
21
        }
24✔
22
        cmd.AddCommand(
24✔
23
                newProxyStatusCmd(),
24✔
24
                newProxyStopCmd(),
24✔
25
                newProxyServeCmd(),
24✔
26
        )
24✔
27
        return cmd
24✔
28
}
24✔
29

30
func newProxyStatusCmd() *cobra.Command {
24✔
31
        return &cobra.Command{
24✔
32
                Use:   "status",
24✔
33
                Short: "Show proxy status and active routes",
24✔
34
                Long:  "Display the proxy daemon status and a table of all active project routes.",
24✔
35
                RunE:  proxyStatus,
24✔
36
        }
24✔
37
}
24✔
38

39
func newProxyStopCmd() *cobra.Command {
24✔
40
        return &cobra.Command{
24✔
41
                Use:   "stop",
24✔
42
                Short: "Stop the proxy daemon",
24✔
43
                Long:  "Force-stop the proxy daemon. It will restart automatically on the next 'astro dev start'.",
24✔
44
                RunE:  proxyStop,
24✔
45
        }
24✔
46
}
24✔
47

48
func newProxyServeCmd() *cobra.Command {
24✔
49
        cmd := &cobra.Command{
24✔
50
                Use:    "serve",
24✔
51
                Short:  "Run the proxy server (used internally)",
24✔
52
                Hidden: true,
24✔
53
                RunE:   proxyServe,
24✔
54
        }
24✔
55
        cmd.Flags().StringVar(&proxyPortFlag, "port", proxy.DefaultPort, "Port to listen on")
24✔
56
        return cmd
24✔
57
}
24✔
58

NEW
59
func proxyStatus(_ *cobra.Command, _ []string) error {
×
NEW
60
        port := config.CFG.ProxyPort.GetString()
×
NEW
61
        if port == "" {
×
NEW
62
                port = proxy.DefaultPort
×
NEW
63
        }
×
64

NEW
65
        routes, err := proxy.ListRoutes()
×
NEW
66
        if err != nil {
×
NEW
67
                return fmt.Errorf("error reading routes: %w", err)
×
NEW
68
        }
×
69

NEW
70
        pid, alive := proxy.IsRunning()
×
NEW
71
        switch {
×
NEW
72
        case alive:
×
NEW
73
                fmt.Printf("%s Proxy is running (PID %d) on port %s\n", ansi.Green("\u2714"), pid, port)
×
NEW
74
        case len(routes) > 0:
×
NEW
75
                // Routes exist but daemon is dead — auto-restart
×
NEW
76
                fmt.Println("Proxy is not running. Restarting…")
×
NEW
77
                if _, ensureErr := proxy.EnsureRunning(port); ensureErr != nil {
×
NEW
78
                        fmt.Printf("Warning: could not restart proxy: %s\n", ensureErr.Error())
×
NEW
79
                } else {
×
NEW
80
                        pid, alive = proxy.IsRunning()
×
NEW
81
                        if alive {
×
NEW
82
                                fmt.Printf("%s Proxy restarted (PID %d) on port %s\n", ansi.Green("\u2714"), pid, port)
×
NEW
83
                        }
×
84
                }
NEW
85
        default:
×
NEW
86
                fmt.Println("Proxy is not running.")
×
87
        }
88

NEW
89
        if len(routes) == 0 {
×
NEW
90
                fmt.Println("\nNo active routes.")
×
NEW
91
                return nil
×
NEW
92
        }
×
93

NEW
94
        fmt.Println("\nActive routes:")
×
NEW
95
        tw := tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', 0) //nolint:mnd
×
NEW
96
        fmt.Fprintln(tw, "URL\tBackend Port\tPostgres Port\tProject Dir\tPID")
×
NEW
97
        for _, r := range routes {
×
NEW
98
                pgPort := "-"
×
NEW
99
                if p, ok := r.Services["postgres"]; ok {
×
NEW
100
                        pgPort = p
×
NEW
101
                }
×
NEW
102
                url := fmt.Sprintf("http://%s:%s", r.Hostname, port)
×
NEW
103
                fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%d\n", url, r.Port, pgPort, r.ProjectDir, r.PID)
×
104
        }
NEW
105
        return tw.Flush()
×
106
}
107

NEW
108
func proxyStop(_ *cobra.Command, _ []string) error {
×
NEW
109
        _, wasRunning := proxy.IsRunning()
×
NEW
110

×
NEW
111
        if err := proxy.StopDaemon(); err != nil {
×
NEW
112
                return fmt.Errorf("error stopping proxy: %w", err)
×
NEW
113
        }
×
114

NEW
115
        if wasRunning {
×
NEW
116
                fmt.Println("Proxy stopped.")
×
NEW
117
        } else {
×
NEW
118
                fmt.Println("Proxy is not running.")
×
NEW
119
        }
×
NEW
120
        return nil
×
121
}
122

NEW
123
func proxyServe(_ *cobra.Command, _ []string) error {
×
NEW
124
        p := proxy.NewProxy(proxyPortFlag)
×
NEW
125
        return p.Serve()
×
NEW
126
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc