mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
tsnet: add examples (#8289)
Closes #8288 Follows the examples from the KB[1]. [1]: https://tailscale.com/kb/1244/tsnet/ Signed-off-by: Xe Iaso <xe@tailscale.com>
This commit is contained in:
parent
1138f4eb5f
commit
24f0e91169
72
tsnet/example_tshello_test.go
Normal file
72
tsnet/example_tshello_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package tsnet_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"tailscale.com/tsnet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func firstLabel(s string) string {
|
||||||
|
s, _, _ = strings.Cut(s, ".")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example_tshello is a full example on using tsnet. When you run this program it will print
|
||||||
|
// an authentication link. Open it in your favorite web browser and add it to your tailnet
|
||||||
|
// like any other machine. Open another terminal window and try to ping it:
|
||||||
|
//
|
||||||
|
// $ ping tshello -c 2
|
||||||
|
// PING tshello (100.105.183.159) 56(84) bytes of data.
|
||||||
|
// 64 bytes from tshello.your-tailnet.ts.net (100.105.183.159): icmp_seq=1 ttl=64 time=25.0 ms
|
||||||
|
// 64 bytes from tshello.your-tailnet.ts.net (100.105.183.159): icmp_seq=2 ttl=64 time=1.12 ms
|
||||||
|
//
|
||||||
|
// Then connect to it using curl:
|
||||||
|
//
|
||||||
|
// $ curl http://tshello
|
||||||
|
// <html><body><h1>Hello, world!</h1>
|
||||||
|
// <p>You are <b>Xe</b> from <b>pneuma</b> (100.78.40.86:49214)</p>
|
||||||
|
//
|
||||||
|
// From here you can do anything you want with the Go standard library HTTP stack, or anything
|
||||||
|
// that is compatible with it (Gin/Gonic, Gorilla/mux, etc.).
|
||||||
|
func Example_tshello() {
|
||||||
|
var (
|
||||||
|
addr = flag.String("addr", ":80", "address to listen on")
|
||||||
|
hostname = flag.String("hostname", "tshello", "hostname to use on the tailnet")
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
s := new(tsnet.Server)
|
||||||
|
s.Hostname = *hostname
|
||||||
|
defer s.Close()
|
||||||
|
ln, err := s.Listen("tcp", *addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
lc, err := s.LocalClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
who, err := lc.WhoIs(r.Context(), r.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "<html><body><h1>Hello, tailnet!</h1>\n")
|
||||||
|
fmt.Fprintf(w, "<p>You are <b>%s</b> from <b>%s</b> (%s)</p>",
|
||||||
|
html.EscapeString(who.UserProfile.LoginName),
|
||||||
|
html.EscapeString(firstLabel(who.Node.ComputedName)),
|
||||||
|
r.RemoteAddr)
|
||||||
|
})))
|
||||||
|
}
|
212
tsnet/example_tsnet_test.go
Normal file
212
tsnet/example_tsnet_test.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package tsnet_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"tailscale.com/tsnet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExampleServer shows you how to construct a ready-to-use tsnet instance.
|
||||||
|
func ExampleServer() {
|
||||||
|
srv := new(tsnet.Server)
|
||||||
|
if err := srv.Start(); err != nil {
|
||||||
|
log.Fatalf("can't start tsnet server: %v", err)
|
||||||
|
}
|
||||||
|
defer srv.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_hostname shows you how to set a tsnet server's hostname.
|
||||||
|
//
|
||||||
|
// This setting lets you control the host name of your program on your
|
||||||
|
// tailnet. By default this will be the name of your program (such as foo
|
||||||
|
// for a program stored at /usr/local/bin/foo). You can also override this
|
||||||
|
// by setting the Hostname field.
|
||||||
|
func ExampleServer_hostname() {
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: "kirito",
|
||||||
|
}
|
||||||
|
|
||||||
|
// do something with srv
|
||||||
|
_ = srv
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_dir shows you how to configure the persistent directory for
|
||||||
|
// a tsnet application. This is where the Tailscale node information is stored
|
||||||
|
// so that your application can reconnect to your tailnet when the application
|
||||||
|
// is restarted.
|
||||||
|
//
|
||||||
|
// By default, tsnet will store data in your user configuration directory based
|
||||||
|
// on the name of the binary. Note that this folder must already exist or tsnet
|
||||||
|
// calls will fail.
|
||||||
|
func ExampleServer_dir() {
|
||||||
|
dir := filepath.Join("/data", "tsnet")
|
||||||
|
|
||||||
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Dir: dir,
|
||||||
|
}
|
||||||
|
|
||||||
|
// do something with srv
|
||||||
|
_ = srv
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_multipleInstances shows you how to configure multiple instances
|
||||||
|
// of tsnet per program. This allows you to have multiple Tailscale nodes in the
|
||||||
|
// same process/container.
|
||||||
|
func ExampleServer_multipleInstances() {
|
||||||
|
baseDir := "/data"
|
||||||
|
var servers []*tsnet.Server
|
||||||
|
for _, hostname := range []string{"ichika", "nino", "miku", "yotsuba", "itsuki"} {
|
||||||
|
os.MkdirAll(filepath.Join(baseDir, hostname), 0700)
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: hostname,
|
||||||
|
AuthKey: os.Getenv("TS_AUTHKEY"),
|
||||||
|
Ephemeral: true,
|
||||||
|
Dir: filepath.Join(baseDir, hostname),
|
||||||
|
}
|
||||||
|
if err := srv.Start(); err != nil {
|
||||||
|
log.Fatalf("can't start tsnet server: %v", err)
|
||||||
|
}
|
||||||
|
servers = append(servers, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When you're done, close the instances
|
||||||
|
defer func() {
|
||||||
|
for _, srv := range servers {
|
||||||
|
srv.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_ignoreLogs shows you how to ignore all of the log messages written
|
||||||
|
// by a tsnet instance.
|
||||||
|
func ExampleServer_ignoreLogs() {
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Logf: func(string, ...any) {},
|
||||||
|
}
|
||||||
|
_ = srv
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_ignoreLogsSometimes shows you how to ignore all of the log messages
|
||||||
|
// written by a tsnet instance, but allows you to opt-into them if a command-line
|
||||||
|
// flag is set.
|
||||||
|
func ExampleServer_ignoreLogsSometimes() {
|
||||||
|
tsnetVerbose := flag.Bool("tsnet-verbose", false, "if set, verbosely log tsnet information")
|
||||||
|
hostname := flag.String("tsnet-hostname", "hikari", "hostname to use on the tailnet")
|
||||||
|
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: *hostname,
|
||||||
|
Logf: func(string, ...any) {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if *tsnetVerbose {
|
||||||
|
srv.Logf = log.New(os.Stderr, fmt.Sprintf("[tsnet:%s] ", *hostname), log.LstdFlags).Printf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_HTTPClient shows you how to make HTTP requests over your tailnet.
|
||||||
|
//
|
||||||
|
// If you want to make outgoing HTTP connections to resources on your tailnet, use
|
||||||
|
// the HTTP client that the tsnet.Server exposes.
|
||||||
|
func ExampleServer_HTTPClient() {
|
||||||
|
srv := &tsnet.Server{}
|
||||||
|
cli := srv.HTTPClient()
|
||||||
|
|
||||||
|
resp, err := cli.Get("https://hello.ts.net")
|
||||||
|
if resp == nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// do something with resp
|
||||||
|
_ = resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_Start demonstrates the Start method, which should be called if
|
||||||
|
// you need to explicitly start it. Note that the Start method is implicitly
|
||||||
|
// called if needed.
|
||||||
|
func ExampleServer_Start() {
|
||||||
|
srv := new(tsnet.Server)
|
||||||
|
|
||||||
|
if err := srv.Start(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be sure to close the server instance at some point. It will stay open until
|
||||||
|
// either the OS process ends or the server is explicitly closed.
|
||||||
|
defer srv.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_Listen shows you how to create a TCP listener on your tailnet and
|
||||||
|
// then makes an HTTP server on top of that.
|
||||||
|
func ExampleServer_Listen() {
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: "tadaima",
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := srv.Listen("tcp", ":80")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_ListenTLS shows you how to create a TCP listener on your tailnet and
|
||||||
|
// then makes an HTTPS server on top of that.
|
||||||
|
func ExampleServer_ListenTLS() {
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: "aegis",
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := srv.ListenTLS("tcp", ":443")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_ListenFunnel shows you how to create an HTTPS service on both your tailnet
|
||||||
|
// and the public internet via Funnel.
|
||||||
|
func ExampleServer_ListenFunnel() {
|
||||||
|
srv := &tsnet.Server{
|
||||||
|
Hostname: "ophion",
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := srv.ListenFunnel("tcp", ":443")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleServer_ListenFunnel_funnelOnly shows you how to create a funnel-only HTTPS service.
|
||||||
|
func ExampleServer_ListenFunnel_funnelOnly() {
|
||||||
|
srv := new(tsnet.Server)
|
||||||
|
srv.Hostname = "ophion"
|
||||||
|
ln, err := srv.ListenFunnel("tcp", ":443", tsnet.FunnelOnly())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
|
||||||
|
})))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user