cmd/tailscale: allow serve|funnel off to delete an entire port
This PR allows you to do "tailscale serve -bg -https:4545 off" and it will delete all handlers under it. It will also prompt you for a y/n in case you wanted to delete a single port. Updates #8489 Signed-off-by: Marwan Sulaiman <marwan@tailscale.com>
This commit is contained in:
parent
e561f1ce61
commit
60e768fd14
|
@ -164,6 +164,7 @@ type serveEnv struct {
|
|||
tcp string // TCP port
|
||||
tlsTerminatedTCP string // a TLS terminated TCP port
|
||||
subcmd serveMode // subcommand
|
||||
yes bool // update without prompt
|
||||
|
||||
lc localServeClient // localClient interface, specific to serve
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ func newServeV2Command(e *serveEnv, subcmd serveMode) *ffcli.Command {
|
|||
fs.StringVar(&e.http, "http", "", "Expose an HTTP server at the specified port")
|
||||
fs.StringVar(&e.tcp, "tcp", "", "Expose a TCP forwarder to forward raw TCP packets at the specified port")
|
||||
fs.StringVar(&e.tlsTerminatedTCP, "tls-terminated-tcp", "", "Expose a TCP forwarder to forward TLS-terminated TCP packets at the specified port")
|
||||
|
||||
fs.BoolVar(&e.yes, "yes", false, "Update without interactive prompts")
|
||||
}),
|
||||
UsageFunc: usageFunc,
|
||||
Subcommands: []*ffcli.Command{
|
||||
|
@ -679,13 +679,40 @@ func (e *serveEnv) removeWebServe(sc *ipn.ServeConfig, dnsName string, srvPort u
|
|||
return errors.New("cannot remove web handler; currently serving TCP")
|
||||
}
|
||||
|
||||
hp := ipn.HostPort(net.JoinHostPort(dnsName, strconv.Itoa(int(srvPort))))
|
||||
if !sc.WebHandlerExists(hp, mount) {
|
||||
portStr := strconv.Itoa(int(srvPort))
|
||||
hp := ipn.HostPort(net.JoinHostPort(dnsName, portStr))
|
||||
|
||||
var targetExists bool
|
||||
var mounts []string
|
||||
// mount is deduced from e.setPath but it is ambiguous as
|
||||
// to whether the user explicitly passed "/" or it was defaulted to.
|
||||
if e.setPath == "" {
|
||||
targetExists = sc.Web[hp] != nil && len(sc.Web[hp].Handlers) > 0
|
||||
if targetExists {
|
||||
for mount := range sc.Web[hp].Handlers {
|
||||
mounts = append(mounts, mount)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targetExists = sc.WebHandlerExists(hp, mount)
|
||||
mounts = []string{mount}
|
||||
}
|
||||
|
||||
if !targetExists {
|
||||
return errors.New("error: handler does not exist")
|
||||
}
|
||||
|
||||
if len(mounts) > 1 {
|
||||
msg := fmt.Sprintf("Are you sure you want to delete %d handlers under port %s?", len(mounts), portStr)
|
||||
if !e.yes && !promptYesNo(msg) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// delete existing handler, then cascade delete if empty
|
||||
delete(sc.Web[hp].Handlers, mount)
|
||||
for _, m := range mounts {
|
||||
delete(sc.Web[hp].Handlers, m)
|
||||
}
|
||||
if len(sc.Web[hp].Handlers) == 0 {
|
||||
delete(sc.Web, hp)
|
||||
delete(sc.TCP, srvPort)
|
||||
|
|
|
@ -725,6 +725,40 @@ func TestServeDevConfigMutations(t *testing.T) {
|
|||
wantErr: anyErr(),
|
||||
})
|
||||
|
||||
add(step{
|
||||
command: cmd("serve reset"),
|
||||
want: &ipn.ServeConfig{},
|
||||
})
|
||||
|
||||
// start two handlers and turn them off in one command
|
||||
add(step{
|
||||
command: cmd("serve --https=4545 --set-path=/foo --bg localhost:3000"),
|
||||
want: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{4545: {HTTPS: true}},
|
||||
Web: map[ipn.HostPort]*ipn.WebServerConfig{
|
||||
"foo.test.ts.net:4545": {Handlers: map[string]*ipn.HTTPHandler{
|
||||
"/foo": {Proxy: "http://127.0.0.1:3000"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
})
|
||||
add(step{
|
||||
command: cmd("serve --https=4545 --set-path=/bar --bg localhost:3000"),
|
||||
want: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{4545: {HTTPS: true}},
|
||||
Web: map[ipn.HostPort]*ipn.WebServerConfig{
|
||||
"foo.test.ts.net:4545": {Handlers: map[string]*ipn.HTTPHandler{
|
||||
"/foo": {Proxy: "http://127.0.0.1:3000"},
|
||||
"/bar": {Proxy: "http://127.0.0.1:3000"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
})
|
||||
add(step{
|
||||
command: cmd("serve --https=4545 --bg --yes localhost:3000 off"),
|
||||
want: &ipn.ServeConfig{},
|
||||
})
|
||||
|
||||
lc := &fakeLocalServeClient{}
|
||||
// And now run the steps above.
|
||||
for i, st := range steps {
|
||||
|
|
|
@ -82,7 +82,14 @@ func confirmUpdate(ver string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
fmt.Printf("This will update Tailscale from %v to %v. Continue? [y/n] ", version.Short(), ver)
|
||||
msg := fmt.Sprintf("This will update Tailscale from %v to %v. Continue?", version.Short(), ver)
|
||||
return promptYesNo(msg)
|
||||
}
|
||||
|
||||
// PromptYesNo takes a question and prompts the user to answer the
|
||||
// question with a yes or no. It appends a [y/n] to the message.
|
||||
func promptYesNo(msg string) bool {
|
||||
fmt.Print(msg + " [y/n] ")
|
||||
var resp string
|
||||
fmt.Scanln(&resp)
|
||||
resp = strings.ToLower(resp)
|
||||
|
|
Loading…
Reference in New Issue