TUN-3066: Command line action for tunnel run

This commit is contained in:
Adam Chalmers 2020-06-16 17:43:22 -05:00
parent b95b289a8c
commit a1a8645294
2 changed files with 63 additions and 11 deletions

View File

@ -172,6 +172,7 @@ func Commands() []*cli.Command {
subcommands = append(subcommands, buildCreateCommand()) subcommands = append(subcommands, buildCreateCommand())
subcommands = append(subcommands, buildListCommand()) subcommands = append(subcommands, buildListCommand())
subcommands = append(subcommands, buildDeleteCommand()) subcommands = append(subcommands, buildDeleteCommand())
subcommands = append(subcommands, buildRunCommand())
cmds = append(cmds, &cli.Command{ cmds = append(cmds, &cli.Command{
Name: "tunnel", Name: "tunnel",
@ -1092,8 +1093,8 @@ func stdinControl(reconnectCh chan origin.ReconnectSignal, logger logger.Service
logger.Infof("Unknown command: %s", command) logger.Infof("Unknown command: %s", command)
fallthrough fallthrough
case "help": case "help":
logger.Info(`Supported command: logger.Info(`Supported command:
reconnect [delay] reconnect [delay]
- restarts one randomly chosen connection with optional delay before reconnect`) - restarts one randomly chosen connection with optional delay before reconnect`)
} }
} }

View File

@ -4,6 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
@ -32,6 +33,14 @@ var (
Aliases: []string{"o"}, Aliases: []string{"o"},
Usage: "Render output using given `FORMAT`. Valid options are 'json' or 'yaml'", Usage: "Render output using given `FORMAT`. Valid options are 'json' or 'yaml'",
} }
forceFlag = &cli.StringFlag{
Name: "force",
Aliases: []string{"f"},
Usage: "By default, if a tunnel is currently being run from a cloudflared, you can't " +
"simultaneously rerun it again from a second cloudflared. The --force flag lets you " +
"overwrite the previous tunnel. If you want to use a single hostname with multiple " +
"tunnels, you can do so with Cloudflare's Load Balancer product.",
}
) )
const hideSubcommands = true const hideSubcommands = true
@ -117,13 +126,6 @@ func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSe
if err != nil { if err != nil {
return err return err
} }
logger.Infof("Writing tunnel credentials to %v. cloudflared chose this file based on where your origin certificate was found.", filePath)
logger.Infof("Keep this file secret. To revoke these credentials, delete the tunnel.")
file, err := os.Create(filePath)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Unable to write to %s", filePath))
}
defer file.Close()
body, err := json.Marshal(pogs.TunnelAuth{ body, err := json.Marshal(pogs.TunnelAuth{
AccountTag: accountID, AccountTag: accountID,
TunnelSecret: tunnelSecret, TunnelSecret: tunnelSecret,
@ -131,8 +133,23 @@ func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSe
if err != nil { if err != nil {
return errors.Wrap(err, "Unable to marshal tunnel credentials to JSON") return errors.Wrap(err, "Unable to marshal tunnel credentials to JSON")
} }
fmt.Fprintf(file, "%d", body) logger.Infof("Writing tunnel credentials to %v. cloudflared chose this file based on where your origin certificate was found.", filePath)
return nil logger.Infof("Keep this file secret. To revoke these credentials, delete the tunnel.")
return ioutil.WriteFile(filePath, body, 400)
}
func readTunnelCredentials(tunnelID, originCertPath string) (*pogs.TunnelAuth, error) {
filePath, err := tunnelFilePath(tunnelID, originCertPath)
if err != nil {
return nil, err
}
body, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, errors.Wrapf(err, "couldn't read tunnel credentials from %v", filePath)
}
auth := pogs.TunnelAuth{}
err = json.Unmarshal(body, &auth)
return &auth, errors.Wrap(err, "couldn't parse tunnel credentials from JSON")
} }
func buildListCommand() *cli.Command { func buildListCommand() *cli.Command {
@ -290,3 +307,37 @@ func getOriginCertFromContext(originCertPath string, logger logger.Service) (*ce
} }
return cert, nil return cert, nil
} }
func buildRunCommand() *cli.Command {
return &cli.Command{
Name: "run",
Action: cliutil.ErrorHandler(runTunnel),
Usage: "Proxy a local web server by running the given tunnel",
ArgsUsage: "TUNNEL-ID",
Hidden: hideSubcommands,
Flags: []cli.Flag{forceFlag},
}
}
func runTunnel(c *cli.Context) error {
if c.NArg() != 1 {
return cliutil.UsageError(`"cloudflared tunnel run" requires exactly 1 argument, the ID of the tunnel to run.`)
}
id := c.Args().First()
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return errors.Wrap(err, "Error locating origin cert")
}
credentials, err := readTunnelCredentials(id, originCertPath)
if err != nil {
return err
}
logger.Debugf("Read credentials for %v", credentials.AccountTag)
panic("TODO: start tunnel supervisor")
}