feat(dns): expose service as service-name.cluster-domain if cluster domain reserved

This commit is contained in:
Pavel Sviderski
2025-02-26 21:10:21 +10:00
parent 4cc68e3133
commit a5f6ec4a68
5 changed files with 148 additions and 34 deletions
+22 -22
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"github.com/distribution/reference"
"github.com/docker/compose/v2/pkg/progress"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
@@ -12,13 +11,28 @@ import (
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"slices"
"strings"
"sync"
"uncloud/internal/api"
"uncloud/internal/machine/api/pb"
"uncloud/internal/secret"
)
func (cli *Client) PrepareDeploymentSpec(ctx context.Context, spec api.ServiceSpec) (api.ServiceSpec, error) {
domain, err := cli.GetDomain(ctx)
if err != nil && !errors.Is(err, ErrNotFound) {
return spec, fmt.Errorf("get domain: %w", err)
}
// If the domain is not found (not reserved), an empty domain is used for the resolver.
resolver := NewServiceSpecResolver(domain)
if err = resolver.Resolve(&spec); err != nil {
return spec, err
}
return spec, nil
}
type RunServiceResponse struct {
ID string
Name string
@@ -31,26 +45,7 @@ func (cli *Client) RunService(ctx context.Context, spec api.ServiceSpec) (RunSer
return resp, fmt.Errorf("invalid service spec: %w", err)
}
img, err := reference.ParseDockerRef(spec.Container.Image)
if err != nil {
return resp, fmt.Errorf("invalid image: %w", err)
}
if spec.Name == "" {
// Generate a random service name from the image if not specified.
// Get the image name without the repository and tag/digest parts.
imageName := reference.FamiliarName(img)
// Get the last part of the image name (path), e.g. "nginx" from "bitnami/nginx".
if i := strings.LastIndex(imageName, "/"); i != -1 {
imageName = imageName[i+1:]
}
// Append a random suffix to the image name to generate an optimistically unique service name.
suffix, err := secret.RandomAlphaNumeric(4)
if err != nil {
return resp, fmt.Errorf("generate random suffix: %w", err)
}
spec.Name = fmt.Sprintf("%s-%s", imageName, suffix)
} else {
if spec.Name != "" {
// Optimistically check if a service with the specified name already exists.
_, err := cli.InspectService(ctx, spec.Name)
if err == nil {
@@ -61,6 +56,11 @@ func (cli *Client) RunService(ctx context.Context, spec api.ServiceSpec) (RunSer
}
}
var err error
if spec, err = cli.PrepareDeploymentSpec(ctx, spec); err != nil {
return resp, fmt.Errorf("prepare service spec ready for deployment: %w", err)
}
serviceID, err := secret.NewID()
if err != nil {
return resp, fmt.Errorf("generate service ID: %w", err)