5858 forceDeleteFlag = & cli.BoolFlag {
5959 Name : "force" ,
6060 Aliases : []string {"f" },
61- Usage : "Allows you to delete a tunnel, even if it has active connections." ,
61+ Usage : "Allows you to delete a tunnel, even if it has active connections." ,
6262 }
6363)
6464
@@ -131,13 +131,13 @@ func createTunnel(c *cli.Context) error {
131131 return nil
132132}
133133
134- func tunnelFilePath (tunnelID , directory string ) (string , error ) {
134+ func tunnelFilePath (tunnelID uuid. UUID , directory string ) (string , error ) {
135135 fileName := fmt .Sprintf ("%v.json" , tunnelID )
136136 filePath := filepath .Clean (fmt .Sprintf ("%s/%s" , directory , fileName ))
137137 return homedir .Expand (filePath )
138138}
139139
140- func writeTunnelCredentials (tunnelID , accountID , originCertPath string , tunnelSecret []byte , logger logger.Service ) error {
140+ func writeTunnelCredentials (tunnelID uuid. UUID , accountID , originCertPath string , tunnelSecret []byte , logger logger.Service ) error {
141141 originCertDir := filepath .Dir (originCertPath )
142142 filePath , err := tunnelFilePath (tunnelID , originCertDir )
143143 if err != nil {
@@ -155,7 +155,7 @@ func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSe
155155 return ioutil .WriteFile (filePath , body , 400 )
156156}
157157
158- func readTunnelCredentials (c * cli.Context , tunnelID string , logger logger.Service ) (* pogs.TunnelAuth , error ) {
158+ func readTunnelCredentials (c * cli.Context , tunnelID uuid. UUID , logger logger.Service ) (* pogs.TunnelAuth , error ) {
159159 filePath , err := tunnelCredentialsPath (c , tunnelID , logger )
160160 if err != nil {
161161 return nil , err
@@ -172,7 +172,7 @@ func readTunnelCredentials(c *cli.Context, tunnelID string, logger logger.Servic
172172 return & auth , nil
173173}
174174
175- func tunnelCredentialsPath (c * cli.Context , tunnelID string , logger logger.Service ) (string , error ) {
175+ func tunnelCredentialsPath (c * cli.Context , tunnelID uuid. UUID , logger logger.Service ) (string , error ) {
176176 if filePath := c .String ("credentials-file" ); filePath != "" {
177177 if validFilePath (filePath ) {
178178 return filePath , nil
@@ -322,7 +322,10 @@ func deleteTunnel(c *cli.Context) error {
322322 if c .NArg () != 1 {
323323 return cliutil .UsageError (`"cloudflared tunnel delete" requires exactly 1 argument, the ID of the tunnel to delete.` )
324324 }
325- id := c .Args ().First ()
325+ tunnelID , err := uuid .Parse (c .Args ().First ())
326+ if err != nil {
327+ return errors .Wrap (err , "error parsing tunnel ID" )
328+ }
326329
327330 logger , err := logger .New ()
328331 if err != nil {
@@ -337,9 +340,9 @@ func deleteTunnel(c *cli.Context) error {
337340
338341 forceFlagSet := c .Bool ("force" )
339342
340- tunnel , err := client .GetTunnel (id )
343+ tunnel , err := client .GetTunnel (tunnelID )
341344 if err != nil {
342- return errors .Wrapf (err , "Can't get tunnel information. Please check tunnel id: %s" , id )
345+ return errors .Wrapf (err , "Can't get tunnel information. Please check tunnel id: %s" , tunnelID )
343346 }
344347
345348 // Check if tunnel DeletedAt field has already been set
@@ -351,17 +354,17 @@ func deleteTunnel(c *cli.Context) error {
351354 if ! forceFlagSet {
352355 return errors .New ("You can not delete this tunnel because it has active connections. To see connections run the 'list' command. If you believe the tunnel is not active, you can use a -f / --force flag with this command." )
353356 }
354-
355- if err := client .CleanupConnections (id ); err != nil {
356- return errors .Wrapf (err , "Error cleaning up connections for tunnel %s" , id )
357+
358+ if err := client .CleanupConnections (tunnelID ); err != nil {
359+ return errors .Wrapf (err , "Error cleaning up connections for tunnel %s" , tunnelID )
357360 }
358361 }
359362
360- if err := client .DeleteTunnel (id ); err != nil {
361- return errors .Wrapf (err , "Error deleting tunnel %s" , id )
363+ if err := client .DeleteTunnel (tunnelID ); err != nil {
364+ return errors .Wrapf (err , "Error deleting tunnel %s" , tunnelID )
362365 }
363366
364- tunnelCredentialsPath , err := tunnelCredentialsPath (c , id , logger )
367+ tunnelCredentialsPath , err := tunnelCredentialsPath (c , tunnelID , logger )
365368 if err != nil {
366369 logger .Infof ("Cannot locate tunnel credentials to delete, error: %v. Please delete the file manually" , err )
367370 return nil
@@ -388,7 +391,7 @@ func renderOutput(format string, v interface{}) error {
388391}
389392
390393func newTunnelstoreClient (c * cli.Context , cert * certutil.OriginCert , logger logger.Service ) tunnelstore.Client {
391- client := tunnelstore .NewRESTClient (c .String ("api-url" ), cert .AccountID , cert .ServiceKey , logger )
394+ client := tunnelstore .NewRESTClient (c .String ("api-url" ), cert .AccountID , cert .ZoneID , cert . ServiceKey , logger )
392395 return client
393396}
394397
@@ -428,8 +431,8 @@ func runTunnel(c *cli.Context) error {
428431 if c .NArg () != 1 {
429432 return cliutil .UsageError (`"cloudflared tunnel run" requires exactly 1 argument, the ID of the tunnel to run.` )
430433 }
431- id := c . Args (). First ()
432- tunnelID , err := uuid .Parse (id )
434+
435+ tunnelID , err := uuid .Parse (c . Args (). First () )
433436 if err != nil {
434437 return errors .Wrap (err , "error parsing tunnel ID" )
435438 }
@@ -439,7 +442,7 @@ func runTunnel(c *cli.Context) error {
439442 return errors .Wrap (err , "error setting up logger" )
440443 }
441444
442- credentials , err := readTunnelCredentials (c , id , logger )
445+ credentials , err := readTunnelCredentials (c , tunnelID , logger )
443446 if err != nil {
444447 return err
445448 }
@@ -474,12 +477,108 @@ func cleanupConnections(c *cli.Context) error {
474477 client := newTunnelstoreClient (c , cert , logger )
475478
476479 for i := 0 ; i < c .NArg (); i ++ {
477- id := c .Args ().Get (i )
478- logger .Infof ("Cleanup connection for tunnel %s" , id )
479- if err := client .CleanupConnections (id ); err != nil {
480- logger .Errorf ("Error cleaning up connections for tunnel %s, error :%v" , id , err )
480+ tunnelID , err := uuid .Parse (c .Args ().Get (i ))
481+ if err != nil {
482+ logger .Errorf ("Failed to parse argument %d as tunnelID, error :%v" , i , err )
483+ continue
484+ }
485+ logger .Infof ("Cleanup connection for tunnel %s" , tunnelID )
486+ if err := client .CleanupConnections (tunnelID ); err != nil {
487+ logger .Errorf ("Error cleaning up connections for tunnel %v, error :%v" , tunnelID , err )
481488 }
482489 }
483490
484491 return nil
485492}
493+
494+ func buildRouteCommand () * cli.Command {
495+ return & cli.Command {
496+ Name : "route" ,
497+ Action : cliutil .ErrorHandler (routeTunnel ),
498+ Usage : "Define what hostname or load balancer can route to this tunnel" ,
499+ Description : `The route defines what hostname or load balancer can route to this tunnel.
500+ To route a hostname: cloudflared tunnel route dns <tunnel ID> <hostname>
501+ To route a load balancer: cloudflared tunnel route lb <tunnel ID> <load balancer name> <load balancer pool>
502+ If you don't specify a load balancer pool, we will create a new pool called tunnel:<tunnel ID>` ,
503+ ArgsUsage : "dns|lb TUNNEL-ID HOSTNAME [LB-POOL]" ,
504+ Hidden : hideSubcommands ,
505+ }
506+ }
507+
508+ func routeTunnel (c * cli.Context ) error {
509+ if c .NArg () < 2 {
510+ return cliutil .UsageError (`"cloudflared tunnel route" requires the first argument to be the route type(dns or lb), followed by the ID of the tunnel` )
511+ }
512+ const tunnelIDIndex = 1
513+ tunnelID , err := uuid .Parse (c .Args ().Get (tunnelIDIndex ))
514+ if err != nil {
515+ return errors .Wrap (err , "error parsing tunnel ID" )
516+ }
517+
518+ logger , err := logger .New ()
519+ if err != nil {
520+ return errors .Wrap (err , "error setting up logger" )
521+ }
522+
523+ routeType := c .Args ().First ()
524+ var route tunnelstore.Route
525+ switch routeType {
526+ case "dns" :
527+ route , err = dnsRouteFromArg (c , tunnelID )
528+ if err != nil {
529+ return err
530+ }
531+ case "lb" :
532+ route , err = lbRouteFromArg (c , tunnelID , logger )
533+ if err != nil {
534+ return err
535+ }
536+ default :
537+ return cliutil .UsageError ("%s is not a recognized route type. Supported route types are dns and lb" , routeType )
538+ }
539+
540+ cert , _ , err := getOriginCertFromContext (c , logger )
541+ if err != nil {
542+ return err
543+ }
544+
545+ client := newTunnelstoreClient (c , cert , logger )
546+ return client .RouteTunnel (tunnelID , route )
547+ }
548+
549+ func dnsRouteFromArg (c * cli.Context , tunnelID uuid.UUID ) (tunnelstore.Route , error ) {
550+ const (
551+ userHostnameIndex = 2
552+ expectArgs = 3
553+ )
554+ if c .NArg () != expectArgs {
555+ return nil , cliutil .UsageError ("Expect %d arguments, got %d" , expectArgs , c .NArg ())
556+ }
557+ userHostname := c .Args ().Get (userHostnameIndex )
558+ if userHostname == "" {
559+ return nil , cliutil .UsageError ("The third argument should be the hostname" )
560+ }
561+ return tunnelstore .NewDNSRoute (userHostname ), nil
562+ }
563+
564+ func lbRouteFromArg (c * cli.Context , tunnelID uuid.UUID , logger logger.Service ) (tunnelstore.Route , error ) {
565+ const (
566+ lbNameIndex = 2
567+ lbPoolIndex = 3
568+ expectMinArgs = 3
569+ )
570+ if c .NArg () < expectMinArgs {
571+ return nil , cliutil .UsageError ("Expect at least %d arguments, got %d" , expectMinArgs , c .NArg ())
572+ }
573+ lbName := c .Args ().Get (lbNameIndex )
574+ if lbName == "" {
575+ return nil , cliutil .UsageError ("The third argument should be the load balancer name" )
576+ }
577+ lbPool := c .Args ().Get (lbPoolIndex )
578+ if lbPool == "" {
579+ lbPool = fmt .Sprintf ("tunnel:%v" , tunnelID )
580+ logger .Infof ("Generate pool name %s" , lbPool )
581+ }
582+
583+ return tunnelstore .NewLBRoute (lbName , lbPool ), nil
584+ }
0 commit comments