2024-06-23 12:37:10 +00:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cmp"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2024-07-09 09:43:17 +00:00
|
|
|
"isle/admin"
|
2024-06-23 12:37:10 +00:00
|
|
|
"isle/bootstrap"
|
2024-07-12 13:30:21 +00:00
|
|
|
"isle/nebula"
|
2024-07-13 14:31:52 +00:00
|
|
|
"net/netip"
|
2024-06-23 12:37:10 +00:00
|
|
|
"slices"
|
|
|
|
|
|
|
|
"golang.org/x/exp/maps"
|
|
|
|
)
|
|
|
|
|
|
|
|
// RPC exposes all RPC methods which are available to be called over the RPC
|
|
|
|
// interface.
|
|
|
|
type RPC struct {
|
|
|
|
daemon Daemon
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRPC initializes and returns an RPC instance.
|
|
|
|
func NewRPC(daemon Daemon) *RPC {
|
|
|
|
return &RPC{daemon}
|
|
|
|
}
|
|
|
|
|
2024-07-09 09:43:17 +00:00
|
|
|
// CreateNetworkRequest contains the arguments to the CreateNetwork RPC method.
|
|
|
|
//
|
|
|
|
// All fields are required.
|
|
|
|
type CreateNetworkRequest struct {
|
|
|
|
// Human-readable name of the network.
|
|
|
|
Name string
|
|
|
|
|
|
|
|
// Primary domain name that network services are served under.
|
|
|
|
Domain string
|
|
|
|
|
2024-07-12 13:30:21 +00:00
|
|
|
// An IP subnet, in CIDR form, which will be the overall range of possible
|
|
|
|
// IPs in the network. The first IP in this network range will become this
|
|
|
|
// first host's IP.
|
|
|
|
IPNet nebula.IPNet
|
2024-07-09 09:43:17 +00:00
|
|
|
|
|
|
|
// The name of this first host in the network.
|
2024-07-12 13:30:21 +00:00
|
|
|
HostName nebula.HostName
|
2024-07-09 09:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateNetwork passes through to the Daemon method of the same name.
|
|
|
|
func (r *RPC) CreateNetwork(
|
|
|
|
ctx context.Context, req CreateNetworkRequest,
|
|
|
|
) (
|
|
|
|
admin.Admin, error,
|
|
|
|
) {
|
|
|
|
return r.daemon.CreateNetwork(
|
|
|
|
ctx, req.Name, req.Domain, req.IPNet, req.HostName,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-07-07 10:44:49 +00:00
|
|
|
// JoinNetwork passes through to the Daemon method of the same name.
|
|
|
|
func (r *RPC) JoinNetwork(
|
|
|
|
ctx context.Context, req bootstrap.Bootstrap,
|
|
|
|
) (
|
|
|
|
struct{}, error,
|
|
|
|
) {
|
|
|
|
return struct{}{}, r.daemon.JoinNetwork(ctx, req)
|
|
|
|
}
|
|
|
|
|
2024-07-09 09:43:17 +00:00
|
|
|
// GetHostsResult wraps the results from the GetHosts RPC method.
|
|
|
|
type GetHostsResult struct {
|
|
|
|
Hosts []bootstrap.Host
|
|
|
|
}
|
|
|
|
|
2024-07-06 13:36:48 +00:00
|
|
|
// GetHosts returns all hosts known to the network, sorted by their name.
|
2024-06-23 12:37:10 +00:00
|
|
|
func (r *RPC) GetHosts(
|
|
|
|
ctx context.Context, req struct{},
|
|
|
|
) (
|
|
|
|
GetHostsResult, error,
|
|
|
|
) {
|
2024-07-12 14:11:42 +00:00
|
|
|
b, err := r.daemon.GetBootstrap(ctx)
|
2024-06-23 12:37:10 +00:00
|
|
|
if err != nil {
|
2024-07-12 14:11:42 +00:00
|
|
|
return GetHostsResult{}, fmt.Errorf("retrieving bootstrap: %w", err)
|
2024-06-23 12:37:10 +00:00
|
|
|
}
|
|
|
|
|
2024-07-12 14:11:42 +00:00
|
|
|
hosts := maps.Values(b.Hosts)
|
2024-06-23 12:37:10 +00:00
|
|
|
slices.SortFunc(hosts, func(a, b bootstrap.Host) int {
|
|
|
|
return cmp.Compare(a.Name, b.Name)
|
|
|
|
})
|
|
|
|
|
|
|
|
return GetHostsResult{hosts}, nil
|
|
|
|
}
|
2024-07-12 14:03:37 +00:00
|
|
|
|
2024-07-13 12:34:06 +00:00
|
|
|
// GetGarageClientParams passes the call through to the Daemon method of the
|
|
|
|
// same name.
|
2024-07-12 14:03:37 +00:00
|
|
|
func (r *RPC) GetGarageClientParams(
|
|
|
|
ctx context.Context, req struct{},
|
|
|
|
) (
|
2024-07-13 12:34:06 +00:00
|
|
|
GarageClientParams, error,
|
2024-07-12 14:03:37 +00:00
|
|
|
) {
|
2024-07-13 12:34:06 +00:00
|
|
|
return r.daemon.GetGarageClientParams(ctx)
|
2024-07-12 14:11:42 +00:00
|
|
|
}
|
|
|
|
|
2024-07-12 15:05:39 +00:00
|
|
|
// GetNebulaCAPublicCredentials returns the CAPublicCredentials for the network.
|
2024-07-12 14:11:42 +00:00
|
|
|
func (r *RPC) GetNebulaCAPublicCredentials(
|
|
|
|
ctx context.Context, req struct{},
|
|
|
|
) (
|
|
|
|
nebula.CAPublicCredentials, error,
|
|
|
|
) {
|
|
|
|
b, err := r.daemon.GetBootstrap(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nebula.CAPublicCredentials{}, fmt.Errorf(
|
|
|
|
"retrieving bootstrap: %w", err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return b.CAPublicCredentials, nil
|
2024-07-12 14:03:37 +00:00
|
|
|
}
|
2024-07-12 15:05:39 +00:00
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
// RemoveHostRequest contains the arguments to the RemoveHost RPC method.
|
2024-07-12 15:05:39 +00:00
|
|
|
//
|
|
|
|
// All fields are required.
|
|
|
|
type RemoveHostRequest struct {
|
|
|
|
HostName nebula.HostName
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveHost passes the call through to the Daemon method of the same name.
|
|
|
|
func (r *RPC) RemoveHost(ctx context.Context, req RemoveHostRequest) (struct{}, error) {
|
|
|
|
return struct{}{}, r.daemon.RemoveHost(ctx, req.HostName)
|
|
|
|
}
|
2024-07-13 14:08:13 +00:00
|
|
|
|
2024-07-13 14:31:52 +00:00
|
|
|
// CreateHostRequest contains the arguments to the
|
|
|
|
// CreateHost RPC method.
|
|
|
|
//
|
|
|
|
// All fields are required.
|
|
|
|
type CreateHostRequest struct {
|
|
|
|
CASigningPrivateKey nebula.SigningPrivateKey // TODO load from secrets storage
|
|
|
|
HostName nebula.HostName
|
|
|
|
IP netip.Addr
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateHostResult wraps the results from the CreateHost RPC method.
|
|
|
|
type CreateHostResult struct {
|
|
|
|
HostBootstrap bootstrap.Bootstrap
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateHost passes the call through to the Daemon method of the
|
|
|
|
// same name.
|
|
|
|
func (r *RPC) CreateHost(
|
|
|
|
ctx context.Context, req CreateHostRequest,
|
|
|
|
) (
|
|
|
|
CreateHostResult, error,
|
|
|
|
) {
|
|
|
|
hostBootstrap, err := r.daemon.CreateHost(
|
|
|
|
ctx, req.CASigningPrivateKey, req.HostName, req.IP,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return CreateHostResult{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return CreateHostResult{HostBootstrap: hostBootstrap}, nil
|
|
|
|
}
|
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
// CreateNebulaCertificateRequest contains the arguments to the
|
|
|
|
// CreateNebulaCertificate RPC method.
|
|
|
|
//
|
|
|
|
// All fields are required.
|
|
|
|
type CreateNebulaCertificateRequest struct {
|
|
|
|
CASigningPrivateKey nebula.SigningPrivateKey // TODO load from secrets storage
|
|
|
|
HostName nebula.HostName
|
|
|
|
HostEncryptingPublicKey nebula.EncryptingPublicKey
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateNebulaCertificateResult wraps the results from the
|
|
|
|
// CreateNebulaCertificate RPC method.
|
|
|
|
type CreateNebulaCertificateResult struct {
|
|
|
|
HostNebulaCertifcate nebula.Certificate
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateNebulaCertificate passes the call through to the Daemon method of the
|
|
|
|
// same name.
|
|
|
|
func (r *RPC) CreateNebulaCertificate(
|
|
|
|
ctx context.Context, req CreateNebulaCertificateRequest,
|
|
|
|
) (
|
|
|
|
CreateNebulaCertificateResult, error,
|
|
|
|
) {
|
|
|
|
cert, err := r.daemon.CreateNebulaCertificate(
|
|
|
|
ctx, req.CASigningPrivateKey, req.HostName, req.HostEncryptingPublicKey,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return CreateNebulaCertificateResult{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return CreateNebulaCertificateResult{
|
|
|
|
HostNebulaCertifcate: cert,
|
|
|
|
}, nil
|
|
|
|
}
|