Implement RPC socket and use it to list hosts
This commit is contained in:
parent
47e53dffb7
commit
c3609252a5
@ -69,7 +69,7 @@ in rec {
|
||||
'';
|
||||
};
|
||||
|
||||
vendorHash = "sha256-heXFvEea3u3zvdUvVxlI+FTxqEeImoXd1sqdJJTASoc=";
|
||||
vendorHash = "sha256-fBCwaZLusixNnD1QG0XtDe/NpNvonI7wBhqWbRrLFAg=";
|
||||
|
||||
subPackages = [
|
||||
"./cmd/entrypoint"
|
||||
|
@ -78,5 +78,5 @@ type Host struct {
|
||||
// This assumes that the Host and its data has already been verified against the
|
||||
// CA signing key.
|
||||
func (h Host) IP() net.IP {
|
||||
return h.PublicCredentials.Cert.Details.Ips[0].IP
|
||||
return h.PublicCredentials.Cert.Unwrap().Details.Ips[0].IP
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ var subCmdAdminCreateNebulaCert = subCmd{
|
||||
return fmt.Errorf("creating cert: %w", err)
|
||||
}
|
||||
|
||||
nebulaHostCertPEM, err := nebulaHostCert.MarshalToPEM()
|
||||
nebulaHostCertPEM, err := nebulaHostCert.Unwrap().MarshalToPEM()
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshaling cert to PEM: %w", err)
|
||||
}
|
||||
|
@ -115,6 +115,23 @@ func runDaemonPmuxOnce(
|
||||
}
|
||||
}()
|
||||
|
||||
{
|
||||
logger := logger.WithNamespace("http")
|
||||
httpSrv, err := newHTTPServer(
|
||||
ctx, logger, daemon.NewRPC(daemonInst),
|
||||
)
|
||||
if err != nil {
|
||||
return bootstrap.Bootstrap{}, fmt.Errorf("starting HTTP server: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
// see comment in daemonInst shutdown logic regarding background
|
||||
// context.
|
||||
if err := httpSrv.Shutdown(context.Background()); err != nil {
|
||||
logger.Error(ctx, "Failed to cleanly shutdown http server", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(3 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
@ -1,10 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"isle/bootstrap"
|
||||
"isle/daemon"
|
||||
"isle/daemon/jsonrpc2"
|
||||
"isle/garage/garagesrv"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||
)
|
||||
|
||||
func coalesceDaemonConfigAndBootstrap(
|
||||
@ -50,3 +58,41 @@ func coalesceDaemonConfigAndBootstrap(
|
||||
|
||||
return hostBootstrap, nil
|
||||
}
|
||||
|
||||
const daemonHTTPRPCPath = "/rpc/v0.json"
|
||||
|
||||
func newHTTPServer(
|
||||
ctx context.Context, logger *mlog.Logger, rpc *daemon.RPC,
|
||||
) (
|
||||
*http.Server, error,
|
||||
) {
|
||||
l, err := net.Listen("unix", envSocketPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to listen on socket %q: %w", envSocketPath, err,
|
||||
)
|
||||
}
|
||||
|
||||
ctx = mctx.Annotate(ctx, "httpAddr", l.Addr().String())
|
||||
logger.Info(ctx, "HTTP server socket created")
|
||||
|
||||
rpcHandler := jsonrpc2.Chain(
|
||||
jsonrpc2.NewMLogMiddleware(logger.WithNamespace("rpc")),
|
||||
jsonrpc2.ExposeServerSideErrorsMiddleware,
|
||||
)(
|
||||
jsonrpc2.NewDispatchHandler(&rpc),
|
||||
)
|
||||
|
||||
httpMux := http.NewServeMux()
|
||||
httpMux.Handle(daemonHTTPRPCPath, jsonrpc2.NewHTTPHandler(rpcHandler))
|
||||
|
||||
srv := &http.Server{Handler: httpMux}
|
||||
|
||||
go func() {
|
||||
if err := srv.Serve(l); !errors.Is(err, http.ErrServerClosed) {
|
||||
logger.Fatal(ctx, "HTTP server unexpectedly shut down", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"isle/bootstrap"
|
||||
"isle/daemon"
|
||||
"isle/jsonutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||
)
|
||||
|
||||
var hostNameRegexp = regexp.MustCompile(`^[a-z][a-z0-9\-]*$`)
|
||||
@ -26,37 +26,19 @@ func validateHostName(name string) error {
|
||||
var subCmdHostsList = subCmd{
|
||||
name: "list",
|
||||
descr: "Lists all hosts in the network, and their IPs",
|
||||
checkLock: true,
|
||||
do: func(subCmdCtx subCmdCtx) error {
|
||||
|
||||
flags := subCmdCtx.flagSet(false)
|
||||
|
||||
logLevelStr := flags.StringP(
|
||||
"log-level", "l", "info",
|
||||
`Maximum log level which should be output. Values can be "debug", "info", "warn", "error", "fatal". Does not apply to sub-processes`,
|
||||
)
|
||||
|
||||
if err := flags.Parse(subCmdCtx.args); err != nil {
|
||||
return fmt.Errorf("parsing flags: %w", err)
|
||||
}
|
||||
|
||||
ctx := subCmdCtx.ctx
|
||||
|
||||
logLevel := mlog.LevelFromString(*logLevelStr)
|
||||
if logLevel == nil {
|
||||
return fmt.Errorf("couldn't parse log level %q", *logLevelStr)
|
||||
var resRaw json.RawMessage
|
||||
err := subCmdCtx.daemonRCPClient.Call(ctx, &resRaw, "GetHosts", nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("calling GetHosts: %w", err)
|
||||
}
|
||||
|
||||
logger := subCmdCtx.logger.WithMaxLevel(logLevel.Int())
|
||||
|
||||
hostBootstrap, err := loadHostBootstrap()
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||
}
|
||||
|
||||
hostsMap, err := hostBootstrap.GetGarageBootstrapHosts(ctx, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("retrieving hosts from garage: %w", err)
|
||||
var res daemon.GetHostsResult
|
||||
if err := json.Unmarshal(resRaw, &res); err != nil {
|
||||
return fmt.Errorf("unmarshaling %s into %T: %w", string(resRaw), res, err)
|
||||
}
|
||||
|
||||
type host struct {
|
||||
@ -67,8 +49,8 @@ var subCmdHostsList = subCmd{
|
||||
Storage bootstrap.GarageHost `json:",omitempty"`
|
||||
}
|
||||
|
||||
hosts := make([]host, 0, len(hostsMap))
|
||||
for _, h := range hostsMap {
|
||||
hosts := make([]host, 0, len(res.Hosts))
|
||||
for _, h := range res.Hosts {
|
||||
|
||||
host := host{
|
||||
Name: h.Name,
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
// The purpose of this binary is to act as the entrypoint of the isle
|
||||
|
@ -21,7 +21,7 @@ var subCmdNebulaShow = subCmd{
|
||||
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||
}
|
||||
|
||||
caCert := hostBootstrap.CAPublicCredentials.Cert
|
||||
caCert := hostBootstrap.CAPublicCredentials.Cert.Unwrap()
|
||||
caCertPEM, err := caCert.MarshalToPEM()
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshaling CA cert to PEM: %w", err)
|
||||
|
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"isle/daemon/jsonrpc2"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -18,6 +19,7 @@ type subCmdCtx struct {
|
||||
|
||||
ctx context.Context
|
||||
logger *mlog.Logger
|
||||
daemonRCPClient jsonrpc2.Client
|
||||
}
|
||||
|
||||
type subCmd struct {
|
||||
@ -107,12 +109,17 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
||||
}
|
||||
}
|
||||
|
||||
daemonRCPClient := jsonrpc2.NewUnixHTTPClient(
|
||||
envSocketPath, daemonHTTPRPCPath,
|
||||
)
|
||||
|
||||
err := subCmd.do(subCmdCtx{
|
||||
subCmd: subCmd,
|
||||
args: args,
|
||||
subCmdNames: append(ctx.subCmdNames, subCmdName),
|
||||
ctx: ctx.ctx,
|
||||
logger: ctx.logger,
|
||||
daemonRCPClient: daemonRCPClient,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
@ -59,14 +59,14 @@ func nebulaPmuxProcConfig(
|
||||
staticHostMap[ip] = []string{host.Nebula.PublicAddr}
|
||||
}
|
||||
|
||||
caCertPEM, err := hostBootstrap.CAPublicCredentials.Cert.MarshalToPEM()
|
||||
caCertPEM, err := hostBootstrap.CAPublicCredentials.Cert.Unwrap().MarshalToPEM()
|
||||
if err != nil {
|
||||
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
||||
"marshaling CA cert to PEM: :%w", err,
|
||||
)
|
||||
}
|
||||
|
||||
hostCertPEM, err := hostBootstrap.PublicCredentials.Cert.MarshalToPEM()
|
||||
hostCertPEM, err := hostBootstrap.PublicCredentials.Cert.Unwrap().MarshalToPEM()
|
||||
if err != nil {
|
||||
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
||||
"marshaling host cert to PEM: :%w", err,
|
||||
|
@ -6,6 +6,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/tv42/httpunix"
|
||||
)
|
||||
|
||||
type httpClient struct {
|
||||
@ -15,12 +18,33 @@ type httpClient struct {
|
||||
|
||||
// NewHTTPClient returns a Client which will use HTTP POST requests against the
|
||||
// given URL as a transport for JSONRPC2 method calls.
|
||||
func NewHTTPClient(url string) Client {
|
||||
func NewHTTPClient(urlStr string) Client {
|
||||
return &httpClient{
|
||||
c: &http.Client{
|
||||
Transport: http.DefaultTransport.(*http.Transport).Clone(),
|
||||
},
|
||||
url: url,
|
||||
url: urlStr,
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnixHTTPClient returns a Client which will use HTTP POST requests against
|
||||
// the given unix socket as a transport for JSONRPC2 method calls. The given
|
||||
// path will be used as the path portion of the HTTP request.
|
||||
func NewUnixHTTPClient(unixSocketPath, reqPath string) Client {
|
||||
const host = "uds"
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: httpunix.Scheme,
|
||||
Host: host,
|
||||
Path: reqPath,
|
||||
}
|
||||
|
||||
transport := new(httpunix.Transport)
|
||||
transport.RegisterLocation(host, unixSocketPath)
|
||||
|
||||
return &httpClient{
|
||||
c: &http.Client{Transport: transport},
|
||||
url: u.String(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,9 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@ -156,3 +158,20 @@ func TestHTTP(t *testing.T) {
|
||||
t.Cleanup(server.Close)
|
||||
testClient(t, NewHTTPClient(server.URL))
|
||||
}
|
||||
|
||||
func TestUnixHTTP(t *testing.T) {
|
||||
var (
|
||||
unixSocketPath = filepath.Join(t.TempDir(), "test.sock")
|
||||
server = httptest.NewUnstartedServer(NewHTTPHandler(testHandler))
|
||||
)
|
||||
|
||||
var err error
|
||||
if server.Listener, err = net.Listen("unix", unixSocketPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
server.Start()
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
testClient(t, NewUnixHTTPClient(unixSocketPath, "/"))
|
||||
}
|
||||
|
@ -18,6 +18,11 @@ func NewHTTPHandler(h Handler) http.Handler {
|
||||
}
|
||||
|
||||
func (h httpHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
ctx = r.Context()
|
||||
enc = json.NewEncoder(rw)
|
||||
|
46
go/daemon/rpc.go
Normal file
46
go/daemon/rpc.go
Normal file
@ -0,0 +1,46 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"isle/bootstrap"
|
||||
"slices"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// GetHostsResult wraps the results from the GetHosts RPC method.
|
||||
type GetHostsResult struct {
|
||||
Hosts []bootstrap.Host
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// GetHosts returns all hosts known to the cluster, sorted by their name.
|
||||
func (r *RPC) GetHosts(
|
||||
ctx context.Context, req struct{},
|
||||
) (
|
||||
GetHostsResult, error,
|
||||
) {
|
||||
hostsMap, err := r.daemon.GetGarageBootstrapHosts(ctx)
|
||||
if err != nil {
|
||||
return GetHostsResult{}, fmt.Errorf("retrieving hosts: %w", err)
|
||||
}
|
||||
|
||||
hosts := maps.Values(hostsMap)
|
||||
slices.SortFunc(hosts, func(a, b bootstrap.Host) int {
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
|
||||
return GetHostsResult{hosts}, nil
|
||||
}
|
@ -12,13 +12,14 @@ require (
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/slackhq/nebula v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
10
go/go.sum
10
go/go.sum
@ -13,8 +13,8 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -77,10 +77,14 @@ github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03O
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0=
|
||||
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -92,8 +96,6 @@ golang.org/x/sys v0.0.0-20220406155245-289d7a0edf71/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
|
29
go/nebula/certificate.go
Normal file
29
go/nebula/certificate.go
Normal file
@ -0,0 +1,29 @@
|
||||
package nebula
|
||||
|
||||
import "github.com/slackhq/nebula/cert"
|
||||
|
||||
// Certificate wraps a NebulaCertificate to provide convenient (and consistent)
|
||||
// text (un)marshaling methods.
|
||||
type Certificate struct {
|
||||
inner cert.NebulaCertificate
|
||||
}
|
||||
|
||||
// Unwrap returns the wrapped NebulaCertificate type.
|
||||
func (c Certificate) Unwrap() *cert.NebulaCertificate {
|
||||
return &c.inner
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (c Certificate) MarshalText() ([]byte, error) {
|
||||
return c.inner.MarshalToPEM()
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (c *Certificate) UnmarshalText(b []byte) error {
|
||||
nebCrt, _, err := cert.UnmarshalNebulaCertificateFromPEM(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.inner = *nebCrt
|
||||
return nil
|
||||
}
|
@ -13,7 +13,7 @@ import (
|
||||
// HostPublicCredentials contains certificate and signing public keys which are
|
||||
// able to be broadcast publicly.
|
||||
type HostPublicCredentials struct {
|
||||
Cert cert.NebulaCertificate
|
||||
Cert Certificate
|
||||
SigningKey SigningPublicKey
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ type HostPrivateCredentials struct {
|
||||
// able to be broadcast publicly. The signing public key is the same one which
|
||||
// is embedded into the certificate.
|
||||
type CAPublicCredentials struct {
|
||||
Cert cert.NebulaCertificate
|
||||
Cert Certificate
|
||||
SigningKey SigningPublicKey
|
||||
}
|
||||
|
||||
@ -47,20 +47,20 @@ func NewHostCert(
|
||||
hostName string,
|
||||
ip net.IP,
|
||||
) (
|
||||
cert.NebulaCertificate, error,
|
||||
Certificate, error,
|
||||
) {
|
||||
caCert := caCreds.Public.Cert
|
||||
|
||||
issuer, err := caCert.Sha256Sum()
|
||||
issuer, err := caCert.inner.Sha256Sum()
|
||||
if err != nil {
|
||||
return cert.NebulaCertificate{}, fmt.Errorf("getting ca.crt issuer: %w", err)
|
||||
return Certificate{}, fmt.Errorf("getting ca.crt issuer: %w", err)
|
||||
}
|
||||
|
||||
expireAt := caCert.Details.NotAfter.Add(-1 * time.Second)
|
||||
expireAt := caCert.inner.Details.NotAfter.Add(-1 * time.Second)
|
||||
|
||||
subnet := caCert.Details.Subnets[0]
|
||||
subnet := caCert.inner.Details.Subnets[0]
|
||||
if !subnet.Contains(ip) {
|
||||
return cert.NebulaCertificate{}, fmt.Errorf("invalid ip %q, not contained by network subnet %q", ip, subnet)
|
||||
return Certificate{}, fmt.Errorf("invalid ip %q, not contained by network subnet %q", ip, subnet)
|
||||
}
|
||||
|
||||
hostCert := cert.NebulaCertificate{
|
||||
@ -78,15 +78,15 @@ func NewHostCert(
|
||||
},
|
||||
}
|
||||
|
||||
if err := hostCert.CheckRootConstrains(&caCert); err != nil {
|
||||
return cert.NebulaCertificate{}, fmt.Errorf("validating certificate constraints: %w", err)
|
||||
if err := hostCert.CheckRootConstrains(&caCert.inner); err != nil {
|
||||
return Certificate{}, fmt.Errorf("validating certificate constraints: %w", err)
|
||||
}
|
||||
|
||||
if err := signCert(&hostCert, caCreds.SigningPrivateKey); err != nil {
|
||||
return cert.NebulaCertificate{}, fmt.Errorf("signing host cert with ca.key: %w", err)
|
||||
return Certificate{}, fmt.Errorf("signing host cert with ca.key: %w", err)
|
||||
}
|
||||
|
||||
return hostCert, nil
|
||||
return Certificate{hostCert}, nil
|
||||
}
|
||||
|
||||
// NewHostCredentials generates a new key/cert for a nebula host using the CA
|
||||
@ -149,7 +149,7 @@ func NewCACredentials(domain string, subnet *net.IPNet) (CACredentials, error) {
|
||||
|
||||
return CACredentials{
|
||||
Public: CAPublicCredentials{
|
||||
Cert: caCert,
|
||||
Cert: Certificate{caCert},
|
||||
SigningKey: signingPubKey,
|
||||
},
|
||||
SigningPrivateKey: signingPrivKey,
|
||||
|
@ -16,8 +16,8 @@ func TestSigningKeysJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(string(pubJSON), `"-----BEGIN `) {
|
||||
t.Fatalf("pub key didn't marshal to PEM: %q", pubJSON)
|
||||
if !strings.HasPrefix(string(pubJSON), `"S0`) {
|
||||
t.Fatalf("pub key didn't marshal with prefix: %q", pubJSON)
|
||||
}
|
||||
|
||||
var pub2 SigningPublicKey
|
||||
@ -36,8 +36,8 @@ func TestSigningKeysJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(string(privJSON), `"-----BEGIN `) {
|
||||
t.Fatalf("priv key didn't marshal to PEM: %q", privJSON)
|
||||
if !strings.HasPrefix(string(privJSON), `"s0`) {
|
||||
t.Fatalf("priv key didn't marshal with prefix: %q", privJSON)
|
||||
}
|
||||
|
||||
var priv2 SigningPrivateKey
|
||||
|
13
tests/cases/hosts/00-list.sh
Normal file
13
tests/cases/hosts/00-list.sh
Normal file
@ -0,0 +1,13 @@
|
||||
# shellcheck source=../../utils/with-1-data-1-empty-node-cluster.sh
|
||||
source "$UTILS"/with-1-data-1-empty-node-cluster.sh
|
||||
|
||||
as_primus
|
||||
hosts="$(isle hosts list)"
|
||||
|
||||
[ "$(echo "$hosts" | jq -r '.[0].Name')" = "primus" ]
|
||||
[ "$(echo "$hosts" | jq -r '.[0].VPN.IP')" = "10.6.9.1" ]
|
||||
[ "$(echo "$hosts" | jq -r '.[0].Storage.Instances|length')" = "3" ]
|
||||
|
||||
[ "$(echo "$hosts" | jq -r '.[1].Name')" = "secondus" ]
|
||||
[ "$(echo "$hosts" | jq -r '.[1].VPN.IP')" = "10.6.9.2" ]
|
||||
[ "$(echo "$hosts" | jq -r '.[1].Storage.Instances|length')" = "0" ]
|
@ -12,5 +12,6 @@ cat <<EOF
|
||||
export TMPDIR="$TMPDIR"
|
||||
export XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR"
|
||||
export XDG_STATE_HOME="$XDG_STATE_HOME"
|
||||
export ISLE_SOCKET_PATH="$ROOT_TMPDIR/$base-daemon.sock"
|
||||
cd "$TMPDIR"
|
||||
EOF
|
||||
|
@ -62,10 +62,10 @@ EOF
|
||||
pid="$!"
|
||||
echo "Waiting for primus daemon (process $pid) to initialize"
|
||||
|
||||
while ! isle hosts list >/dev/null; do sleep 1; done
|
||||
|
||||
$SHELL "$UTILS/register-cleanup.sh" "$pid" "1-data-1-empty-node-cluster/primus"
|
||||
|
||||
while ! isle hosts list >/dev/null; do sleep 1; done
|
||||
|
||||
echo "Creating secondus bootstrap"
|
||||
isle admin create-bootstrap \
|
||||
--admin-path admin.json \
|
||||
@ -86,8 +86,7 @@ EOF
|
||||
pid="$!"
|
||||
echo "Waiting for secondus daemon (process $!) to initialize"
|
||||
|
||||
while ! isle hosts list >/dev/null; do sleep 1; done
|
||||
|
||||
$SHELL "$UTILS/register-cleanup.sh" "$pid" "1-data-1-empty-node-cluster/secondus"
|
||||
while ! isle hosts list >/dev/null; do sleep 1; done
|
||||
)
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user