Files
tf_registry/server/handlers.go
T

134 lines
3.4 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
"os"
"strings"
"time"
)
// Terraform Registry Protocol Structs
type Discovery struct {
ProvidersV1 string `json:"providers.v1"`
}
type VersionList struct {
ID string `json:"id"`
Versions []Version `json:"versions"`
Warnings []string `json:"warnings"`
}
type Version struct {
Version string `json:"version"`
Protocols []string `json:"protocols"`
Platforms []Platform `json:"platforms"`
}
type Platform struct {
OS string `json:"os"`
Arch string `json:"arch"`
}
type DownloadResponse struct {
Protocols []string `json:"protocols"`
OS string `json:"os"`
Arch string `json:"arch"`
Filename string `json:"filename"`
DownloadURL string `json:"download_url"`
ShasumsURL string `json:"shasums_url"`
ShasumsSignatureURL string `json:"shasums_signature_url"`
Shasum string `json:"shasum"`
SigningKeys SigningKeys `json:"signing_keys"`
}
type SigningKeys struct {
GPGPublicKeys []GPGPublicKey `json:"gpg_public_keys"`
}
type GPGPublicKey struct {
KeyID string `json:"key_id"`
ASCIIArmor string `json:"ascii_armor"`
}
func discoveryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Discovery{ProvidersV1: "/v1/providers/"})
}
func rootHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
tmpl, _ := templateFS.ReadFile("index.html")
html := strings.Replace(string(tmpl), "{{.Version}}", VERSION, 1)
fmt.Fprint(w, html)
}
func healthzHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
func readyzHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
_, err := s3Client.BucketExists(ctx, bucketName)
if err != nil {
msg := fmt.Sprintf("s3 unreachable: %v", err)
log.Printf("readyz: %s", msg)
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(msg))
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
func debugHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprintf(w, "=== ENV ===\n")
for _, e := range os.Environ() {
if strings.Contains(e, "S3_") || strings.Contains(e, "REGISTRY") || strings.Contains(e, "PORT") {
fmt.Fprintln(w, e)
}
}
s3ep := os.Getenv("S3_ENDPOINT")
fmt.Fprintf(w, "\n=== DNS: %s ===\n", s3ep)
addrs, err := net.LookupHost(s3ep)
if err != nil {
fmt.Fprintf(w, "DNS ERROR: %v\n", err)
} else {
for _, a := range addrs {
fmt.Fprintf(w, " %s\n", a)
}
}
fmt.Fprintf(w, "\n=== TCP dial: %s:443 ===\n", s3ep)
conn, err := net.DialTimeout("tcp", s3ep+":443", 5*time.Second)
if err != nil {
fmt.Fprintf(w, "TCP ERROR: %v\n", err)
} else {
fmt.Fprintf(w, "TCP OK: %s -> %s\n", conn.LocalAddr(), conn.RemoteAddr())
conn.Close()
}
fmt.Fprintf(w, "\n=== S3 BucketExists ===\n")
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
_, err = s3Client.BucketExists(ctx, bucketName)
if err != nil {
fmt.Fprintf(w, "S3 ERROR: %v\n", err)
} else {
fmt.Fprintf(w, "S3 OK: bucket %s accessible\n", bucketName)
}
}