2022-12-14 14:35:07 +00:00
package main
import (
"flag"
"fmt"
2023-01-25 19:24:33 +00:00
"log"
2022-12-14 14:35:07 +00:00
"net/http"
"os"
2023-01-25 19:24:33 +00:00
"strings"
2022-12-14 14:35:07 +00:00
"time"
2024-01-17 16:49:34 +00:00
"github.com/hetznercloud/hcloud-go/v2/hcloud"
2022-12-14 14:35:07 +00:00
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
"github.com/jtaczanowski/go-scheduler"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
const (
defaultPort = 8080
defaultFetchInterval = 1 * time . Minute
)
var (
2023-01-25 19:24:33 +00:00
hcloudAPIToken string
port uint
fetchInterval time . Duration
additionalLabelsFlag string
additionalLabels [ ] string
2022-12-14 14:35:07 +00:00
)
func handleFlags ( ) {
flag . StringVar ( & hcloudAPIToken , "hcloud-token" , "" , "the token to authenticate against the HCloud API" )
flag . UintVar ( & port , "port" , defaultPort , "the port that the exporter exposes its data on" )
flag . DurationVar ( & fetchInterval , "fetch-interval" , defaultFetchInterval , "the interval between data fetching cycles" )
2023-01-25 19:24:33 +00:00
flag . StringVar ( & additionalLabelsFlag , "additional-labels" , "" , "comma separated additional labels to parse for all metrics, e.g: 'service,environment,owner'" )
2022-12-14 14:35:07 +00:00
flag . Parse ( )
if hcloudAPIToken == "" {
if envHCloudAPIToken , present := os . LookupEnv ( "HCLOUD_TOKEN" ) ; present {
hcloudAPIToken = envHCloudAPIToken
}
}
if hcloudAPIToken == "" {
panic ( fmt . Errorf ( "no API token for HCloud specified, but required" ) )
}
2024-05-29 18:15:53 +00:00
if strings . HasPrefix ( hcloudAPIToken , "file:" ) {
hcloudAPITokenBytes , err := os . ReadFile ( strings . TrimPrefix ( hcloudAPIToken , "file:" ) )
if err != nil {
panic ( fmt . Errorf ( "failed to read HCLOUD_TOKEN from file: %s" , err . Error ( ) ) )
}
hcloudAPIToken = strings . TrimSpace ( string ( hcloudAPITokenBytes ) )
}
if len ( hcloudAPIToken ) != 64 {
panic ( fmt . Errorf ( "invalid API token for HCloud specified, must be 64 characters long" ) )
}
2023-01-25 19:24:33 +00:00
additionalLabelsFlag = strings . TrimSpace ( strings . ReplaceAll ( additionalLabelsFlag , " " , "" ) )
additionalLabelsSlice := strings . Split ( additionalLabelsFlag , "," )
if len ( additionalLabelsSlice ) > 0 && additionalLabelsSlice [ 0 ] != "" {
additionalLabels = additionalLabelsSlice
}
2022-12-14 14:35:07 +00:00
}
func main ( ) {
handleFlags ( )
client := hcloud . NewClient ( hcloud . WithToken ( hcloudAPIToken ) )
priceRepository := & fetcher . PriceProvider { Client : client }
fetchers := fetcher . Fetchers {
2023-01-25 19:24:33 +00:00
fetcher . NewFloatingIP ( priceRepository , additionalLabels ... ) ,
fetcher . NewPrimaryIP ( priceRepository , additionalLabels ... ) ,
fetcher . NewLoadbalancer ( priceRepository , additionalLabels ... ) ,
fetcher . NewLoadbalancerTraffic ( priceRepository , additionalLabels ... ) ,
fetcher . NewServer ( priceRepository , additionalLabels ... ) ,
fetcher . NewServerBackup ( priceRepository , additionalLabels ... ) ,
fetcher . NewServerTraffic ( priceRepository , additionalLabels ... ) ,
fetcher . NewSnapshot ( priceRepository , additionalLabels ... ) ,
fetcher . NewVolume ( priceRepository , additionalLabels ... ) ,
2022-12-14 14:35:07 +00:00
}
fetchers . MustRun ( client )
scheduler . RunTaskAtInterval ( func ( ) { fetchers . MustRun ( client ) } , fetchInterval , 0 )
scheduler . RunTaskAtInterval ( priceRepository . Sync , 10 * fetchInterval , 10 * fetchInterval )
registry := prometheus . NewRegistry ( )
fetchers . RegisterCollectors ( registry )
http . Handle ( "/metrics" , promhttp . HandlerFor ( registry , promhttp . HandlerOpts { } ) )
2023-01-25 19:24:33 +00:00
log . Printf ( "Listening on: http://0.0.0.0:%d\n" , port )
2023-05-07 13:27:31 +00:00
server := & http . Server {
Addr : fmt . Sprintf ( ":%d" , port ) ,
ReadHeaderTimeout : 10 * time . Second ,
}
if err := server . ListenAndServe ( ) ; err != nil {
2022-12-14 14:35:07 +00:00
panic ( err )
}
}