feat(dns): client for creating ingress records

This commit is contained in:
Pavel Sviderski
2025-02-24 20:33:08 +10:00
parent ecec42ea60
commit 2d84059d7f
3 changed files with 94 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
package client
import (
"context"
"fmt"
"uncloud/internal/machine/api/pb"
)
// TODO:
func (cli *Client) CreateIngressRecords(ctx context.Context, serviceID string) ([]*pb.DNSRecord, error) {
// TODO:
// - Inspect the service and get the list of machines it runs on.
// - For each machine get the machine's public IP address(s).
// - Update the wildcard DNS record for the service with the public IP addresses (call Cluster API).
req := &pb.CreateDomainRecordsRequest{
Records: []*pb.DNSRecord{
{
Name: "*",
Type: pb.DNSRecord_A,
// TODO: Get the public IP addresses of the machines running Caddy containers.
Values: []string{"1.2.3.4", "5.6.7.8"},
},
// TODO: Add AAAA record with routable IPv6 addresses of machines running Caddy containers.
},
}
resp, err := cli.CreateDomainRecords(ctx, req)
if err != nil {
return nil, fmt.Errorf("create cluster domain records in Uncloud DNS: %w", err)
}
return resp.Records, nil
}
+18
View File
@@ -1,10 +1,28 @@
package dns
const (
RecordTypeA RecordType = "A"
RecordTypeAAAA RecordType = "AAAA"
)
type RecordType string
type DomainResponse struct {
Name string `json:"name,omitempty"`
Token string `json:"token,omitempty"`
}
type RecordRequest struct {
Name string `json:"name,omitempty"`
Type RecordType `json:"type,omitempty"`
Values []string `json:"values,omitempty"`
}
type RecordResponse struct {
RecordRequest
FQDN string `json:"fqdn,omitempty"`
}
type AuthErrorResponse struct {
Status int `json:"status,omitempty"`
Message string `json:"msg,omitempty"`
+43
View File
@@ -1,6 +1,7 @@
package dns
import (
"bytes"
"encoding/json"
"errors"
"fmt"
@@ -17,6 +18,10 @@ type Client interface {
// ReserveDomain calls Uncloud DNS to reserve a new domain. It returns the domain, a token for authentication,
// and an error.
ReserveDomain(endpoint string) (string, string, error)
// CreateRecords calls Uncloud DNS to create or update DNS records based on the supplied RecordRequests
// for the specified domain.
CreateRecords(endpoint, domain, token string, records []RecordRequest) ([]RecordResponse, error)
}
// ErrAuthNoDomain indicates that a request failed authentication because the domain was not found.
@@ -55,6 +60,35 @@ func (c *client) ReserveDomain(endpoint string) (string, string, error) {
return domain, resp.Token, nil
}
func (c *client) CreateRecords(endpoint, domain, token string, records []RecordRequest) ([]RecordResponse, error) {
// TODO: update Uncloud DNS service to not use a leading dot for domain names.
if !strings.HasPrefix(domain, ".") {
domain = "." + domain
}
url := fmt.Sprintf("%s/domains/%s/records", endpoint, domain)
var resp []RecordResponse
for _, recordRequest := range records {
body, err := jsonBody(recordRequest)
if err != nil {
return resp, err
}
req, err := c.request(http.MethodPost, url, body, token)
if err != nil {
return resp, err
}
var recordResp RecordResponse
if err = c.do(req, &recordResp); err != nil {
return resp, err
}
resp = append(resp, recordResp)
}
return resp, nil
}
func (c *client) request(method string, url string, body io.Reader, token string) (*http.Request, error) {
req, err := http.NewRequest(method, url, body)
if err != nil {
@@ -116,3 +150,12 @@ func (c *client) do(req *http.Request, responseBody any) error {
return nil
}
func jsonBody(payload any) (io.Reader, error) {
buf := &bytes.Buffer{}
err := json.NewEncoder(buf).Encode(payload)
if err != nil {
return nil, err
}
return buf, nil
}