@ -22,8 +22,11 @@ import (
"log"
"log"
"net"
"net"
"net/http"
"net/http"
"net/url"
"os"
"os"
"path/filepath"
"path/filepath"
"runtime/debug"
"strconv"
"strings"
"strings"
"sync/atomic"
"sync/atomic"
"time"
"time"
@ -34,20 +37,56 @@ import (
func main ( ) {
func main ( ) {
var (
var (
auth = flag . Bool ( "auth" , false , "auth with cigocached and exit, printing the access token as output" )
version = flag . Bool ( "version" , false , "print version and exit" )
token = flag . String ( "token" , "" , "the cigocached access token to use, as created using --auth" )
auth = flag . Bool ( "auth" , false , "auth with cigocached and exit, printing the access token as output" )
cigocachedURL = flag . String ( "cigocached-url" , "" , "optional cigocached URL (scheme, host, and port). empty means to not use one." )
stats = flag . Bool ( "stats" , false , "fetch and print cigocached stats and exit" )
dir = flag . String ( "cache-dir" , "" , "cache directory; empty means automatic" )
token = flag . String ( "token" , "" , "the cigocached access token to use, as created using --auth" )
verbose = flag . Bool ( "verbose" , false , "enable verbose logging" )
srvURL = flag . String ( "cigocached-url" , "" , "optional cigocached URL (scheme, host, and port). Empty means to not use one." )
srvHostDial = flag . String ( "cigocached-host" , "" , "optional cigocached host to dial instead of the host in the provided --cigocached-url. Useful for public TLS certs on private addresses." )
dir = flag . String ( "cache-dir" , "" , "cache directory; empty means automatic" )
verbose = flag . Bool ( "verbose" , false , "enable verbose logging" )
)
)
flag . Parse ( )
flag . Parse ( )
if * version {
info , ok := debug . ReadBuildInfo ( )
if ! ok {
log . Fatal ( "no build info" )
}
var (
rev string
dirty bool
)
for _ , s := range info . Settings {
switch s . Key {
case "vcs.revision" :
rev = s . Value
case "vcs.modified" :
dirty , _ = strconv . ParseBool ( s . Value )
}
}
if dirty {
rev += "-dirty"
}
fmt . Println ( rev )
return
}
var srvHost string
if * srvHostDial != "" && * srvURL != "" {
u , err := url . Parse ( * srvURL )
if err != nil {
log . Fatal ( err )
}
srvHost = u . Hostname ( )
}
if * auth {
if * auth {
if * cigocachedURL == "" {
if * srv URL == "" {
log . Print ( "--cigocached-url is empty, skipping auth" )
log . Print ( "--cigocached-url is empty, skipping auth" )
return
return
}
}
tk , err := fetchAccessToken ( httpClient ( ) , os . Getenv ( "ACTIONS_ID_TOKEN_REQUEST_URL" ) , os . Getenv ( "ACTIONS_ID_TOKEN_REQUEST_TOKEN" ) , * cigocachedURL )
tk , err := fetchAccessToken ( httpClient ( srvHost , * srvHostDial ) , os . Getenv ( "ACTIONS_ID_TOKEN_REQUEST_URL" ) , os . Getenv ( "ACTIONS_ID_TOKEN_REQUEST_TOKEN" ) , * srv URL)
if err != nil {
if err != nil {
log . Printf ( "error fetching access token, skipping auth: %v" , err )
log . Printf ( "error fetching access token, skipping auth: %v" , err )
return
return
@ -56,6 +95,28 @@ func main() {
return
return
}
}
if * stats {
if * srvURL == "" {
log . Fatal ( "--cigocached-url is empty; cannot fetch stats" )
}
tk := * token
if tk == "" {
log . Fatal ( "--token is empty; cannot fetch stats" )
}
c := & gocachedClient {
baseURL : * srvURL ,
cl : httpClient ( srvHost , * srvHostDial ) ,
accessToken : tk ,
verbose : * verbose ,
}
stats , err := c . fetchStats ( )
if err != nil {
log . Fatalf ( "error fetching gocached stats: %v" , err )
}
fmt . Println ( stats )
return
}
if * dir == "" {
if * dir == "" {
d , err := os . UserCacheDir ( )
d , err := os . UserCacheDir ( )
if err != nil {
if err != nil {
@ -75,13 +136,13 @@ func main() {
} ,
} ,
verbose : * verbose ,
verbose : * verbose ,
}
}
if * cigocached URL != "" {
if * srv URL != "" {
if * verbose {
if * verbose {
log . Printf ( "Using cigocached at %s" , * cigocached URL)
log . Printf ( "Using cigocached at %s" , * srv URL)
}
}
c . gocached = & gocachedClient {
c . gocached = & gocachedClient {
baseURL : * cigocached URL,
baseURL : * srv URL,
cl : httpClient ( ) ,
cl : httpClient ( srvHost , * srvHostDial ) ,
accessToken : * token ,
accessToken : * token ,
verbose : * verbose ,
verbose : * verbose ,
}
}
@ -104,18 +165,18 @@ func main() {
}
}
}
}
func httpClient ( ) * http . Client {
func httpClient ( srvHost , srvHostDial string ) * http . Client {
if srvHost == "" || srvHostDial == "" {
return http . DefaultClient
}
return & http . Client {
return & http . Client {
Transport : & http . Transport {
Transport : & http . Transport {
DialContext : func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
DialContext : func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
host , port , err := net . SplitHostPort ( addr )
if host , port , err := net . SplitHostPort ( addr ) ; err == nil && host == srvHost {
if err == nil {
// This allows us to serve a publicly trusted TLS cert
// This does not run in a tailnet. We serve corp.ts.net
// while also minimising latency by explicitly using a
// TLS certs, and override DNS resolution to lookup the
// private network address.
// private IP for the VM by its hostname.
addr = net . JoinHostPort ( srvHostDial , port )
if vm , ok := strings . CutSuffix ( host , ".corp.ts.net" ) ; ok {
addr = net . JoinHostPort ( vm , port )
}
}
}
var d net . Dialer
var d net . Dialer
return d . DialContext ( ctx , network , addr )
return d . DialContext ( ctx , network , addr )