tsnet: move example programs into godoc examples

Signed-off-by: Harry Harpham <harry@tailscale.com>
hwh33/tsnet-services-support
Harry Harpham 2 days ago
parent f93322c2f3
commit 8fa186e42b
No known key found for this signature in database

@ -1,107 +0,0 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// The tsnet-services example demonstrates how to use tsnet with Services
// which listen on multiple ports.
//
// To run this example yourself:
//
// 1. Define an ACL tag, an auto-approval rule, and traffic permits by adding
// the following to your tailnet's ACL policy file:
// TODO: convince gofmt to chill
// "tagOwners": {
// "tag:tsnet-demo-host": ["autogroup:member"],
// },
// "autoApprovers": {
// "services": {
// "svc:tsnet-demo": ["tag:tsnet-demo-host"],
// },
// },
// // Allow anybody in the tailnet to reach the demo Service.
// "grants": [
// "src": ["*"],
// "dst": ["tag:tsnet-demo-host"],
// "ip": ["*"],
// ],
//
// 2. Generate an auth key using the Tailscale admin panel. When doing so, add
// the tsnet-demo-host tag to your key.
// https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key
//
// 2. Define a Service. For the purposes of this demo, it must be defined to
// listen on TCP ports 443 and 6060. Note that you only need to follow Step
// 1 in the following document.
// https://tailscale.com/kb/1552/tailscale-services#step-1-define-a-tailscale-service
//
// 3. Run the demo on the command line:
// TS_AUTHKEY=<yourkey> go run tsnet-services.go -service <service-name>
package main
import (
"flag"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"strings"
"tailscale.com/tsnet"
)
var (
svcName = flag.String("service", "", "the name of your Service, e.g. svc:demo-service")
)
func main() {
flag.Parse()
if *svcName == "" {
log.Fatal("a Service name must be provided")
}
const serverPort uint16 = 443
const pprofPort uint16 = 6060
s := &tsnet.Server{
Hostname: "tsnet-services-demo",
}
defer s.Close()
ln, err := s.ListenService(*svcName, serverPort, tsnet.ServiceHTTPOptions{HTTPS: true})
if err != nil {
log.Fatal(err)
}
defer ln.Close()
pprofLn, err := s.ListenService(*svcName, pprofPort, nil)
if err != nil {
log.Fatal(err)
}
defer pprofLn.Close()
go func() {
log.Printf("Listening for pprof requests on http://%v:%d\n", pprofLn.FQDN, pprofPort)
handler := func(w http.ResponseWriter, r *http.Request) {
// The pprof listener is separate from our main server, so we can
// allow users to leave off the /debug/pprof prefix. We'll just
// attach it here, then pass along to the pprof handlers, which have
// been added implicitly due to our import of net/http/pprof.
if !strings.HasPrefix("/debug/pprof", r.URL.Path) {
r.URL.Path = "/debug/pprof" + r.URL.Path
}
http.DefaultServeMux.ServeHTTP(w, r)
}
if err := http.Serve(pprofLn, http.HandlerFunc(handler)); err != nil {
log.Fatal("error serving pprof:", err)
}
}()
log.Printf("Listening on https://%v\n", ln.FQDN)
// Specifying a handler here means pprof endpoints will not be served by
// this server (since we are not using http.DefaultServeMux).
err = http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
}))
log.Fatal(err)
}

@ -1,99 +0,0 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// The tsnet-services example demonstrates how to use tsnet with Services and a
// reverse proxy. This is useful when the backing server is external to the
// tsnet application.
//
// To run this example yourself:
//
// 1. Define an ACL tag, an auto-approval rule, and traffic permits by adding
// the following to your tailnet's ACL policy file:
// TODO: convince gofmt to chill
// "tagOwners": {
// "tag:tsnet-demo-host": ["autogroup:member"],
// },
// "autoApprovers": {
// "services": {
// "svc:tsnet-demo": ["tag:tsnet-demo-host"],
// },
// },
// // Allow anybody in the tailnet to reach the demo Service.
// "grants": [
// "src": ["*"],
// "dst": ["tag:tsnet-demo-host"],
// "ip": ["*"],
// ],
//
// 2. Generate an auth key using the Tailscale admin panel. When doing so, add
// the tsnet-demo-host tag to your key.
// https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key
//
// 2. Define a Service. For the purposes of this demo, it must be defined to
// listen on TCP port 443. Note that you only need to follow Step 1 in the
// following document.
// https://tailscale.com/kb/1552/tailscale-services#step-1-define-a-tailscale-service
//
// 3. Run the demo on the command line:
// TS_AUTHKEY=<yourkey> go run tsnet-services.go -service <service-name>
package main
import (
"flag"
"fmt"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"tailscale.com/tsnet"
)
var (
svcName = flag.String("service", "", "the name of your Service, e.g. svc:demo-service")
)
func main() {
flag.Parse()
if *svcName == "" {
log.Fatal("a Service name must be provided")
}
const port uint16 = 443
// We will start an HTTP server on a local socket. This server will simulate
// a server which may be running in another process or even another machine.
backingListener, err := net.Listen("tcp", "localhost:0")
if err != nil {
log.Fatal(err)
}
defer backingListener.Close()
go func() {
log.Fatal(http.Serve(backingListener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
})))
}()
s := &tsnet.Server{
Hostname: "tsnet-services-demo",
}
defer s.Close()
ln, err := s.ListenService(*svcName, port, tsnet.ServiceHTTPOptions{HTTPS: true})
if err != nil {
log.Fatal(err)
}
defer ln.Close()
// Use a reverse proxy to direct traffic to the backing server
rp := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: backingListener.Addr().String(),
})
log.Printf("Listening on https://%v\n", ln.FQDN)
err = http.Serve(ln, rp)
log.Fatal(err)
}

