feat(cfsetup): start the tunnel connector as a setup step
Setup created the tunnel, routed DNS, and wrote config.yml, but nothing installed or started a connector for it. A one-click run therefore left the tunnel routed-but-dead: every web hostname returned Cloudflare error 1033 (tunnel has no connector) even though the config was correct on disk. Add a StartConnector step to the Runner seam, invoked right after the config is written (and gated on ConfigPath, so a caller wanting only the Access config is not forced to install a service). The ExecRunner implementation runs `cloudflared --config <path> service install`, which installs and starts a managed system service (systemd/launchd/Windows), and is idempotent on an already-installed service. The orchestration — connector started, and only after its config exists — is unit-tested against the fake Runner; the actual service install is INTEGRATION-ONLY. Together with the RouteDNS --overwrite-dns fix, this closes both distinct paths to a 1033 half-state from a fresh setup: a stale DNS binding and a missing connector.
This commit is contained in:
3 files changed
+110
No files matched your search
@@ -171,6 +171,30 @@ func (r *ExecRunner) WriteTunnelConfig(path string, contents []byte) error {
|
||||
return os.WriteFile(path, contents, 0o644)
|
||||
}
|
||||
|
||||
// StartConnector installs and starts the cloudflared connector as a managed system
|
||||
// service bound to configPath (`cloudflared --config <configPath> service install`),
|
||||
// so the tunnel written by WriteTunnelConfig has a running process serving it. On
|
||||
// Linux this installs and starts a systemd unit; on macOS a launchd agent; on
|
||||
// Windows a service. It is the step that turns a routed-but-dead tunnel (Cloudflare
|
||||
// error 1033) into a reachable one, and it runs as the operator (root under the
|
||||
// break-glass TUI) since installing a system service requires it.
|
||||
//
|
||||
// It is idempotent on re-run: an already-installed service is reported by cloudflared
|
||||
// and treated as success rather than failing the whole setup. Re-applying a CHANGED
|
||||
// config to an already-installed service would need a restart this method does not
|
||||
// perform — a caveat noted honestly. INTEGRATION-ONLY.
|
||||
func (r *ExecRunner) StartConnector(ctx context.Context, configPath string) error {
|
||||
if strings.TrimSpace(configPath) == "" {
|
||||
return fmt.Errorf("cfsetup: connector config path is required")
|
||||
}
|
||||
// The global --config flag must precede the `service install` subcommand.
|
||||
_, err := r.runCloudflared(ctx, "--config", configPath, "service", "install")
|
||||
if err != nil && strings.Contains(err.Error(), "already installed") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateAccessApplication POSTs the self-hosted Access app and returns its id and
|
||||
// issued aud (spec §14: the aud felis [auth] access_jwt_aud must adopt).
|
||||
func (r *ExecRunner) CreateAccessApplication(ctx context.Context, app AccessApplication) (string, string, error) {
|
||||
|
||||
Reference in new issue
Block a user