fix
This commit is contained in:
parent
a1942c0054
commit
9d5a33e743
1 changed files with 119 additions and 0 deletions
|
|
@ -67,6 +67,53 @@ func (a *App) ensureCaddyRoute(ctx context.Context, p Project) error {
|
|||
"match": []any{map[string]any{"host": []string{p.RouteHost}}},
|
||||
"handle": []any{map[string]any{"handler": "reverse_proxy", "upstreams": []any{map[string]any{"dial": "unix/" + socketPath}}}},
|
||||
}
|
||||
|
||||
cfg, err := a.fetchCaddyConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexes := findCaddyRouteIndexesByID(cfg, a.cfg.CaddyServerID, route["@id"].(string))
|
||||
if len(indexes) > 0 {
|
||||
// Update first matching route in place.
|
||||
if err := a.putCaddyRouteAtIndex(ctx, indexes[0], route); err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove stale duplicates from highest index to lowest.
|
||||
for i := len(indexes) - 1; i >= 1; i-- {
|
||||
if err := a.deleteCaddyRouteAtIndex(ctx, indexes[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := a.appendCaddyRoute(ctx, route); err != nil {
|
||||
// If duplicate race happened, retry once through dedupe/update path.
|
||||
if strings.Contains(err.Error(), "duplicate ID") {
|
||||
cfg2, ferr := a.fetchCaddyConfig(ctx)
|
||||
if ferr != nil {
|
||||
return err
|
||||
}
|
||||
indexes2 := findCaddyRouteIndexesByID(cfg2, a.cfg.CaddyServerID, route["@id"].(string))
|
||||
if len(indexes2) == 0 {
|
||||
return err
|
||||
}
|
||||
if uerr := a.putCaddyRouteAtIndex(ctx, indexes2[0], route); uerr != nil {
|
||||
return uerr
|
||||
}
|
||||
for i := len(indexes2) - 1; i >= 1; i-- {
|
||||
if derr := a.deleteCaddyRouteAtIndex(ctx, indexes2[i]); derr != nil {
|
||||
return derr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) appendCaddyRoute(ctx context.Context, route map[string]any) error {
|
||||
body, _ := json.Marshal(route)
|
||||
url := fmt.Sprintf("%s/config/apps/http/servers/%s/routes", a.cfg.CaddyAdminURL, a.cfg.CaddyServerID)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(string(body)))
|
||||
|
|
@ -86,6 +133,78 @@ func (a *App) ensureCaddyRoute(ctx context.Context, p Project) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *App) putCaddyRouteAtIndex(ctx context.Context, idx int, route map[string]any) error {
|
||||
body, _ := json.Marshal(route)
|
||||
url := fmt.Sprintf("%s/config/apps/http/servers/%s/routes/%d", a.cfg.CaddyAdminURL, a.cfg.CaddyServerID, idx)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, strings.NewReader(string(body)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("caddy update request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 300 {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("caddy update error: status=%d body=%s", resp.StatusCode, string(respBody))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) deleteCaddyRouteAtIndex(ctx context.Context, idx int) error {
|
||||
url := fmt.Sprintf("%s/config/apps/http/servers/%s/routes/%d", a.cfg.CaddyAdminURL, a.cfg.CaddyServerID, idx)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("caddy delete request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 300 {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("caddy delete error: status=%d body=%s", resp.StatusCode, string(respBody))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findCaddyRouteIndexesByID(cfg map[string]any, serverID, routeID string) []int {
|
||||
var out []int
|
||||
apps, ok := cfg["apps"].(map[string]any)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
httpApp, ok := apps["http"].(map[string]any)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
servers, ok := httpApp["servers"].(map[string]any)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
server, ok := servers[serverID].(map[string]any)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
routes, ok := server["routes"].([]any)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
for i, r := range routes {
|
||||
rm, ok := r.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if rid, ok := rm["@id"].(string); ok && rid == routeID {
|
||||
out = append(out, i)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *App) fetchCaddyConfig(ctx context.Context) (map[string]any, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, a.cfg.CaddyAdminURL+"/config/", nil)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue