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