package daemon import ( "cmp" "context" "fmt" "isle/bootstrap" "isle/nebula" "slices" "golang.org/x/exp/maps" ) // GetHostsResult wraps the results from the GetHosts RPC method. type GetHostsResult struct { Hosts []bootstrap.Host } // RemoveHostRequest contains the arguments to the RemoveHost RPC method. // // All fields are required. type RemoveHostRequest struct { HostName nebula.HostName } // CreateHostRequest contains the arguments to the // CreateHost RPC method. // // All fields are required. type CreateHostRequest struct { HostName nebula.HostName Opts CreateHostOpts } // CreateHostResult wraps the results from the CreateHost RPC method. type CreateHostResult struct { JoiningBootstrap JoiningBootstrap } // CreateNebulaCertificateRequest contains the arguments to the // CreateNebulaCertificate RPC method. // // All fields are required. type CreateNebulaCertificateRequest struct { HostName nebula.HostName HostEncryptingPublicKey nebula.EncryptingPublicKey } // CreateNebulaCertificateResult wraps the results from the // CreateNebulaCertificate RPC method. type CreateNebulaCertificateResult struct { HostNebulaCertifcate nebula.Certificate } // RPC exposes all RPC methods which are available to be called over the RPC // interface. type RPC interface { // CreateNetwork passes through to the Daemon method of the same name. // // name: Human-readable name of the network. // domain: Primary domain name that network services are served under. // ipNet: // 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. // hostName: The name of this first host in the network. CreateNetwork( ctx context.Context, name string, domain string, ipNet nebula.IPNet, hostName nebula.HostName, ) ( struct{}, error, ) // JoinNetwork passes through to the Daemon method of the same name. JoinNetwork( ctx context.Context, req JoiningBootstrap, ) ( struct{}, error, ) // GetHosts returns all hosts known to the network, sorted by their name. GetHosts(ctx context.Context) (GetHostsResult, error) // GetGarageClientParams passes the call through to the Daemon method of the // same name. GetGarageClientParams(ctx context.Context) (GarageClientParams, error) // GetNebulaCAPublicCredentials returns the CAPublicCredentials for the // network. GetNebulaCAPublicCredentials( ctx context.Context, ) ( nebula.CAPublicCredentials, error, ) // RemoveHost passes the call through to the Daemon method of the same name. RemoveHost( ctx context.Context, req RemoveHostRequest, ) ( struct{}, error, ) // CreateHost passes the call through to the Daemon method of the same name. CreateHost( ctx context.Context, req CreateHostRequest, ) ( CreateHostResult, error, ) // CreateNebulaCertificate passes the call through to the Daemon method of // the same name. CreateNebulaCertificate( ctx context.Context, req CreateNebulaCertificateRequest, ) ( CreateNebulaCertificateResult, error, ) } type rpcImpl struct { daemon Daemon } // NewRPC initializes and returns an RPC instance. func NewRPC(daemon Daemon) RPC { return &rpcImpl{daemon} } func (r *rpcImpl) CreateNetwork( ctx context.Context, name string, domain string, ipNet nebula.IPNet, hostName nebula.HostName, ) ( struct{}, error, ) { return struct{}{}, r.daemon.CreateNetwork( ctx, name, domain, ipNet, hostName, ) } func (r *rpcImpl) JoinNetwork( ctx context.Context, req JoiningBootstrap, ) ( struct{}, error, ) { return struct{}{}, r.daemon.JoinNetwork(ctx, req) } func (r *rpcImpl) GetHosts(ctx context.Context) (GetHostsResult, error) { b, err := r.daemon.GetBootstrap(ctx) if err != nil { return GetHostsResult{}, fmt.Errorf("retrieving bootstrap: %w", err) } hosts := maps.Values(b.Hosts) slices.SortFunc(hosts, func(a, b bootstrap.Host) int { return cmp.Compare(a.Name, b.Name) }) return GetHostsResult{hosts}, nil } func (r *rpcImpl) GetGarageClientParams( ctx context.Context, ) ( GarageClientParams, error, ) { return r.daemon.GetGarageClientParams(ctx) } func (r *rpcImpl) GetNebulaCAPublicCredentials( ctx context.Context, ) ( 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 } func (r *rpcImpl) RemoveHost( ctx context.Context, req RemoveHostRequest, ) ( struct{}, error, ) { return struct{}{}, r.daemon.RemoveHost(ctx, req.HostName) } func (r *rpcImpl) CreateHost( ctx context.Context, req CreateHostRequest, ) ( CreateHostResult, error, ) { joiningBootstrap, err := r.daemon.CreateHost( ctx, req.HostName, req.Opts, ) if err != nil { return CreateHostResult{}, err } return CreateHostResult{JoiningBootstrap: joiningBootstrap}, nil } func (r *rpcImpl) CreateNebulaCertificate( ctx context.Context, req CreateNebulaCertificateRequest, ) ( CreateNebulaCertificateResult, error, ) { cert, err := r.daemon.CreateNebulaCertificate( ctx, req.HostName, req.HostEncryptingPublicKey, ) if err != nil { return CreateNebulaCertificateResult{}, err } return CreateNebulaCertificateResult{ HostNebulaCertifcate: cert, }, nil }