diff --git a/main.go b/main.go new file mode 100644 index 0000000..c315dd3 --- /dev/null +++ b/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "html/template" + "io" + "log" + "net/http" + "os" + "path/filepath" + "strconv" +) + +type K8sList struct { + Items []json.RawMessage `json:"items"` +} + +func getEnv(key, fallback string) string { + if val, exists := os.LookupEnv(key); exists && val != "" { + return val + } + return fallback +} + +func getTemplate(path string) (*template.Template, error) { + content, err := os.ReadFile(path) + if err != nil { + return nil, err + } + return template.New("haproxy").Parse(string(content)) +} + +func getK8sResources(k8sHost, token string, verifySSL bool, resource string) ([]json.RawMessage, error) { + url := fmt.Sprintf("%s/api/v1/%s", k8sHost, resource) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", "Bearer "+token) + req.Header.Set("Accept", "application/json") + + client := &http.Client{} + if !verifySSL { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client.Transport = tr + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)) + } + + var list K8sList + if err := json.NewDecoder(resp.Body).Decode(&list); err != nil { + return nil, err + } + return list.Items, nil +} + +func main() { + k8sHost := getEnv("KUBERNETES_HOST", "") + k8sToken := getEnv("KUBERNETES_TOKEN", "") + verifySSLStr := getEnv("KUBERNETES_VERIFYSSL", "false") + templatePath := getEnv("HAPROXY_TEMPLATE", "haproxy.tmpl") + + if k8sHost == "" || k8sToken == "" { + log.Fatal("KUBERNETES_HOST and KUBERNETES_TOKEN must be set") + } + + verifySSL, err := strconv.ParseBool(verifySSLStr) + if err != nil { + log.Fatalf("Invalid KUBERNETES_VERIFYSSL value: %v", err) + } + + services, err := getK8sResources(k8sHost, k8sToken, verifySSL, "services") + if err != nil { + log.Fatalf("Failed to get services: %v", err) + } + endpoints, err := getK8sResources(k8sHost, k8sToken, verifySSL, "endpoints") + if err != nil { + log.Fatalf("Failed to get endpoints: %v", err) + } + + tmplAbsPath, _ := filepath.Abs(templatePath) + tmpl, err := getTemplate(tmplAbsPath) + if err != nil { + log.Fatalf("Failed to parse template: %v", err) + } + + var buf bytes.Buffer + err = tmpl.Execute(&buf, map[string]interface{}{ + "services": services, + "endpoints": endpoints, + }) + if err != nil { + log.Fatalf("Failed to render template: %v", err) + } + + fmt.Println(buf.String()) +}