[WIP] first implementation stubs

This commit is contained in:
2024-03-22 23:11:03 +01:00
parent 33921aa992
commit 6f5c58b906
16 changed files with 637 additions and 0 deletions

31
internal/config.go Normal file
View File

@@ -0,0 +1,31 @@
package internal
import (
"errors"
"fmt"
"time"
"github.com/jinzhu/configor"
)
type Config = struct {
LogLevel string `default:"Info" env:"MAIL_DNS_SERVICE_LOGLEVEL"`
LabelSelector string `default:"kops.k8s.io/instance-role=Node" env:"MAIL_DNS_SERVICE_LABELSELECTOR"`
HcloudToken string `default:"" env:"MAIL_DNS_SERVICE_HCLOUD_TOKEN"`
}
func GenConfig() (cfg *Config, err error) {
cfg = &Config{}
err = configor.New(&configor.Config{
ENVPrefix: "METALLB_IP_FLOATER",
AutoReload: true,
Silent: true,
AutoReloadInterval: time.Minute}).Load(cfg, "config.json")
if err != nil {
return nil, errors.New(fmt.Sprintf("Error generating Config: %s", err.Error()))
}
return cfg, nil
}

22
internal/config_test.go Normal file
View File

@@ -0,0 +1,22 @@
package internal
import (
"reflect"
"testing"
)
var defaultConfig = Config{
LogLevel: "Info",
LabelSelector: "kops.k8s.io/instance-role=Node",
HcloudToken: "",
}
func TestConfigDefaults(t *testing.T) {
cfg, err := GenConfig()
if err != nil {
t.Errorf("%s", err.Error())
}
if !reflect.DeepEqual(&defaultConfig, cfg) {
t.Errorf("got %+v, want %+v", cfg, defaultConfig)
}
}

31
internal/health.go Normal file
View File

@@ -0,0 +1,31 @@
package internal
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
)
func StartHealthEndpoint() {
r := mux.NewRouter()
r.Use(mux.CORSMethodMiddleware(r))
r.HandleFunc("/health", send200).Methods(http.MethodGet)
err := http.ListenAndServe("0.0.0.0:8080", r)
if err != nil {
log.WithFields(log.Fields{
"Caller": "StartHealthEndpoint",
}).Error(fmt.Sprintf("Error creating health endpoint: %s", err.Error()))
}
}
func send200(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte{})
if err != nil {
log.WithFields(log.Fields{
"Caller": "send200",
}).Error(fmt.Sprintf("Error answering health endpoint: %s", err.Error()))
}
}

23
internal/health_test.go Normal file
View File

@@ -0,0 +1,23 @@
package internal
import (
"net/http"
"strings"
"testing"
)
func TestHealth(t *testing.T) {
go func() {
StartHealthEndpoint()
}()
request, _ := http.NewRequest(http.MethodGet, "http://localhost:8080/health", strings.NewReader(""))
resp, err := http.DefaultClient.Do(request)
if err != nil {
t.Errorf("Health endpoint did not start: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Bad response from health endpoint. Want: %d, got %d", http.StatusOK, resp.StatusCode)
}
}

41
internal/hetzner.go Normal file
View File

@@ -0,0 +1,41 @@
package internal
import (
"context"
"errors"
"fmt"
"github.com/hetznercloud/hcloud-go/hcloud"
log "github.com/sirupsen/logrus"
)
func GetAllNodes(cfg *Config) ([]*hcloud.Server, error) {
client := hcloud.NewClient(hcloud.WithToken(cfg.HcloudToken))
servers, _, err := client.Server.List(context.TODO(), hcloud.ServerListOpts{
ListOpts: hcloud.ListOpts{
LabelSelector: cfg.LabelSelector,
}})
if err != nil {
return nil, errors.New(fmt.Sprintf("Error listing Hetzner Nodes: %s", err.Error()))
}
if servers == nil {
return nil, errors.New(fmt.Sprintf("No Nodes found with label selector: %s", cfg.LabelSelector))
}
return servers, nil
}
func GetAllIps(servers []*hcloud.Server) ([]string, error) {
ips := make([]string, len(servers))
for i, instance := range servers {
if len(instance.PrivateNet) == 0 || instance.PrivateNet[0].IP == nil {
return []string{""}, errors.New(fmt.Sprintf("Instance %s has no attached IP", instance.Name))
}
log.WithFields(log.Fields{
"Caller": "GetAllIps",
}).Info(fmt.Sprintf("Found IP: %s", instance.PrivateNet[0].IP.String()))
ips[i] = instance.PrivateNet[0].IP.String()
}
return ips, nil
}

30
internal/hetzner_test.go Normal file
View File

@@ -0,0 +1,30 @@
package internal
import (
"testing"
"github.com/hetznercloud/hcloud-go/hcloud"
)
func TestGetAllIps(t *testing.T) {
servers := []*hcloud.Server{{
Status: hcloud.ServerStatusRunning,
Name: "Test",
}}
servers = append(servers, &hcloud.Server{
Status: hcloud.ServerStatusRunning,
Name: "Test2",
})
expectedError := "Instance Test has no attached IP"
_, err := GetAllIps(servers)
if err == nil {
t.Error("GetAllIps did not error with missing data")
}
if err.Error() != expectedError {
t.Errorf("Wrong error message. want %s, got %s", expectedError, err.Error())
}
}

61
internal/k8s.go Normal file
View File

@@ -0,0 +1,61 @@
package internal
import (
"bytes"
"errors"
"fmt"
"html/template"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
func RecreateDnsCrd() error {
k8s_config, err := rest.InClusterConfig()
if err != nil {
return errors.New(fmt.Sprintf("Could not create in cluster k8s config: %v", err))
}
_, err = kubernetes.NewForConfig(k8s_config)
if err != nil {
return errors.New(fmt.Sprintf("Could not create k8s client: %v", err))
}
return nil
}
var CRD_TEMPLATE = `
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: {{ .Name }}
annotations:
external.dns/provider: cf
spec:
endpoints:
- dnsName: mail
recordTTL: 180
recordType: A
targets:
- {{ .IP }}
`
type CrdConfig struct {
Name string
IP string
}
func generateCrd(name string, ip string) (string, error) {
config := CrdConfig{
Name: name,
IP: ip,
}
tmpl, err := template.New("crd").Parse(CRD_TEMPLATE)
if err != nil {
return "", errors.New(fmt.Sprintf("Errors in crd template: %s", err.Error()))
}
var buf bytes.Buffer
err = tmpl.Execute(&buf, &config)
if err != nil {
return "", errors.New(fmt.Sprintf("Could not render crd template: %s", err.Error()))
}
return buf.String(), nil
}

28
internal/utils/logging.go Normal file
View File

@@ -0,0 +1,28 @@
package utils
import (
"os"
"git.uploadfilter24.eu/covidnetes/mail-dns-service/internal"
log "github.com/sirupsen/logrus"
)
func ConfigureLogger(cfg *internal.Config) {
switch cfg.LogLevel {
case "Debug":
log.SetLevel(log.DebugLevel)
case "Info":
log.SetLevel(log.InfoLevel)
case "Warn":
log.SetLevel(log.WarnLevel)
case "Error":
log.SetLevel(log.ErrorLevel)
default:
log.SetLevel(log.InfoLevel)
log.Warnf("Home: invalid log level supplied: '%s'", cfg.LogLevel)
}
log.SetFormatter(&log.JSONFormatter{})
log.SetOutput(os.Stdout)
}