From 4c5ebccacc9927974cab7df17c6c18887dda288d Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Wed, 19 May 2021 12:38:09 -0500 Subject: [PATCH] TUN-4425: --overwrite-dns flag for in adhoc and route dns cmds --- CHANGES.md | 7 +++++++ cmd/cloudflared/tunnel/cmd.go | 11 ++++++++--- cmd/cloudflared/tunnel/subcommands.go | 22 +++++++++++++++------- tunnelstore/client.go | 18 +++++++++++------- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b03540a8..5d6cad3f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ **Experimental**: This is a new format for release notes. The format and availability is subject to change. +## 2021.5.8 +### New Features +- When creating a DNS record to point a hostname at a tunnel, you can now use --overwrite-dns to overwrite any existing + DNS records with that hostname. This works when using the CLI to provision DNS, and when starting an adhoc tunnel, e.g. + - `cloudflared route --overwrite-dns dns foo foo.example.com` + - `cloudflared tunnel --overwrite-dns --name foo --hostname foo.example.com` + ## 2021.5.7 ### New Features - Named Tunnels will automatically select the protocol to connect to Cloudflare's edge network. diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index 8bc88a67..2c3ee3ad 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -87,6 +87,10 @@ const ( var ( graceShutdownC chan struct{} version string + + routeFailMsg = fmt.Sprintf("failed to provision routing, please create it manually via Cloudflare dashboard or UI; "+ + "most likely you already have a conflicting record there. You can also rerun this command with --%s to overwrite "+ + "any existing DNS records for this hostname.", overwriteDNSFlag) ) func Flags() []cli.Flag { @@ -181,7 +185,7 @@ func runAdhocNamedTunnel(sc *subcommandContext, name, credentialsOutputPath stri if r, ok := routeFromFlag(sc.c); ok { if res, err := sc.route(tunnel.ID, r); err != nil { - sc.log.Err(err).Str("route", r.String()).Msg("failed to provision routing, please create it manually via Cloudflare dashboard or UI; most likely you already have a conflicting record there") + sc.log.Err(err).Str("route", r.String()).Msg(routeFailMsg) } else { sc.log.Info().Msg(res.SuccessSummary()) } @@ -199,12 +203,12 @@ func runClassicTunnel(sc *subcommandContext) error { return StartServer(sc.c, version, nil, sc.log, sc.isUIEnabled) } -func routeFromFlag(c *cli.Context) (tunnelstore.Route, bool) { +func routeFromFlag(c *cli.Context) (route tunnelstore.Route, ok bool) { if hostname := c.String("hostname"); hostname != "" { if lbPool := c.String("lb-pool"); lbPool != "" { return tunnelstore.NewLBRoute(hostname, lbPool), true } - return tunnelstore.NewDNSRoute(hostname), true + return tunnelstore.NewDNSRoute(hostname, c.Bool(overwriteDNSFlagName)), true } return nil, false } @@ -613,6 +617,7 @@ func tunnelFlags(shouldHide bool) []cli.Flag { Hidden: shouldHide, }), selectProtocolFlag, + overwriteDNSFlag, }...) return flags diff --git a/cmd/cloudflared/tunnel/subcommands.go b/cmd/cloudflared/tunnel/subcommands.go index 35794096..66bd59b7 100644 --- a/cmd/cloudflared/tunnel/subcommands.go +++ b/cmd/cloudflared/tunnel/subcommands.go @@ -29,10 +29,11 @@ import ( ) const ( - allSortByOptions = "name, id, createdAt, deletedAt, numConnections" - connsSortByOptions = "id, startedAt, numConnections, version" - CredFileFlagAlias = "cred-file" - CredFileFlag = "credentials-file" + allSortByOptions = "name, id, createdAt, deletedAt, numConnections" + connsSortByOptions = "id, startedAt, numConnections, version" + CredFileFlagAlias = "cred-file" + CredFileFlag = "credentials-file" + overwriteDNSFlagName = "overwrite-dns" LogFieldTunnelID = "tunnelID" ) @@ -133,6 +134,12 @@ var ( Usage: `Constraints the cleanup to stop the connections of a single Connector (by its ID). You can find the various Connectors (and their IDs) currently connected to your tunnel via 'cloudflared tunnel info '.`, EnvVars: []string{"TUNNEL_CLEANUP_CONNECTOR"}, } + overwriteDNSFlag = &cli.BoolFlag{ + Name: overwriteDNSFlagName, + Aliases: []string{"f"}, + Usage: `Overwrites existing DNS records with this hostname`, + EnvVars: []string{"TUNNEL_FORCE_PROVISIONING_DNS"}, + } ) func buildCreateCommand() *cli.Command { @@ -670,10 +677,11 @@ Further information about managing Cloudflare WARP traffic to your tunnel is ava Subcommands: []*cli.Command{ buildRouteIPSubcommand(), }, + Flags: []cli.Flag{overwriteDNSFlag}, } } -func dnsRouteFromArg(c *cli.Context) (tunnelstore.Route, error) { +func dnsRouteFromArg(c *cli.Context, overwriteExisting bool) (tunnelstore.Route, error) { const ( userHostnameIndex = 2 expectedNArgs = 3 @@ -687,7 +695,7 @@ func dnsRouteFromArg(c *cli.Context) (tunnelstore.Route, error) { } else if !validateHostname(userHostname, true) { return nil, errors.Errorf("%s is not a valid hostname", userHostname) } - return tunnelstore.NewDNSRoute(userHostname), nil + return tunnelstore.NewDNSRoute(userHostname, overwriteExisting), nil } func lbRouteFromArg(c *cli.Context) (tunnelstore.Route, error) { @@ -756,7 +764,7 @@ func routeCommand(c *cli.Context) error { if err != nil { return err } - route, err = dnsRouteFromArg(c) + route, err = dnsRouteFromArg(c, c.Bool(overwriteDNSFlagName)) if err != nil { return err } diff --git a/tunnelstore/client.go b/tunnelstore/client.go index e1f1c4e1..c5230cc8 100644 --- a/tunnelstore/client.go +++ b/tunnelstore/client.go @@ -81,7 +81,8 @@ type RouteResult interface { } type DNSRoute struct { - userHostname string + userHostname string + overwriteExisting bool } type DNSRouteResult struct { @@ -89,19 +90,22 @@ type DNSRouteResult struct { CName Change `json:"cname"` } -func NewDNSRoute(userHostname string) Route { +func NewDNSRoute(userHostname string, overwriteExisting bool) Route { return &DNSRoute{ - userHostname: userHostname, + userHostname: userHostname, + overwriteExisting: overwriteExisting, } } func (dr *DNSRoute) MarshalJSON() ([]byte, error) { s := struct { - Type string `json:"type"` - UserHostname string `json:"user_hostname"` + Type string `json:"type"` + UserHostname string `json:"user_hostname"` + OverwriteExisting bool `json:"overwrite_existing"` }{ - Type: dr.RecordType(), - UserHostname: dr.userHostname, + Type: dr.RecordType(), + UserHostname: dr.userHostname, + OverwriteExisting: dr.overwriteExisting, } return json.Marshal(&s) }