@ -0,0 +1,61 @@
package tsnet_test
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"strings"
"tailscale.com/tsnet"
)
// This example function is in a separate file for the "net/http/pprof" import.
// ExampleServer_ListenService_multiplePorts demonstrates how to advertise a
// Service on multiple ports. In this example, we run an HTTPS server on 443 and
// an HTTP server handling pprof requests to the same runtime on 6060.
func ExampleServer_ListenService_multiplePorts() {
s := &tsnet.Server{
Hostname: "tsnet-services-demo",
}
defer s.Close()
ln, err := s.ListenService("svc:my-service", 443, tsnet.ServiceHTTPOptions{HTTPS: true})
if err != nil {
log.Fatal(err)
}
defer ln.Close()
pprofLn, err := s.ListenService("svc:my-service", 6060, nil)
if err != nil {
log.Fatal(err)
}
defer pprofLn.Close()
go func() {
log.Printf("Listening for pprof requests on http://%v:%d\n", pprofLn.FQDN, 6060)
handler := func(w http.ResponseWriter, r *http.Request) {
// The pprof listener is separate from our main server, so we can
// allow users to leave off the /debug/pprof prefix. We'll just
// attach it here, then pass along to the pprof handlers, which have
// been added implicitly due to our import of net/http/pprof.
if !strings.HasPrefix("/debug/pprof", r.URL.Path) {
r.URL.Path = "/debug/pprof" + r.URL.Path
}
http.DefaultServeMux.ServeHTTP(w, r)
}
if err := http.Serve(pprofLn, http.HandlerFunc(handler)); err != nil {
log.Fatal("error serving pprof:", err)
}
}()
log.Printf("Listening on https://%v\n", ln.FQDN)
// Specifying a handler here means pprof endpoints will not be served by
// this server (since we are not using http.DefaultServeMux).
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
})))
}

@ -8,6 +8,8 @@ import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
@ -200,3 +202,50 @@ func ExampleServer_ListenFunnel_funnelOnly() {
fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
})))
}
// ExampleServer_ListenService demonstrates how to advertise an HTTPS Service.
func ExampleServer_ListenService() {
s := &tsnet.Server{
Hostname: "tsnet-services-demo",
}
defer s.Close()
ln, err := s.ListenService("svc:my-service", 443, tsnet.ServiceHTTPOptions{HTTPS: true})
if err != nil {
log.Fatal(err)
}
defer ln.Close()
log.Printf("Listening on https://%v\n", ln.FQDN)
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
})))
}
// ExampleServer_ListenService_reverseProxy demonstrates how to advertise a
// Service targeting a reverse proxy. This is useful when the backing server is
// external to the tsnet application.
func ExampleServer_ListenService_reverseProxy() {
// targetAddress represents the address of the backing server.
const targetAddress = "1.2.3.4:80"
// We will use a reverse proxy to direct traffic to the backing server.
reverseProxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: targetAddress,
})
s := &tsnet.Server{
Hostname: "tsnet-services-demo",
}
defer s.Close()
ln, err := s.ListenService("svc:my-service", 443, tsnet.ServiceHTTPOptions{HTTPS: true})
if err != nil {
log.Fatal(err)
}
defer ln.Close()
log.Printf("Listening on https://%v\n", ln.FQDN)
log.Fatal(http.Serve(ln, reverseProxy))
}

Loading…
Cancel
Save