Implement GetBootstrap to replace other redundant methods
This commit is contained in:
parent
54cebcad53
commit
df5ece950a
@ -3,7 +3,7 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"isle/nebula"
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"maps"
|
||||
"net/netip"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||
@ -110,33 +110,26 @@ func New(
|
||||
) (
|
||||
Bootstrap, error,
|
||||
) {
|
||||
hostPubCreds, hostPrivCreds, err := nebula.NewHostCredentials(
|
||||
caCreds, name, ip,
|
||||
)
|
||||
host, hostPrivCreds, err := NewHost(caCreds, name, ip)
|
||||
if err != nil {
|
||||
return Bootstrap{}, fmt.Errorf("generating host credentials: %w", err)
|
||||
return Bootstrap{}, fmt.Errorf("creating host: %w", err)
|
||||
}
|
||||
|
||||
assigned := HostAssigned{
|
||||
Name: name,
|
||||
PublicCredentials: hostPubCreds,
|
||||
}
|
||||
|
||||
signedAssigned, err := nebula.Sign(assigned, caCreds.SigningPrivateKey)
|
||||
signedAssigned, err := nebula.Sign(
|
||||
host.HostAssigned, caCreds.SigningPrivateKey,
|
||||
)
|
||||
if err != nil {
|
||||
return Bootstrap{}, fmt.Errorf("signing assigned fields: %w", err)
|
||||
}
|
||||
|
||||
existingHosts = maps.Clone(existingHosts)
|
||||
existingHosts[name] = Host{
|
||||
HostAssigned: assigned,
|
||||
}
|
||||
existingHosts[name] = host
|
||||
|
||||
return Bootstrap{
|
||||
NetworkCreationParams: adminCreationParams,
|
||||
CAPublicCredentials: caCreds.Public,
|
||||
PrivateCredentials: hostPrivCreds,
|
||||
HostAssigned: assigned,
|
||||
HostAssigned: host.HostAssigned,
|
||||
SignedHostAssigned: signedAssigned,
|
||||
Hosts: existingHosts,
|
||||
}, nil
|
||||
@ -150,15 +143,19 @@ func (b *Bootstrap) UnmarshalJSON(data []byte) error {
|
||||
|
||||
err := json.Unmarshal(data, (*inner)(b))
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("json unmarshaling: %w", err)
|
||||
}
|
||||
|
||||
// Generally this will be filled, but during unit tests we sometimes leave
|
||||
// it empty for convenience.
|
||||
if b.SignedHostAssigned != nil {
|
||||
b.HostAssigned, err = b.SignedHostAssigned.Unwrap(
|
||||
b.CAPublicCredentials.SigningKey,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unwrapping HostAssigned: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -174,22 +171,16 @@ func (b Bootstrap) ThisHost() Host {
|
||||
return host
|
||||
}
|
||||
|
||||
// Hash returns a deterministic hash of the given hosts map.
|
||||
func HostsHash(hostsMap map[nebula.HostName]Host) ([]byte, error) {
|
||||
|
||||
hosts := make([]Host, 0, len(hostsMap))
|
||||
for _, host := range hostsMap {
|
||||
// HostsOrdered returns the Hosts as a slice in a deterministic order.
|
||||
func (b Bootstrap) HostsOrdered() []Host {
|
||||
hosts := make([]Host, 0, len(b.Hosts))
|
||||
for _, host := range b.Hosts {
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
|
||||
sort.Slice(hosts, func(i, j int) bool {
|
||||
return hosts[i].Name < hosts[j].Name
|
||||
slices.SortFunc(hosts, func(a, b Host) int {
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
|
||||
h := sha512.New()
|
||||
if err := json.NewEncoder(h).Encode(hosts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
return hosts
|
||||
}
|
||||
|
@ -73,6 +73,31 @@ type Host struct {
|
||||
HostConfigured
|
||||
}
|
||||
|
||||
// NewHost creates a Host instance using the given assigned fields, along with
|
||||
// the HostPrivateCredentials which its PublicCredentials field.
|
||||
func NewHost(
|
||||
caCreds nebula.CACredentials, name nebula.HostName, ip netip.Addr,
|
||||
) (
|
||||
host Host, hostPrivCreds nebula.HostPrivateCredentials, err error,
|
||||
) {
|
||||
hostPubCreds, hostPrivCreds, err := nebula.NewHostCredentials(
|
||||
caCreds, name, ip,
|
||||
)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("generating host credentials: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
host = Host{
|
||||
HostAssigned: HostAssigned{
|
||||
Name: name,
|
||||
PublicCredentials: hostPubCreds,
|
||||
},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IP returns the IP address encoded in the Host's nebula certificate, or panics
|
||||
// if there is an error.
|
||||
//
|
||||
|
@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"isle/bootstrap"
|
||||
)
|
||||
|
||||
func (ctx subCmdCtx) getHosts() ([]bootstrap.Host, error) {
|
||||
return ctx.getDaemonRPC().GetHosts(ctx)
|
||||
}
|
@ -4,10 +4,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"isle/bootstrap"
|
||||
"isle/daemon/network"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
var subCmdHostCreate = subCmd{
|
||||
@ -65,35 +63,48 @@ var subCmdHostList = subCmd{
|
||||
return nil, fmt.Errorf("parsing flags: %w", err)
|
||||
}
|
||||
|
||||
hostsRes, err := ctx.getHosts()
|
||||
currBoostrap, err := ctx.getDaemonRPC().GetBootstrap(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calling GetHosts: %w", err)
|
||||
return nil, fmt.Errorf("calling GetBootstrap: %w", err)
|
||||
}
|
||||
|
||||
type host struct {
|
||||
Name string
|
||||
hosts := currBoostrap.HostsOrdered()
|
||||
|
||||
type storageInstanceView struct {
|
||||
ID string `yaml:"id"`
|
||||
RPCPort int `yaml:"rpc_port"`
|
||||
S3APIPort int `yaml:"s3_api_port"`
|
||||
}
|
||||
|
||||
type hostView struct {
|
||||
Name string `yaml:"name"`
|
||||
VPN struct {
|
||||
IP string
|
||||
IP string `yaml:"ip"`
|
||||
PublicAddr string `yaml:"public_addr,omitempty"`
|
||||
}
|
||||
Storage bootstrap.GarageHost `json:",omitempty"`
|
||||
Storage struct {
|
||||
Instances []storageInstanceView `yaml:"instances"`
|
||||
} `yaml:",omitempty"`
|
||||
}
|
||||
|
||||
hosts := make([]host, 0, len(hostsRes))
|
||||
for _, h := range hostsRes {
|
||||
|
||||
host := host{
|
||||
Name: string(h.Name),
|
||||
Storage: h.Garage,
|
||||
hostViews := make([]hostView, len(hosts))
|
||||
for i, host := range hosts {
|
||||
storageInstanceViews := make([]storageInstanceView, len(host.Garage.Instances))
|
||||
for i := range host.Garage.Instances {
|
||||
storageInstanceViews[i] = storageInstanceView(host.Garage.Instances[i])
|
||||
}
|
||||
|
||||
host.VPN.IP = h.IP().String()
|
||||
|
||||
hosts = append(hosts, host)
|
||||
hostView := hostView{
|
||||
Name: string(host.Name),
|
||||
}
|
||||
|
||||
sort.Slice(hosts, func(i, j int) bool { return hosts[i].Name < hosts[j].Name })
|
||||
hostView.VPN.IP = host.IP().String()
|
||||
hostView.VPN.PublicAddr = host.Nebula.PublicAddr
|
||||
hostView.Storage.Instances = storageInstanceViews
|
||||
hostViews[i] = hostView
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
return hostViews, nil
|
||||
}),
|
||||
}
|
||||
|
||||
|
134
go/cmd/entrypoint/host_test.go
Normal file
134
go/cmd/entrypoint/host_test.go
Normal file
@ -0,0 +1,134 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"isle/bootstrap"
|
||||
"isle/nebula"
|
||||
"isle/toolkit"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHostList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var ipNet nebula.IPNet
|
||||
require.NoError(t, ipNet.UnmarshalText([]byte("172.16.0.0/16")))
|
||||
|
||||
caCreds, err := nebula.NewCACredentials("test.com", ipNet)
|
||||
require.NoError(t, err)
|
||||
|
||||
type host struct {
|
||||
name string
|
||||
ip string
|
||||
publicAddr string
|
||||
storageInstances []bootstrap.GarageHostInstance
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
hosts []host
|
||||
want any
|
||||
}{
|
||||
{
|
||||
name: "no hosts",
|
||||
want: []any{},
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
hosts: []host{
|
||||
{
|
||||
name: "a",
|
||||
ip: "172.16.0.1",
|
||||
},
|
||||
},
|
||||
want: []map[string]any{
|
||||
{
|
||||
"name": "a",
|
||||
"vpn": map[string]any{
|
||||
"ip": "172.16.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple",
|
||||
hosts: []host{
|
||||
{
|
||||
name: "a",
|
||||
ip: "172.16.0.1",
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
ip: "172.16.0.2",
|
||||
publicAddr: "1.1.1.1:80",
|
||||
storageInstances: []bootstrap.GarageHostInstance{{
|
||||
ID: "storageInstanceID",
|
||||
RPCPort: 9000,
|
||||
S3APIPort: 9001,
|
||||
}},
|
||||
},
|
||||
},
|
||||
want: []map[string]any{
|
||||
{
|
||||
"name": "a",
|
||||
"vpn": map[string]any{
|
||||
"ip": "172.16.0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"vpn": map[string]any{
|
||||
"ip": "172.16.0.2",
|
||||
"public_addr": "1.1.1.1:80",
|
||||
},
|
||||
"storage": map[string]any{
|
||||
"instances": []any{
|
||||
map[string]any{
|
||||
"id": "storageInstanceID",
|
||||
"rpc_port": 9000,
|
||||
"s3_api_port": 9001,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var (
|
||||
h = newRunHarness(t)
|
||||
hosts = map[nebula.HostName]bootstrap.Host{}
|
||||
)
|
||||
|
||||
for _, testHost := range test.hosts {
|
||||
var (
|
||||
hostName nebula.HostName
|
||||
ip = netip.MustParseAddr(testHost.ip)
|
||||
)
|
||||
require.NoError(
|
||||
t, hostName.UnmarshalText([]byte(testHost.name)),
|
||||
)
|
||||
|
||||
host, _, err := bootstrap.NewHost(caCreds, hostName, ip)
|
||||
require.NoError(t, err)
|
||||
|
||||
host.Nebula.PublicAddr = testHost.publicAddr
|
||||
host.Garage.Instances = testHost.storageInstances
|
||||
|
||||
hosts[hostName] = host
|
||||
}
|
||||
|
||||
h.daemonRPC.
|
||||
On("GetBootstrap", toolkit.MockArg[context.Context]()).
|
||||
Return(bootstrap.Bootstrap{Hosts: hosts}, nil).
|
||||
Once()
|
||||
|
||||
h.runAssertStdout(t, test.want, "host", "list")
|
||||
})
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"isle/daemon"
|
||||
"isle/daemon/jsonrpc2"
|
||||
"isle/toolkit"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -16,8 +18,9 @@ import (
|
||||
type runHarness struct {
|
||||
ctx context.Context
|
||||
logger *mlog.Logger
|
||||
daemonRPC *daemon.MockRPC
|
||||
stdout *bytes.Buffer
|
||||
daemonRPC *daemon.MockRPC
|
||||
daemonRPCServer *httptest.Server
|
||||
}
|
||||
|
||||
func newRunHarness(t *testing.T) *runHarness {
|
||||
@ -26,17 +29,33 @@ func newRunHarness(t *testing.T) *runHarness {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
logger = toolkit.NewTestLogger(t)
|
||||
daemonRPC = daemon.NewMockRPC(t)
|
||||
stdout = new(bytes.Buffer)
|
||||
|
||||
daemonRPC = daemon.NewMockRPC(t)
|
||||
daemonRPCHandler = jsonrpc2.NewHTTPHandler(daemon.NewRPCHandler(
|
||||
logger.WithNamespace("rpc"), daemonRPC,
|
||||
))
|
||||
daemonRPCServer = httptest.NewServer(daemonRPCHandler)
|
||||
)
|
||||
|
||||
return &runHarness{ctx, logger, daemonRPC, stdout}
|
||||
t.Cleanup(daemonRPCServer.Close)
|
||||
|
||||
return &runHarness{ctx, logger, stdout, daemonRPC, daemonRPCServer}
|
||||
}
|
||||
|
||||
func (h *runHarness) run(_ *testing.T, args ...string) error {
|
||||
func (h *runHarness) run(t *testing.T, args ...string) error {
|
||||
httpClient := toolkit.NewHTTPClient(h.logger.WithNamespace("http"))
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, httpClient.Close())
|
||||
})
|
||||
|
||||
daemonRPCClient := daemon.RPCFromClient(
|
||||
jsonrpc2.NewHTTPClient(httpClient, h.daemonRPCServer.URL),
|
||||
)
|
||||
|
||||
return doRootCmd(h.ctx, h.logger, &subCmdCtxOpts{
|
||||
args: args,
|
||||
daemonRPC: h.daemonRPC,
|
||||
daemonRPC: daemonRPCClient,
|
||||
stdout: h.stdout,
|
||||
})
|
||||
}
|
||||
|
@ -72,15 +72,15 @@ var subCmdNebulaShow = subCmd{
|
||||
return nil, fmt.Errorf("parsing flags: %w", err)
|
||||
}
|
||||
|
||||
hosts, err := ctx.getHosts()
|
||||
currBoostrap, err := ctx.getDaemonRPC().GetBootstrap(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting hosts: %w", err)
|
||||
return nil, fmt.Errorf("calling GetBootstrap: %w", err)
|
||||
}
|
||||
|
||||
caPublicCreds, err := ctx.getDaemonRPC().GetNebulaCAPublicCredentials(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err)
|
||||
}
|
||||
var (
|
||||
hosts = currBoostrap.HostsOrdered()
|
||||
caPublicCreds = currBoostrap.CAPublicCredentials
|
||||
)
|
||||
|
||||
caCert := caPublicCreds.Cert
|
||||
caCertDetails := caCert.Unwrap().Details
|
||||
|
@ -60,6 +60,15 @@ func (c *rpcClient) CreateNetwork(ctx context.Context, name string, domain strin
|
||||
return
|
||||
}
|
||||
|
||||
func (c *rpcClient) GetBootstrap(ctx context.Context) (b1 bootstrap.Bootstrap, err error) {
|
||||
err = c.client.Call(
|
||||
ctx,
|
||||
&b1,
|
||||
"GetBootstrap",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *rpcClient) GetConfig(ctx context.Context) (n1 daecommon.NetworkConfig, err error) {
|
||||
err = c.client.Call(
|
||||
ctx,
|
||||
@ -78,24 +87,6 @@ func (c *rpcClient) GetGarageClientParams(ctx context.Context) (g1 network.Garag
|
||||
return
|
||||
}
|
||||
|
||||
func (c *rpcClient) GetHosts(ctx context.Context) (ha1 []bootstrap.Host, err error) {
|
||||
err = c.client.Call(
|
||||
ctx,
|
||||
&ha1,
|
||||
"GetHosts",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *rpcClient) GetNebulaCAPublicCredentials(ctx context.Context) (c2 nebula.CAPublicCredentials, err error) {
|
||||
err = c.client.Call(
|
||||
ctx,
|
||||
&c2,
|
||||
"GetNebulaCAPublicCredentials",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *rpcClient) GetNetworks(ctx context.Context) (ca1 []bootstrap.CreationParams, err error) {
|
||||
err = c.client.Call(
|
||||
ctx,
|
||||
|
@ -242,13 +242,21 @@ func (d *Daemon) GetNetworks(
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetHost implements the method for the network.RPC interface.
|
||||
func (d *Daemon) GetHosts(ctx context.Context) ([]bootstrap.Host, error) {
|
||||
// GetBootstrap implements the method for the network.RPC interface.
|
||||
func (d *Daemon) GetBootstrap(
|
||||
ctx context.Context,
|
||||
) (
|
||||
bootstrap.Bootstrap, error,
|
||||
) {
|
||||
return withNetwork(
|
||||
ctx,
|
||||
d,
|
||||
func(ctx context.Context, n joinedNetwork) ([]bootstrap.Host, error) {
|
||||
return n.GetHosts(ctx)
|
||||
func(
|
||||
ctx context.Context, n joinedNetwork,
|
||||
) (
|
||||
bootstrap.Bootstrap, error,
|
||||
) {
|
||||
return n.GetBootstrap(ctx)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -272,26 +280,6 @@ func (d *Daemon) GetGarageClientParams(
|
||||
)
|
||||
}
|
||||
|
||||
// GetNebulaCAPublicCredentials implements the method for the network.RPC
|
||||
// interface.
|
||||
func (d *Daemon) GetNebulaCAPublicCredentials(
|
||||
ctx context.Context,
|
||||
) (
|
||||
nebula.CAPublicCredentials, error,
|
||||
) {
|
||||
return withNetwork(
|
||||
ctx,
|
||||
d,
|
||||
func(
|
||||
ctx context.Context, n joinedNetwork,
|
||||
) (
|
||||
nebula.CAPublicCredentials, error,
|
||||
) {
|
||||
return n.GetNebulaCAPublicCredentials(ctx)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// RemoveHost implements the method for the network.RPC interface.
|
||||
func (d *Daemon) RemoveHost(ctx context.Context, hostName nebula.HostName) error {
|
||||
_, err := withNetwork(
|
||||
|
@ -3,6 +3,7 @@ package jsonrpc2
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@ -50,7 +51,9 @@ func (h httpHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch rpcErr.Code {
|
||||
case 0: // no error
|
||||
_ = encodeResponse(enc, req.ID, res)
|
||||
if err := encodeResponse(enc, req.ID, res); err != nil {
|
||||
panic(fmt.Errorf("encoding response %#v: %w", res, err))
|
||||
}
|
||||
return
|
||||
|
||||
case errCodeMethodNotFound:
|
||||
@ -63,5 +66,7 @@ func (h httpHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
|
||||
_ = encodeErrorResponse(enc, req.ID, rpcErr)
|
||||
if err := encodeErrorResponse(enc, req.ID, rpcErr); err != nil {
|
||||
panic(fmt.Errorf("encoding error %+v: %w", rpcErr, err))
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package network
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
@ -21,13 +20,11 @@ import (
|
||||
"isle/secrets"
|
||||
"isle/toolkit"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// GarageClientParams contains all the data needed to instantiate garage
|
||||
@ -75,21 +72,14 @@ type JoiningBootstrap struct {
|
||||
// RPC defines the methods related to a single network which are available over
|
||||
// the daemon's RPC interface.
|
||||
type RPC interface {
|
||||
// GetHosts returns all hosts known to the network, sorted by their name.
|
||||
GetHosts(context.Context) ([]bootstrap.Host, error)
|
||||
// GetBootstrap returns the currently active Bootstrap for the Network. The
|
||||
// PrivateCredentials field will be zero'd out before being returned.
|
||||
GetBootstrap(context.Context) (bootstrap.Bootstrap, error)
|
||||
|
||||
// GetGarageClientParams returns a GarageClientParams for the current
|
||||
// network state.
|
||||
GetGarageClientParams(context.Context) (GarageClientParams, error)
|
||||
|
||||
// GetNebulaCAPublicCredentials returns the CAPublicCredentials for the
|
||||
// network.
|
||||
GetNebulaCAPublicCredentials(
|
||||
context.Context,
|
||||
) (
|
||||
nebula.CAPublicCredentials, error,
|
||||
)
|
||||
|
||||
// RemoveHost removes the host of the given name from the network.
|
||||
RemoveHost(ctx context.Context, hostName nebula.HostName) error
|
||||
|
||||
@ -750,17 +740,18 @@ func (n *network) getBootstrap() (
|
||||
})
|
||||
}
|
||||
|
||||
func (n *network) GetHosts(ctx context.Context) ([]bootstrap.Host, error) {
|
||||
func (n *network) GetBootstrap(
|
||||
ctx context.Context,
|
||||
) (
|
||||
bootstrap.Bootstrap, error,
|
||||
) {
|
||||
return withCurrBootstrap(n, func(
|
||||
currBootstrap bootstrap.Bootstrap,
|
||||
) (
|
||||
[]bootstrap.Host, error,
|
||||
bootstrap.Bootstrap, error,
|
||||
) {
|
||||
hosts := maps.Values(currBootstrap.Hosts)
|
||||
slices.SortFunc(hosts, func(a, b bootstrap.Host) int {
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
return hosts, nil
|
||||
currBootstrap.PrivateCredentials = nebula.HostPrivateCredentials{}
|
||||
return currBootstrap, nil
|
||||
})
|
||||
}
|
||||
|
||||
@ -778,21 +769,6 @@ func (n *network) GetGarageClientParams(
|
||||
})
|
||||
}
|
||||
|
||||
func (n *network) GetNebulaCAPublicCredentials(
|
||||
ctx context.Context,
|
||||
) (
|
||||
nebula.CAPublicCredentials, error,
|
||||
) {
|
||||
b, err := n.getBootstrap()
|
||||
if err != nil {
|
||||
return nebula.CAPublicCredentials{}, fmt.Errorf(
|
||||
"retrieving bootstrap: %w", err,
|
||||
)
|
||||
}
|
||||
|
||||
return b.CAPublicCredentials, nil
|
||||
}
|
||||
|
||||
func (n *network) RemoveHost(ctx context.Context, hostName nebula.HostName) error {
|
||||
// TODO RemoveHost should publish a certificate revocation for the host
|
||||
// being removed.
|
||||
|
@ -85,6 +85,19 @@ func TestJoin(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetwork_GetBootstrap(t *testing.T) {
|
||||
var (
|
||||
h = newIntegrationHarness(t)
|
||||
network = h.createNetwork(t, "primus", nil)
|
||||
)
|
||||
|
||||
currBootstrap, err := network.GetBootstrap(h.ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(
|
||||
t, nebula.HostPrivateCredentials{}, currBootstrap.PrivateCredentials,
|
||||
)
|
||||
}
|
||||
|
||||
func TestNetwork_SetConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -364,13 +364,7 @@ func (nh *integrationHarnessNetwork) garageAdminClient(
|
||||
func (nh *integrationHarnessNetwork) getHostsByName(
|
||||
t *testing.T,
|
||||
) map[nebula.HostName]bootstrap.Host {
|
||||
hosts, err := nh.Network.GetHosts(nh.ctx)
|
||||
currBootstrap, err := nh.Network.GetBootstrap(nh.ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
hostsByName := map[nebula.HostName]bootstrap.Host{}
|
||||
for _, h := range hosts {
|
||||
hostsByName[h.Name] = h
|
||||
}
|
||||
|
||||
return hostsByName
|
||||
return currBootstrap.Hosts
|
||||
}
|
||||
|
@ -74,6 +74,34 @@ func (_m *MockNetwork) CreateNebulaCertificate(_a0 context.Context, _a1 nebula.H
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetBootstrap provides a mock function with given fields: _a0
|
||||
func (_m *MockNetwork) GetBootstrap(_a0 context.Context) (bootstrap.Bootstrap, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetBootstrap")
|
||||
}
|
||||
|
||||
var r0 bootstrap.Bootstrap
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (bootstrap.Bootstrap, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) bootstrap.Bootstrap); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bootstrap.Bootstrap)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetConfig provides a mock function with given fields: _a0
|
||||
func (_m *MockNetwork) GetConfig(_a0 context.Context) (daecommon.NetworkConfig, error) {
|
||||
ret := _m.Called(_a0)
|
||||
@ -130,64 +158,6 @@ func (_m *MockNetwork) GetGarageClientParams(_a0 context.Context) (GarageClientP
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetHosts provides a mock function with given fields: _a0
|
||||
func (_m *MockNetwork) GetHosts(_a0 context.Context) ([]bootstrap.Host, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetHosts")
|
||||
}
|
||||
|
||||
var r0 []bootstrap.Host
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) ([]bootstrap.Host, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []bootstrap.Host); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]bootstrap.Host)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetNebulaCAPublicCredentials provides a mock function with given fields: _a0
|
||||
func (_m *MockNetwork) GetNebulaCAPublicCredentials(_a0 context.Context) (nebula.CAPublicCredentials, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetNebulaCAPublicCredentials")
|
||||
}
|
||||
|
||||
var r0 nebula.CAPublicCredentials
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (nebula.CAPublicCredentials, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) nebula.CAPublicCredentials); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(nebula.CAPublicCredentials)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetNetworkCreationParams provides a mock function with given fields: _a0
|
||||
func (_m *MockNetwork) GetNetworkCreationParams(_a0 context.Context) (bootstrap.CreationParams, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"isle/daemon/network"
|
||||
"isle/nebula"
|
||||
"net/http"
|
||||
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||
)
|
||||
|
||||
// RPC defines the methods which the Daemon exposes over RPC (via the RPCHandler
|
||||
@ -53,12 +55,13 @@ type RPC interface {
|
||||
network.RPC
|
||||
}
|
||||
|
||||
// RPCHandler returns a jsonrpc2.Handler which will use the Daemon to serve all
|
||||
// methods defined on the RPC interface.
|
||||
func (d *Daemon) RPCHandler() jsonrpc2.Handler {
|
||||
rpc := RPC(d)
|
||||
// NewRPCHandler returns a jsonrpc2.Handler which will use the given RPC to
|
||||
// serve all methods defined on the interface.
|
||||
func NewRPCHandler(
|
||||
logger *mlog.Logger, rpc RPC,
|
||||
) jsonrpc2.Handler {
|
||||
return jsonrpc2.Chain(
|
||||
jsonrpc2.NewMLogMiddleware(d.logger.WithNamespace("rpc")),
|
||||
jsonrpc2.NewMLogMiddleware(logger),
|
||||
jsonrpc2.ExposeServerSideErrorsMiddleware,
|
||||
)(
|
||||
jsonrpc2.NewDispatchHandler(&rpc),
|
||||
@ -68,5 +71,6 @@ func (d *Daemon) RPCHandler() jsonrpc2.Handler {
|
||||
// HTTPRPCHandler returns an http.Handler which will use the Daemon to serve all
|
||||
// methods defined on the RPC interface via the JSONRPC2 protocol.
|
||||
func (d *Daemon) HTTPRPCHandler() http.Handler {
|
||||
return jsonrpc2.NewHTTPHandler(d.RPCHandler())
|
||||
handler := NewRPCHandler(d.logger.WithNamespace("rpc"), d)
|
||||
return jsonrpc2.NewHTTPHandler(handler)
|
||||
}
|
||||
|
@ -94,6 +94,34 @@ func (_m *MockRPC) CreateNetwork(ctx context.Context, name string, domain string
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetBootstrap provides a mock function with given fields: _a0
|
||||
func (_m *MockRPC) GetBootstrap(_a0 context.Context) (bootstrap.Bootstrap, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetBootstrap")
|
||||
}
|
||||
|
||||
var r0 bootstrap.Bootstrap
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (bootstrap.Bootstrap, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) bootstrap.Bootstrap); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bootstrap.Bootstrap)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetConfig provides a mock function with given fields: _a0
|
||||
func (_m *MockRPC) GetConfig(_a0 context.Context) (daecommon.NetworkConfig, error) {
|
||||
ret := _m.Called(_a0)
|
||||
@ -150,64 +178,6 @@ func (_m *MockRPC) GetGarageClientParams(_a0 context.Context) (network.GarageCli
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetHosts provides a mock function with given fields: _a0
|
||||
func (_m *MockRPC) GetHosts(_a0 context.Context) ([]bootstrap.Host, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetHosts")
|
||||
}
|
||||
|
||||
var r0 []bootstrap.Host
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) ([]bootstrap.Host, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []bootstrap.Host); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]bootstrap.Host)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetNebulaCAPublicCredentials provides a mock function with given fields: _a0
|
||||
func (_m *MockRPC) GetNebulaCAPublicCredentials(_a0 context.Context) (nebula.CAPublicCredentials, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetNebulaCAPublicCredentials")
|
||||
}
|
||||
|
||||
var r0 nebula.CAPublicCredentials
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (nebula.CAPublicCredentials, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) nebula.CAPublicCredentials); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(nebula.CAPublicCredentials)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetNetworks provides a mock function with given fields: _a0
|
||||
func (_m *MockRPC) GetNetworks(_a0 context.Context) ([]bootstrap.CreationParams, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
Loading…
Reference in New Issue
Block a user