Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/uc/dns/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func NewRootCommand() *cobra.Command {
NewReleaseCommand(),
NewReserveCommand(),
NewShowCommand(),
NewSetCommand(),
)
return cmd
}
57 changes: 57 additions & 0 deletions cmd/uc/dns/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dns

import (
"context"
"errors"
"fmt"

"github.com/miekg/dns"
"github.com/psviderski/uncloud/internal/cli"
"github.com/psviderski/uncloud/internal/machine/api/pb"
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func NewSetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "set DOMAIN_NAME",
Args: cobra.ExactArgs(1),
Short: "Set a cluster domain directly in the cluster.",
Long: "Set a cluster domain directly in the cluster, bypassing Uncloud DNS. " +
"This assumes the DNS is externally set up.",
RunE: func(cmd *cobra.Command, args []string) error {
uncli := cmd.Context().Value("cli").(*cli.CLI)
return set(cmd.Context(), uncli, args[0])
},
}

return cmd
}

func set(ctx context.Context, uncli *cli.CLI, name string) error {
labels, ok := dns.IsDomainName(name)
if !ok || labels < 3 {
return fmt.Errorf("domain '%s' is not a valid name", name)
}

clusterClient, err := uncli.ConnectCluster(ctx)
if err != nil {
return fmt.Errorf("connect to cluster: %w", err)
}
defer clusterClient.Close()

domain, err := clusterClient.SetDomain(ctx, &pb.SetDomainRequest{Name: name})
if err != nil {
if status.Convert(err).Code() == codes.AlreadyExists {
return errors.New("domain already reserved")
}
return err
}

fmt.Printf("Set cluster domain: %s\n", domain.Name)

// No need to update anything as the domain records pointing to this cluster should be wildcard, so all
// names already exist.
return nil
}
253 changes: 160 additions & 93 deletions internal/machine/api/pb/cluster.pb.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions internal/machine/api/pb/cluster.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ service Cluster {
rpc RemoveMachine(RemoveMachineRequest) returns (google.protobuf.Empty);

rpc ReserveDomain(ReserveDomainRequest) returns (Domain);
rpc SetDomain(SetDomainRequest) returns (Domain);
rpc GetDomain(google.protobuf.Empty) returns (Domain);
rpc ReleaseDomain(google.protobuf.Empty) returns (Domain);
rpc CreateDomainRecords(CreateDomainRecordsRequest) returns (CreateDomainRecordsResponse);
Expand Down Expand Up @@ -62,6 +63,10 @@ message ReserveDomainRequest {
string endpoint = 1;
}

message SetDomainRequest {
string name = 1;
}

message CreateDomainRecordsRequest {
repeated DNSRecord records = 1;
}
Expand Down
38 changes: 38 additions & 0 deletions internal/machine/api/pb/cluster_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions internal/machine/cluster/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,35 @@ func (c *Cluster) ReleaseDomain(ctx context.Context, _ *emptypb.Empty) (*pb.Doma
return &pb.Domain{Name: domain.Name}, nil
}

func (c *Cluster) SetDomain(ctx context.Context, req *pb.SetDomainRequest) (*pb.Domain, error) {
if err := c.checkReady(); err != nil {
return nil, err
}

if _, err := c.storedDomain(ctx); err == nil {
return nil, status.Errorf(codes.AlreadyExists, "domain already reserved")
} else {
if s := status.Convert(err); s.Code() != codes.NotFound {
return nil, err
}
}

domain := uncloudDNSDomain{
Endpoint: "",
Name: req.Name,
Token: "",
}
domainJSON, err := json.Marshal(domain)
if err != nil {
return nil, status.Errorf(codes.Internal, "marshal set domain for store: %v", err)
}
if err = c.store.Put(ctx, uncloudDNSKey, domainJSON); err != nil {
return nil, status.Errorf(codes.Internal, "store set domain: %v", err)
}

return &pb.Domain{Name: req.Name}, nil
}

func (c *Cluster) CreateDomainRecords(
ctx context.Context, req *pb.CreateDomainRecordsRequest,
) (*pb.CreateDomainRecordsResponse, error) {
Expand All @@ -124,6 +153,10 @@ func (c *Cluster) CreateDomainRecords(
return nil, err
}

if domain.Endpoint == "" { // uc dns set has set a name
return &pb.CreateDomainRecordsResponse{}, nil
}

dnsClient := dns.NewClient()
recordsReq := make([]dns.RecordRequest, len(req.Records))
for i, r := range req.Records {
Expand Down
1 change: 1 addition & 0 deletions website/docs/9-cli-reference/uc_dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ DNS commands allow you to reserve or release a unique 'xxxxxx.uncld.dev' domain
* [uc](uc.md) - A CLI tool for managing Uncloud resources such as machines, services, and volumes.
* [uc dns release](uc_dns_release.md) - Release the reserved cluster domain.
* [uc dns reserve](uc_dns_reserve.md) - Reserve a cluster domain in Uncloud DNS.
* [uc dns set](uc_dns_set.md) - Set a cluster domain directly in the cluster.
* [uc dns show](uc_dns_show.md) - Print the cluster domain name.

31 changes: 31 additions & 0 deletions website/docs/9-cli-reference/uc_dns_set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# uc dns set

Set a cluster domain directly in the cluster.

## Synopsis

Set a cluster domain directly in the cluster, bypassing Uncloud DNS. This assumes the DNS is externally set up.

```
uc dns set DOMAIN_NAME [flags]
```

## Options

```
-h, --help help for set
```

## Options inherited from parent commands

```
--connect string Connect to a remote cluster machine without using the Uncloud configuration file. [$UNCLOUD_CONNECT]
Format: [ssh://]user@host[:port], ssh+go://user@host[:port], tcp://host:port, or unix:///path/to/uncloud.sock
-c, --context string Name of the cluster context to use (default is the current context). [$UNCLOUD_CONTEXT]
--uncloud-config string Path to the Uncloud configuration file. [$UNCLOUD_CONFIG] (default "~/.config/uncloud/config.yaml")
```

## See also

* [uc dns](uc_dns.md) - Manage cluster domain in Uncloud DNS.

Loading