Something went wrong. Try again.
Cloudflare Tunnel client with NetBSD support
Something went wrong. Try again.
5.2 kB · 192 lines
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193package cfapi
import ( "encoding/json" "fmt" "io" "net/http" "path"
"github.com/google/uuid" "github.com/pkg/errors")
type Change = string
const ( ChangeNew = "new" ChangeUpdated = "updated" ChangeUnchanged = "unchanged")
// HostnameRoute represents a record type that can route to a tunneltype HostnameRoute interface { json.Marshaler RecordType() string UnmarshalResult(body io.Reader) (HostnameRouteResult, error) String() string}
type HostnameRouteResult interface { // SuccessSummary explains what will route to this tunnel when it's provisioned successfully SuccessSummary() string}
type DNSRoute struct { userHostname string overwriteExisting bool}
type DNSRouteResult struct { route *DNSRoute CName Change `json:"cname"` Name string `json:"name"`}
func NewDNSRoute(userHostname string, overwriteExisting bool) HostnameRoute { return &DNSRoute{ userHostname: userHostname, overwriteExisting: overwriteExisting, }}
func (dr *DNSRoute) MarshalJSON() ([]byte, error) { s := struct { Type string `json:"type"` UserHostname string `json:"user_hostname"` OverwriteExisting bool `json:"overwrite_existing"` }{ Type: dr.RecordType(), UserHostname: dr.userHostname, OverwriteExisting: dr.overwriteExisting, } return json.Marshal(&s)}
func (dr *DNSRoute) UnmarshalResult(body io.Reader) (HostnameRouteResult, error) { var result DNSRouteResult err := parseResponse(body, &result) result.route = dr return &result, err}
func (dr *DNSRoute) RecordType() string { return "dns"}
func (dr *DNSRoute) String() string { return fmt.Sprintf("%s %s", dr.RecordType(), dr.userHostname)}
func (res *DNSRouteResult) SuccessSummary() string { var msgFmt string switch res.CName { case ChangeNew: msgFmt = "Added CNAME %s which will route to this tunnel" case ChangeUpdated: // this is not currently returned by tunnelsore msgFmt = "%s updated to route to your tunnel" case ChangeUnchanged: msgFmt = "%s is already configured to route to your tunnel" } return fmt.Sprintf(msgFmt, res.hostname())}
// hostname yields the resulting name for the DNS route; if that is not available from Cloudflare API, then the// requested name is returned instead (should not be the common path, it is just a fall-back).func (res *DNSRouteResult) hostname() string { if res.Name != "" { return res.Name } return res.route.userHostname}
type LBRoute struct { lbName string lbPool string}
type LBRouteResult struct { route *LBRoute LoadBalancer Change `json:"load_balancer"` Pool Change `json:"pool"`}
func NewLBRoute(lbName, lbPool string) HostnameRoute { return &LBRoute{ lbName: lbName, lbPool: lbPool, }}
func (lr *LBRoute) MarshalJSON() ([]byte, error) { s := struct { Type string `json:"type"` LBName string `json:"lb_name"` LBPool string `json:"lb_pool"` }{ Type: lr.RecordType(), LBName: lr.lbName, LBPool: lr.lbPool, } return json.Marshal(&s)}
func (lr *LBRoute) RecordType() string { return "lb"}
func (lb *LBRoute) String() string { return fmt.Sprintf("%s %s %s", lb.RecordType(), lb.lbName, lb.lbPool)}
func (lr *LBRoute) UnmarshalResult(body io.Reader) (HostnameRouteResult, error) { var result LBRouteResult err := parseResponse(body, &result) result.route = lr return &result, err}
func (res *LBRouteResult) SuccessSummary() string { var msg string switch res.LoadBalancer + "," + res.Pool { case "new,new": msg = "Created load balancer %s and added a new pool %s with this tunnel as an origin" case "new,updated": msg = "Created load balancer %s with an existing pool %s which was updated to use this tunnel as an origin" case "new,unchanged": msg = "Created load balancer %s with an existing pool %s which already has this tunnel as an origin" case "updated,new": msg = "Added new pool %[2]s with this tunnel as an origin to load balancer %[1]s" case "updated,updated": msg = "Updated pool %[2]s to use this tunnel as an origin and added it to load balancer %[1]s" case "updated,unchanged": msg = "Added pool %[2]s, which already has this tunnel as an origin, to load balancer %[1]s" case "unchanged,updated": msg = "Added this tunnel as an origin in pool %[2]s which is already used by load balancer %[1]s" case "unchanged,unchanged": msg = "Load balancer %s already uses pool %s which has this tunnel as an origin" case "unchanged,new": // this state is not possible fallthrough default: msg = "Something went wrong: failed to modify load balancer %s with pool %s; please check traffic manager configuration in the dashboard" }
return fmt.Sprintf(msg, res.route.lbName, res.route.lbPool)}
func (r *RESTClient) RouteTunnel(tunnelID uuid.UUID, route HostnameRoute) (HostnameRouteResult, error) { endpoint := r.baseEndpoints.zoneLevel endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("%v/routes", tunnelID)) resp, err := r.sendRequest("PUT", endpoint, route) if err != nil { return nil, errors.Wrap(err, "REST request failed") } defer resp.Body.Close()
if resp.StatusCode == http.StatusOK { return route.UnmarshalResult(resp.Body) }
return nil, r.statusCodeToError("add route", resp)}