tailscale/tsnet/example_tsnet_test.go

213 lines
5.7 KiB
Go

// 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!")
})))
}