Compare commits
No commits in common. "64fdba0a485eda5e941d8e93e32f5f84f96c3294" and "8c3e6a2845f2392bc0fe066c5b2671035c645568" have entirely different histories.
64fdba0a48
...
8c3e6a2845
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# This file defines all configuration directives which can be modified for
|
# This file defines all configuration directives which can be modified for
|
||||||
# the isle daemon at runtime. All values specified here are the
|
# the isle daemon at runtime. All values specified here are the
|
||||||
@ -5,76 +6,80 @@
|
|||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# Configuration broken down by network. Each network can be identified by its
|
# A DNS service runs as part of every isle process.
|
||||||
# ID, its name, or its domain.
|
dns:
|
||||||
#networks:
|
|
||||||
|
|
||||||
#id-or-name-or-domain:
|
# list of IPs that the DNS service will use to resolve requests outside the
|
||||||
|
# network's domain.
|
||||||
|
resolvers:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 8.8.8.8
|
||||||
|
|
||||||
# A DNS service runs as part of every isle process.
|
# A VPN service runs as part of every isle process.
|
||||||
#dns:
|
vpn:
|
||||||
|
|
||||||
# list of IPs that the DNS service will use to resolve requests outside the
|
# Enable this field if the vpn will be made to be publicly accessible at a
|
||||||
# network's domain.
|
# particular IP or hostname. At least one host must have a publicly accessible
|
||||||
#resolvers:
|
# VPN process at any given moment.
|
||||||
# - 1.1.1.1
|
#public_addr: "host:port"
|
||||||
# - 8.8.8.8
|
|
||||||
|
|
||||||
# A VPN service runs as part of every isle process.
|
# Firewall directives, as described here:
|
||||||
#vpn:
|
# https://github.com/slackhq/nebula/blob/v1.6.1/examples/config.yml#L260
|
||||||
|
firewall:
|
||||||
|
|
||||||
# Enable this field if the vpn will be made to be publicly accessible at a
|
conntrack:
|
||||||
# particular IP or hostname. At least one host must have a publicly accessible
|
tcp_timeout: 12m
|
||||||
# VPN process at any given moment.
|
udp_timeout: 3m
|
||||||
#public_addr: "host:port"
|
default_timeout: 10m
|
||||||
|
max_connections: 100000
|
||||||
|
|
||||||
# Firewall directives, as described here:
|
outbound:
|
||||||
# https://github.com/slackhq/nebula/blob/v1.6.1/examples/config.yml#L260
|
|
||||||
#firewall:
|
|
||||||
|
|
||||||
# Allow all outbound traffic from this node.
|
# Allow all outbound traffic from this node.
|
||||||
#outbound:
|
- port: any
|
||||||
# - port: any
|
proto: any
|
||||||
# proto: any
|
host: any
|
||||||
# host: any
|
|
||||||
|
|
||||||
# Allow ICMP between hosts.
|
inbound:
|
||||||
#inbound:
|
|
||||||
# - port: any
|
|
||||||
# proto: icmp
|
|
||||||
# host: any
|
|
||||||
#
|
|
||||||
# # If any storage allocations are declared below, the ports used will be
|
|
||||||
# # allowed here automatically.
|
|
||||||
|
|
||||||
#tun:
|
# If any storage allocations are declared below, the ports used will be
|
||||||
# Name of the tun network device which will route VPN traffic.
|
# allowed here automatically.
|
||||||
#device: isle-tun
|
|
||||||
|
|
||||||
#storage:
|
# Allow ICMP between hosts.
|
||||||
|
- port: any
|
||||||
|
proto: icmp
|
||||||
|
host: any
|
||||||
|
|
||||||
# Allocations defined here are used to store data in the distributed storage
|
# That's it.
|
||||||
# network. If no allocations are defined then no data is replicated to this
|
|
||||||
# node.
|
|
||||||
#
|
|
||||||
# Each allocation should have its own data/meta directories, separate from the
|
|
||||||
# other allocations.
|
|
||||||
#
|
|
||||||
# The data directory of each allocation should be on a different drive, while
|
|
||||||
# the meta directories can be anywhere (ideally on an SSD).
|
|
||||||
#
|
|
||||||
# Capacity declares how many gigabytes can be stored in each allocation, and
|
|
||||||
# is required.
|
|
||||||
#
|
|
||||||
# The ports are all _optional_, and will be automatically assigned if they are
|
|
||||||
# not specified. If ports any ports are specified then all should be
|
|
||||||
# specified, and each should be unique across all allocations.
|
|
||||||
#
|
|
||||||
#allocations:
|
|
||||||
|
|
||||||
#- data_path: /foo/bar/data
|
tun:
|
||||||
# meta_path: /foo/bar/meta
|
# Name of the tun network device which will route VPN traffic.
|
||||||
# capacity: 1200
|
device: isle-tun
|
||||||
# #rpc_port: 3900
|
|
||||||
# #s3_api_port: 3901
|
storage:
|
||||||
# #admin_port: 3902
|
|
||||||
|
# Allocations defined here are used to store data in the distributed storage
|
||||||
|
# network. If no allocations are defined then no data is replicated to this
|
||||||
|
# node.
|
||||||
|
#
|
||||||
|
# Each allocation should have its own data/meta directories, separate from the
|
||||||
|
# other allocations.
|
||||||
|
#
|
||||||
|
# The data directory of each allocation should be on a different drive, while
|
||||||
|
# the meta directories can be anywhere (ideally on an SSD).
|
||||||
|
#
|
||||||
|
# Capacity declares how many gigabytes can be stored in each allocation, and
|
||||||
|
# is required.
|
||||||
|
#
|
||||||
|
# The ports are all _optional_, and will be automatically assigned if they are
|
||||||
|
# not specified. If ports any ports are specified then all should be
|
||||||
|
# specified, and each should be unique across all allocations.
|
||||||
|
#
|
||||||
|
#allocations:
|
||||||
|
|
||||||
|
#- data_path: /foo/bar/data
|
||||||
|
# meta_path: /foo/bar/meta
|
||||||
|
# capacity: 1200
|
||||||
|
# #rpc_port: 3900
|
||||||
|
# #s3_api_port: 3901
|
||||||
|
# #admin_port: 3902
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||||
)
|
)
|
||||||
@ -53,42 +52,6 @@ func (p CreationParams) Annotate(aa mctx.Annotations) {
|
|||||||
aa["networkDomain"] = p.Domain
|
aa["networkDomain"] = p.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches returns true if the given string matches some aspect of the
|
|
||||||
// CreationParams.
|
|
||||||
func (p CreationParams) Matches(str string) bool {
|
|
||||||
if strings.HasPrefix(p.ID, str) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.EqualFold(p.Name, str) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.EqualFold(p.Domain, str) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conflicts returns true if either CreationParams has some parameter which
|
|
||||||
// overlaps with that of the other.
|
|
||||||
func (p CreationParams) Conflicts(p2 CreationParams) bool {
|
|
||||||
if p.ID == p2.ID {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.EqualFold(p.Name, p2.Name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.EqualFold(p.Domain, p2.Domain) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootstrap contains all information which is needed by a host daemon to join a
|
// Bootstrap contains all information which is needed by a host daemon to join a
|
||||||
// network on boot.
|
// network on boot.
|
||||||
type Bootstrap struct {
|
type Bootstrap struct {
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (ctx subCmdCtx) getHosts() ([]bootstrap.Host, error) {
|
func (ctx subCmdCtx) getHosts() ([]bootstrap.Host, error) {
|
||||||
res, err := newDaemonRPCClient().GetHosts(ctx)
|
res, err := ctx.daemonRPC.GetHosts(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("calling GetHosts: %w", err)
|
return nil, fmt.Errorf("calling GetHosts: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -16,27 +16,28 @@ import (
|
|||||||
// restart the service into a configuration that will definitely fail.
|
// restart the service into a configuration that will definitely fail.
|
||||||
|
|
||||||
var subCmdDaemon = subCmd{
|
var subCmdDaemon = subCmd{
|
||||||
name: "daemon",
|
name: "daemon",
|
||||||
descr: "Runs the isle daemon (Default if no sub-command given)",
|
descr: "Runs the isle daemon (Default if no sub-command given)",
|
||||||
noNetwork: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
daemonConfigPath := ctx.flags.StringP(
|
|
||||||
|
flags := ctx.flagSet(false)
|
||||||
|
|
||||||
|
daemonConfigPath := flags.StringP(
|
||||||
"config-path", "c", "",
|
"config-path", "c", "",
|
||||||
"Optional path to a daemon.yml file to load configuration from.",
|
"Optional path to a daemon.yml file to load configuration from.",
|
||||||
)
|
)
|
||||||
|
|
||||||
dumpConfig := ctx.flags.Bool(
|
dumpConfig := flags.Bool(
|
||||||
"dump-config", false,
|
"dump-config", false,
|
||||||
"Write the default configuration file to stdout and exit.",
|
"Write the default configuration file to stdout and exit.",
|
||||||
)
|
)
|
||||||
|
|
||||||
logLevelStr := ctx.flags.StringP(
|
logLevelStr := flags.StringP(
|
||||||
"log-level", "l", "info",
|
"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`,
|
`Maximum log level which should be output. Values can be "debug", "info", "warn", "error", "fatal". Does not apply to sub-processes`,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ var subCmdDaemon = subCmd{
|
|||||||
// required linux capabilities are set.
|
// required linux capabilities are set.
|
||||||
// TODO check that the tun module is loaded (for nebula).
|
// TODO check that the tun module is loaded (for nebula).
|
||||||
|
|
||||||
daemonConfig, err := daecommon.LoadConfig(*daemonConfigPath)
|
daemonConfig, err := daecommon.LoadConfig(envAppDirPath, *daemonConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("loading daemon config: %w", err)
|
return fmt.Errorf("loading daemon config: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"isle/daemon"
|
"isle/daemon"
|
||||||
"isle/daemon/jsonrpc2"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -17,14 +16,6 @@ import (
|
|||||||
|
|
||||||
const daemonHTTPRPCPath = "/rpc/v0.json"
|
const daemonHTTPRPCPath = "/rpc/v0.json"
|
||||||
|
|
||||||
func newDaemonRPCClient() daemon.RPC {
|
|
||||||
return daemon.RPCFromClient(
|
|
||||||
jsonrpc2.NewUnixHTTPClient(
|
|
||||||
daemon.HTTPSocketPath(), daemonHTTPRPCPath,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHTTPServer(
|
func newHTTPServer(
|
||||||
ctx context.Context, logger *mlog.Logger, daemonInst *daemon.Daemon,
|
ctx context.Context, logger *mlog.Logger, daemonInst *daemon.Daemon,
|
||||||
) (
|
) (
|
||||||
|
@ -32,26 +32,27 @@ func initMCConfigDir(envVars daecommon.EnvVars) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdGarageMC = subCmd{
|
var subCmdGarageMC = subCmd{
|
||||||
name: "mc",
|
name: "mc",
|
||||||
descr: "Runs the mc (minio-client) binary. The isle garage can be accessed under the `garage` alias",
|
descr: "Runs the mc (minio-client) binary. The isle garage can be accessed under the `garage` alias",
|
||||||
passthroughArgs: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
keyID := ctx.flags.StringP(
|
|
||||||
|
flags := ctx.flagSet(true)
|
||||||
|
|
||||||
|
keyID := flags.StringP(
|
||||||
"key-id", "i", "",
|
"key-id", "i", "",
|
||||||
"Optional key ID to use, defaults to that of the shared global key",
|
"Optional key ID to use, defaults to that of the shared global key",
|
||||||
)
|
)
|
||||||
|
|
||||||
keySecret := ctx.flags.StringP(
|
keySecret := flags.StringP(
|
||||||
"key-secret", "s", "",
|
"key-secret", "s", "",
|
||||||
"Optional key secret to use, defaults to that of the shared global key",
|
"Optional key secret to use, defaults to that of the shared global key",
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientParams, err := newDaemonRPCClient().GetGarageClientParams(ctx)
|
clientParams, err := ctx.daemonRPC.GetGarageClientParams(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calling GetGarageClientParams: %w", err)
|
return fmt.Errorf("calling GetGarageClientParams: %w", err)
|
||||||
}
|
}
|
||||||
@ -66,9 +67,9 @@ var subCmdGarageMC = subCmd{
|
|||||||
*keySecret = clientParams.GlobalBucketS3APICredentials.Secret
|
*keySecret = clientParams.GlobalBucketS3APICredentials.Secret
|
||||||
}
|
}
|
||||||
|
|
||||||
args := ctx.flags.Args()
|
args := flags.Args()
|
||||||
|
|
||||||
if i := ctx.flags.ArgsLenAtDash(); i >= 0 {
|
if i := flags.ArgsLenAtDash(); i >= 0 {
|
||||||
args = args[i:]
|
args = args[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,12 +117,8 @@ var subCmdGarageCLI = subCmd{
|
|||||||
name: "cli",
|
name: "cli",
|
||||||
descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
|
descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
ctx, err := ctx.withParsedFlags()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
clientParams, err := newDaemonRPCClient().GetGarageClientParams(ctx)
|
clientParams, err := ctx.daemonRPC.GetGarageClientParams(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calling GetGarageClientParams: %w", err)
|
return fmt.Errorf("calling GetGarageClientParams: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -16,26 +16,26 @@ var subCmdHostCreate = subCmd{
|
|||||||
descr: "Creates a new host in the network, writing its new bootstrap.json to stdout",
|
descr: "Creates a new host in the network, writing its new bootstrap.json to stdout",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
|
flags = ctx.flagSet(false)
|
||||||
hostName hostNameFlag
|
hostName hostNameFlag
|
||||||
ip ipFlag
|
ip ipFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := ctx.flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
&hostName,
|
&hostName,
|
||||||
"hostname", "n",
|
"hostname", "n",
|
||||||
"Name of the host to generate bootstrap.json for",
|
"Name of the host to generate bootstrap.json for",
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx.flags.VarP(&ip, "ip", "i", "IP of the new host. An available IP will be chosen if none is given.")
|
flags.VarP(&ip, "ip", "i", "IP of the new host. An available IP will be chosen if none is given.")
|
||||||
|
|
||||||
canCreateHosts := ctx.flags.Bool(
|
canCreateHosts := flags.Bool(
|
||||||
"can-create-hosts",
|
"can-create-hosts",
|
||||||
false,
|
false,
|
||||||
"The new host should have the ability to create hosts too",
|
"The new host should have the ability to create hosts too",
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,11 @@ var subCmdHostCreate = subCmd{
|
|||||||
return errors.New("--hostname is required")
|
return errors.New("--hostname is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := newDaemonRPCClient().CreateHost(
|
var (
|
||||||
|
res network.JoiningBootstrap
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
res, err = ctx.daemonRPC.CreateHost(
|
||||||
ctx, hostName.V, network.CreateHostOpts{
|
ctx, hostName.V, network.CreateHostOpts{
|
||||||
IP: ip.V,
|
IP: ip.V,
|
||||||
CanCreateHosts: *canCreateHosts,
|
CanCreateHosts: *canCreateHosts,
|
||||||
@ -61,11 +65,6 @@ var subCmdHostList = subCmd{
|
|||||||
name: "list",
|
name: "list",
|
||||||
descr: "Lists all hosts in the network, and their IPs",
|
descr: "Lists all hosts in the network, and their IPs",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
ctx, err := ctx.withParsedFlags()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostsRes, err := ctx.getHosts()
|
hostsRes, err := ctx.getHosts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calling GetHosts: %w", err)
|
return fmt.Errorf("calling GetHosts: %w", err)
|
||||||
@ -103,17 +102,17 @@ var subCmdHostRemove = subCmd{
|
|||||||
descr: "Removes a host from the network",
|
descr: "Removes a host from the network",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
|
flags = ctx.flagSet(false)
|
||||||
hostName hostNameFlag
|
hostName hostNameFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := ctx.flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
&hostName,
|
&hostName,
|
||||||
"hostname", "n",
|
"hostname", "n",
|
||||||
"Name of the host to remove",
|
"Name of the host to remove",
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +120,7 @@ var subCmdHostRemove = subCmd{
|
|||||||
return errors.New("--hostname is required")
|
return errors.New("--hostname is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := newDaemonRPCClient().RemoveHost(ctx, hostName.V); err != nil {
|
if err := ctx.daemonRPC.RemoveHost(ctx, hostName.V); err != nil {
|
||||||
return fmt.Errorf("calling RemoveHost: %w", err)
|
return fmt.Errorf("calling RemoveHost: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ func main() {
|
|||||||
|
|
||||||
err := subCmdCtx{
|
err := subCmdCtx{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
logger: logger,
|
|
||||||
args: os.Args[1:],
|
args: os.Args[1:],
|
||||||
|
logger: logger,
|
||||||
}.doSubCmd(
|
}.doSubCmd(
|
||||||
subCmdDaemon,
|
subCmdDaemon,
|
||||||
subCmdGarage,
|
subCmdGarage,
|
||||||
|
@ -12,21 +12,23 @@ var subCmdNebulaCreateCert = subCmd{
|
|||||||
name: "create-cert",
|
name: "create-cert",
|
||||||
descr: "Creates a signed nebula certificate file for an existing host and writes it to stdout",
|
descr: "Creates a signed nebula certificate file for an existing host and writes it to stdout",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
|
var (
|
||||||
|
flags = ctx.flagSet(false)
|
||||||
|
hostName hostNameFlag
|
||||||
|
)
|
||||||
|
|
||||||
var hostName hostNameFlag
|
hostNameF := flags.VarPF(
|
||||||
hostNameF := ctx.flags.VarPF(
|
|
||||||
&hostName,
|
&hostName,
|
||||||
"hostname", "n",
|
"hostname", "n",
|
||||||
"Name of the host to generate a certificate for",
|
"Name of the host to generate a certificate for",
|
||||||
)
|
)
|
||||||
|
|
||||||
pubKeyPath := ctx.flags.StringP(
|
pubKeyPath := flags.StringP(
|
||||||
"public-key-path", "p", "",
|
"public-key-path", "p", "",
|
||||||
`Path to PEM file containing public key which will be embedded in the cert.`,
|
`Path to PEM file containing public key which will be embedded in the cert.`,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ var subCmdNebulaCreateCert = subCmd{
|
|||||||
return fmt.Errorf("unmarshaling public key as PEM: %w", err)
|
return fmt.Errorf("unmarshaling public key as PEM: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := newDaemonRPCClient().CreateNebulaCertificate(
|
res, err := ctx.daemonRPC.CreateNebulaCertificate(
|
||||||
ctx, hostName.V, hostPub,
|
ctx, hostName.V, hostPub,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,8 +70,9 @@ var subCmdNebulaShow = subCmd{
|
|||||||
name: "show",
|
name: "show",
|
||||||
descr: "Writes nebula network information to stdout in JSON format",
|
descr: "Writes nebula network information to stdout in JSON format",
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
ctx, err := ctx.withParsedFlags()
|
|
||||||
if err != nil {
|
flags := ctx.flagSet(false)
|
||||||
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +81,7 @@ var subCmdNebulaShow = subCmd{
|
|||||||
return fmt.Errorf("getting hosts: %w", err)
|
return fmt.Errorf("getting hosts: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
caPublicCreds, err := newDaemonRPCClient().GetNebulaCAPublicCredentials(ctx)
|
caPublicCreds, err := ctx.daemonRPC.GetNebulaCAPublicCredentials(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err)
|
return fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -5,44 +5,42 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"isle/daemon/network"
|
"isle/daemon/network"
|
||||||
"isle/jsonutil"
|
"isle/jsonutil"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var subCmdNetworkCreate = subCmd{
|
var subCmdNetworkCreate = subCmd{
|
||||||
name: "create",
|
name: "create",
|
||||||
descr: "Create's a new network, with this host being the first host in that network.",
|
descr: "Create's a new network, with this host being the first host in that network.",
|
||||||
noNetwork: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
|
flags = ctx.flagSet(false)
|
||||||
ipNet ipNetFlag
|
ipNet ipNetFlag
|
||||||
hostName hostNameFlag
|
hostName hostNameFlag
|
||||||
)
|
)
|
||||||
|
|
||||||
name := ctx.flags.StringP(
|
name := flags.StringP(
|
||||||
"name", "N", "",
|
"name", "N", "",
|
||||||
"Human-readable name to identify the network as.",
|
"Human-readable name to identify the network as.",
|
||||||
)
|
)
|
||||||
|
|
||||||
domain := ctx.flags.StringP(
|
domain := flags.StringP(
|
||||||
"domain", "d", "",
|
"domain", "d", "",
|
||||||
"Domain name that should be used as the root domain in the network.",
|
"Domain name that should be used as the root domain in the network.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ipNetF := ctx.flags.VarPF(
|
ipNetF := flags.VarPF(
|
||||||
&ipNet, "ip-net", "i",
|
&ipNet, "ip-net", "i",
|
||||||
`An IP subnet, in CIDR form, which will be the overall range of`+
|
`An IP subnet, in CIDR form, which will be the overall range of`+
|
||||||
` possible IPs in the network. The first IP in this network`+
|
` possible IPs in the network. The first IP in this network`+
|
||||||
` range will become this first host's IP.`,
|
` range will become this first host's IP.`,
|
||||||
)
|
)
|
||||||
|
|
||||||
hostNameF := ctx.flags.VarPF(
|
hostNameF := flags.VarPF(
|
||||||
&hostName,
|
&hostName,
|
||||||
"hostname", "n",
|
"hostname", "n",
|
||||||
"Name of this host, which will be the first host in the network",
|
"Name of this host, which will be the first host in the network",
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ var subCmdNetworkCreate = subCmd{
|
|||||||
return errors.New("--name, --domain, --ip-net, and --hostname are required")
|
return errors.New("--name, --domain, --ip-net, and --hostname are required")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = newDaemonRPCClient().CreateNetwork(
|
err := ctx.daemonRPC.CreateNetwork(
|
||||||
ctx, *name, *domain, ipNet.V, hostName.V,
|
ctx, *name, *domain, ipNet.V, hostName.V,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,16 +63,17 @@ var subCmdNetworkCreate = subCmd{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdNetworkJoin = subCmd{
|
var subCmdNetworkJoin = subCmd{
|
||||||
name: "join",
|
name: "join",
|
||||||
descr: "Joins this host to an existing network",
|
descr: "Joins this host to an existing network",
|
||||||
noNetwork: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
bootstrapPath := ctx.flags.StringP(
|
var (
|
||||||
"bootstrap-path", "b", "", "Path to a bootstrap.json file.",
|
flags = ctx.flagSet(false)
|
||||||
|
bootstrapPath = flags.StringP(
|
||||||
|
"bootstrap-path", "b", "", "Path to a bootstrap.json file.",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
if err := flags.Parse(ctx.args); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,38 +88,17 @@ var subCmdNetworkJoin = subCmd{
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDaemonRPCClient().JoinNetwork(ctx, newBootstrap)
|
return ctx.daemonRPC.JoinNetwork(ctx, newBootstrap)
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var subCmdNetworkList = subCmd{
|
|
||||||
name: "list",
|
|
||||||
descr: "Lists all networks which have been joined",
|
|
||||||
noNetwork: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
|
||||||
ctx, err := ctx.withParsedFlags()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
creationParams, err := newDaemonRPCClient().GetNetworks(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("getting joined networks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonutil.WriteIndented(os.Stdout, creationParams)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var subCmdNetwork = subCmd{
|
var subCmdNetwork = subCmd{
|
||||||
name: "network",
|
name: "network",
|
||||||
descr: "Sub-commands related to network membership",
|
descr: "Sub-commands related to network membership",
|
||||||
plural: "s",
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
return ctx.doSubCmd(
|
return ctx.doSubCmd(
|
||||||
subCmdNetworkCreate,
|
subCmdNetworkCreate,
|
||||||
subCmdNetworkJoin,
|
subCmdNetworkJoin,
|
||||||
subCmdNetworkList,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"isle/daemon"
|
"isle/daemon"
|
||||||
|
"isle/daemon/jsonrpc2"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -13,8 +14,30 @@ import (
|
|||||||
|
|
||||||
type flagSet struct {
|
type flagSet struct {
|
||||||
*pflag.FlagSet
|
*pflag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
network string
|
func (fs flagSet) Parse(args []string) error {
|
||||||
|
fs.VisitAll(func(f *pflag.Flag) {
|
||||||
|
if f.Shorthand == "h" {
|
||||||
|
panic(fmt.Sprintf("flag %+v has reserved shorthand `-h`", f))
|
||||||
|
}
|
||||||
|
if f.Name == "help" {
|
||||||
|
panic(fmt.Sprintf("flag %+v has reserved name `--help`", f))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return fs.FlagSet.Parse(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// subCmdCtx contains all information available to a subCmd's do method.
|
||||||
|
type subCmdCtx struct {
|
||||||
|
context.Context
|
||||||
|
|
||||||
|
subCmd subCmd // the subCmd itself
|
||||||
|
args []string // command-line arguments, excluding the subCmd itself.
|
||||||
|
subCmdNames []string // names of subCmds so far, including this one
|
||||||
|
|
||||||
|
logger *mlog.Logger
|
||||||
|
daemonRPC daemon.RPC
|
||||||
}
|
}
|
||||||
|
|
||||||
type subCmd struct {
|
type subCmd struct {
|
||||||
@ -24,74 +47,11 @@ type subCmd struct {
|
|||||||
|
|
||||||
// If set then the name will be allowed to be suffixed with this string.
|
// If set then the name will be allowed to be suffixed with this string.
|
||||||
plural string
|
plural string
|
||||||
|
|
||||||
// noNetwork, if true, means the call doesn't require a network to be
|
|
||||||
// specified on the command-line if there are more than one networks
|
|
||||||
// configured.
|
|
||||||
noNetwork bool
|
|
||||||
|
|
||||||
// Extra arguments on the command-line will be passed through to some
|
|
||||||
// underlying command.
|
|
||||||
passthroughArgs bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// subCmdCtx contains all information available to a subCmd's do method.
|
func (ctx subCmdCtx) usagePrefix() string {
|
||||||
type subCmdCtx struct {
|
|
||||||
context.Context
|
|
||||||
logger *mlog.Logger
|
|
||||||
|
|
||||||
subCmd subCmd // the subCmd itself
|
subCmdNamesStr := strings.Join(ctx.subCmdNames, " ")
|
||||||
args []string // command-line arguments, excluding the subCmd itself.
|
|
||||||
subCmdNames []string // names of subCmds so far, including this one
|
|
||||||
|
|
||||||
flags flagSet
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSubCmdCtx(
|
|
||||||
ctx context.Context,
|
|
||||||
logger *mlog.Logger,
|
|
||||||
subCmd subCmd,
|
|
||||||
args []string,
|
|
||||||
subCmdNames []string,
|
|
||||||
) subCmdCtx {
|
|
||||||
flags := pflag.NewFlagSet(subCmd.name, pflag.ExitOnError)
|
|
||||||
flags.Usage = func() {
|
|
||||||
var passthroughStr string
|
|
||||||
if subCmd.passthroughArgs {
|
|
||||||
passthroughStr = " [--] [args...]"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(
|
|
||||||
os.Stderr, "%s[-h|--help] [%s flags...]%s\n\n",
|
|
||||||
usagePrefix(subCmdNames), subCmd.name, passthroughStr,
|
|
||||||
)
|
|
||||||
fmt.Fprintf(os.Stderr, "%s FLAGS:\n\n", strings.ToUpper(subCmd.name))
|
|
||||||
fmt.Fprintln(os.Stderr, flags.FlagUsages())
|
|
||||||
|
|
||||||
os.Stderr.Sync()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs := flagSet{FlagSet: flags}
|
|
||||||
|
|
||||||
if !subCmd.noNetwork {
|
|
||||||
fs.FlagSet.StringVar(
|
|
||||||
&fs.network, "network", "", "Which network to perform the command against, if more than one is joined. Can be ID, name, or domain",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return subCmdCtx{
|
|
||||||
Context: ctx,
|
|
||||||
logger: logger,
|
|
||||||
subCmd: subCmd,
|
|
||||||
args: args,
|
|
||||||
subCmdNames: subCmdNames,
|
|
||||||
flags: fs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func usagePrefix(subCmdNames []string) string {
|
|
||||||
subCmdNamesStr := strings.Join(subCmdNames, " ")
|
|
||||||
if subCmdNamesStr != "" {
|
if subCmdNamesStr != "" {
|
||||||
subCmdNamesStr += " "
|
subCmdNamesStr += " "
|
||||||
}
|
}
|
||||||
@ -99,22 +59,26 @@ func usagePrefix(subCmdNames []string) string {
|
|||||||
return fmt.Sprintf("\nUSAGE: %s %s", os.Args[0], subCmdNamesStr)
|
return fmt.Sprintf("\nUSAGE: %s %s", os.Args[0], subCmdNamesStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx subCmdCtx) withParsedFlags() (subCmdCtx, error) {
|
func (ctx subCmdCtx) flagSet(withPassthrough bool) flagSet {
|
||||||
ctx.flags.VisitAll(func(f *pflag.Flag) {
|
flags := pflag.NewFlagSet(ctx.subCmd.name, pflag.ExitOnError)
|
||||||
if f.Shorthand == "h" {
|
flags.Usage = func() {
|
||||||
panic(fmt.Sprintf("flag %+v has reserved shorthand `-h`", f))
|
|
||||||
}
|
|
||||||
if f.Name == "help" {
|
|
||||||
panic(fmt.Sprintf("flag %+v has reserved name `--help`", f))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := ctx.flags.Parse(ctx.args); err != nil {
|
var passthroughStr string
|
||||||
return ctx, err
|
if withPassthrough {
|
||||||
|
passthroughStr = " [--] [args...]"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(
|
||||||
|
os.Stderr, "%s[-h|--help] [%s flags...]%s\n\n",
|
||||||
|
ctx.usagePrefix(), ctx.subCmd.name, passthroughStr,
|
||||||
|
)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s FLAGS:\n\n", strings.ToUpper(ctx.subCmd.name))
|
||||||
|
fmt.Fprintln(os.Stderr, flags.FlagUsages())
|
||||||
|
|
||||||
|
os.Stderr.Sync()
|
||||||
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
return flagSet{flags}
|
||||||
ctx.Context = daemon.WithNetwork(ctx.Context, ctx.flags.network)
|
|
||||||
return ctx, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
||||||
@ -126,7 +90,7 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
|||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
os.Stderr,
|
os.Stderr,
|
||||||
"%s<subCmd> [-h|--help] [sub-command flags...]\n",
|
"%s<subCmd> [-h|--help] [sub-command flags...]\n",
|
||||||
usagePrefix(ctx.subCmdNames),
|
ctx.usagePrefix(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "\nSUB-COMMANDS:\n\n")
|
fmt.Fprintf(os.Stderr, "\nSUB-COMMANDS:\n\n")
|
||||||
@ -159,21 +123,28 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subCmdName, args := args[0], args[1:]
|
subCmdName, args := args[0], args[1:]
|
||||||
|
|
||||||
subCmd, ok := subCmdsMap[subCmdName]
|
subCmd, ok := subCmdsMap[subCmdName]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
printUsageExit(subCmdName)
|
printUsageExit(subCmdName)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextSubCmdCtx := newSubCmdCtx(
|
daemonRPC := daemon.RPCFromClient(
|
||||||
ctx.Context,
|
jsonrpc2.NewUnixHTTPClient(
|
||||||
ctx.logger,
|
daemon.HTTPSocketPath(), daemonHTTPRPCPath,
|
||||||
subCmd,
|
),
|
||||||
args,
|
|
||||||
append(ctx.subCmdNames, subCmdName),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := subCmd.do(nextSubCmdCtx); err != nil {
|
err := subCmd.do(subCmdCtx{
|
||||||
|
Context: ctx.Context,
|
||||||
|
subCmd: subCmd,
|
||||||
|
args: args,
|
||||||
|
subCmdNames: append(ctx.subCmdNames, subCmdName),
|
||||||
|
logger: ctx.logger,
|
||||||
|
daemonRPC: daemonRPC,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var subCmdVersion = subCmd{
|
var subCmdVersion = subCmd{
|
||||||
name: "version",
|
name: "version",
|
||||||
descr: "Dumps version and build info to stdout",
|
descr: "Dumps version and build info to stdout",
|
||||||
noNetwork: true,
|
|
||||||
do: func(ctx subCmdCtx) error {
|
do: func(ctx subCmdCtx) error {
|
||||||
|
|
||||||
versionPath := filepath.Join(envAppDirPath, "share/version")
|
versionPath := filepath.Join(envAppDirPath, "share/version")
|
||||||
|
@ -48,10 +48,10 @@ func (o *Opts) withDefaults() *Opts {
|
|||||||
// - dnsmasq
|
// - dnsmasq
|
||||||
// - garage (0 or more, depending on configured storage allocations)
|
// - garage (0 or more, depending on configured storage allocations)
|
||||||
type Children struct {
|
type Children struct {
|
||||||
logger *mlog.Logger
|
logger *mlog.Logger
|
||||||
networkConfig daecommon.NetworkConfig
|
daemonConfig daecommon.Config
|
||||||
runtimeDir toolkit.Dir
|
runtimeDir toolkit.Dir
|
||||||
opts Opts
|
opts Opts
|
||||||
|
|
||||||
pmux *pmuxlib.Pmux
|
pmux *pmuxlib.Pmux
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ func New(
|
|||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
binDirPath string,
|
binDirPath string,
|
||||||
secretsStore secrets.Store,
|
secretsStore secrets.Store,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
runtimeDir toolkit.Dir,
|
runtimeDir toolkit.Dir,
|
||||||
garageAdminToken string,
|
garageAdminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
@ -80,17 +80,17 @@ func New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := &Children{
|
c := &Children{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
networkConfig: networkConfig,
|
daemonConfig: daemonConfig,
|
||||||
runtimeDir: runtimeDir,
|
runtimeDir: runtimeDir,
|
||||||
opts: *opts,
|
opts: *opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
pmuxConfig, err := c.newPmuxConfig(
|
pmuxConfig, err := c.newPmuxConfig(
|
||||||
ctx,
|
ctx,
|
||||||
garageRPCSecret,
|
garageRPCSecret,
|
||||||
binDirPath,
|
binDirPath,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
garageAdminToken,
|
garageAdminToken,
|
||||||
hostBootstrap,
|
hostBootstrap,
|
||||||
)
|
)
|
||||||
@ -101,7 +101,7 @@ func New(
|
|||||||
c.pmux = pmuxlib.NewPmux(pmuxConfig, c.opts.Stdout, c.opts.Stderr)
|
c.pmux = pmuxlib.NewPmux(pmuxConfig, c.opts.Stdout, c.opts.Stderr)
|
||||||
|
|
||||||
initErr := c.postPmuxInit(
|
initErr := c.postPmuxInit(
|
||||||
ctx, networkConfig, garageAdminToken, hostBootstrap,
|
ctx, daemonConfig, garageAdminToken, hostBootstrap,
|
||||||
)
|
)
|
||||||
if initErr != nil {
|
if initErr != nil {
|
||||||
logger.Warn(ctx, "failed to initialize Children, shutting down child processes", err)
|
logger.Warn(ctx, "failed to initialize Children, shutting down child processes", err)
|
||||||
@ -118,7 +118,7 @@ func New(
|
|||||||
// successfully.
|
// successfully.
|
||||||
func (c *Children) RestartDNSMasq(hostBootstrap bootstrap.Bootstrap) error {
|
func (c *Children) RestartDNSMasq(hostBootstrap bootstrap.Bootstrap) error {
|
||||||
_, err := dnsmasqWriteConfig(
|
_, err := dnsmasqWriteConfig(
|
||||||
c.runtimeDir.Path, c.networkConfig, hostBootstrap,
|
c.runtimeDir.Path, c.daemonConfig, hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("writing new dnsmasq config: %w", err)
|
return fmt.Errorf("writing new dnsmasq config: %w", err)
|
||||||
@ -134,7 +134,7 @@ func (c *Children) RestartDNSMasq(hostBootstrap bootstrap.Bootstrap) error {
|
|||||||
// successfully.
|
// successfully.
|
||||||
func (c *Children) RestartNebula(hostBootstrap bootstrap.Bootstrap) error {
|
func (c *Children) RestartNebula(hostBootstrap bootstrap.Bootstrap) error {
|
||||||
_, err := nebulaWriteConfig(
|
_, err := nebulaWriteConfig(
|
||||||
c.runtimeDir.Path, c.networkConfig, hostBootstrap,
|
c.runtimeDir.Path, c.daemonConfig, hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("writing a new nebula config: %w", err)
|
return fmt.Errorf("writing a new nebula config: %w", err)
|
||||||
|
@ -18,14 +18,14 @@ type ReloadDiff struct {
|
|||||||
// CalculateReloadDiff calculates a ReloadDiff based on an old and new
|
// CalculateReloadDiff calculates a ReloadDiff based on an old and new
|
||||||
// bootstrap.
|
// bootstrap.
|
||||||
func CalculateReloadDiff(
|
func CalculateReloadDiff(
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
prevBootstrap, nextBootstrap bootstrap.Bootstrap,
|
prevBootstrap, nextBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
diff ReloadDiff, err error,
|
diff ReloadDiff, err error,
|
||||||
) {
|
) {
|
||||||
{
|
{
|
||||||
prevNebulaConfig, prevErr := nebulaConfig(networkConfig, prevBootstrap)
|
prevNebulaConfig, prevErr := nebulaConfig(daemonConfig, prevBootstrap)
|
||||||
nextNebulaConfig, nextErr := nebulaConfig(networkConfig, nextBootstrap)
|
nextNebulaConfig, nextErr := nebulaConfig(daemonConfig, nextBootstrap)
|
||||||
if err = errors.Join(prevErr, nextErr); err != nil {
|
if err = errors.Join(prevErr, nextErr); err != nil {
|
||||||
err = fmt.Errorf("calculating nebula config: %w", err)
|
err = fmt.Errorf("calculating nebula config: %w", err)
|
||||||
return
|
return
|
||||||
@ -38,8 +38,8 @@ func CalculateReloadDiff(
|
|||||||
|
|
||||||
{
|
{
|
||||||
diff.DNSChanged = !reflect.DeepEqual(
|
diff.DNSChanged = !reflect.DeepEqual(
|
||||||
dnsmasqConfig(networkConfig, prevBootstrap),
|
dnsmasqConfig(daemonConfig, prevBootstrap),
|
||||||
dnsmasqConfig(networkConfig, nextBootstrap),
|
dnsmasqConfig(daemonConfig, nextBootstrap),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func dnsmasqConfig(
|
func dnsmasqConfig(
|
||||||
networkConfig daecommon.NetworkConfig, hostBootstrap bootstrap.Bootstrap,
|
daemonConfig daecommon.Config, hostBootstrap bootstrap.Bootstrap,
|
||||||
) dnsmasq.ConfData {
|
) dnsmasq.ConfData {
|
||||||
hostsSlice := make([]dnsmasq.ConfDataHost, 0, len(hostBootstrap.Hosts))
|
hostsSlice := make([]dnsmasq.ConfDataHost, 0, len(hostBootstrap.Hosts))
|
||||||
for _, host := range hostBootstrap.Hosts {
|
for _, host := range hostBootstrap.Hosts {
|
||||||
@ -29,7 +29,7 @@ func dnsmasqConfig(
|
|||||||
})
|
})
|
||||||
|
|
||||||
return dnsmasq.ConfData{
|
return dnsmasq.ConfData{
|
||||||
Resolvers: networkConfig.DNS.Resolvers,
|
Resolvers: daemonConfig.DNS.Resolvers,
|
||||||
Domain: hostBootstrap.NetworkCreationParams.Domain,
|
Domain: hostBootstrap.NetworkCreationParams.Domain,
|
||||||
IP: hostBootstrap.ThisHost().IP().String(),
|
IP: hostBootstrap.ThisHost().IP().String(),
|
||||||
Hosts: hostsSlice,
|
Hosts: hostsSlice,
|
||||||
@ -38,14 +38,14 @@ func dnsmasqConfig(
|
|||||||
|
|
||||||
func dnsmasqWriteConfig(
|
func dnsmasqWriteConfig(
|
||||||
runtimeDirPath string,
|
runtimeDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
string, error,
|
string, error,
|
||||||
) {
|
) {
|
||||||
var (
|
var (
|
||||||
confPath = filepath.Join(runtimeDirPath, "dnsmasq.conf")
|
confPath = filepath.Join(runtimeDirPath, "dnsmasq.conf")
|
||||||
confData = dnsmasqConfig(networkConfig, hostBootstrap)
|
confData = dnsmasqConfig(daemonConfig, hostBootstrap)
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := dnsmasq.WriteConfFile(confPath, confData); err != nil {
|
if err := dnsmasq.WriteConfFile(confPath, confData); err != nil {
|
||||||
@ -58,13 +58,13 @@ func dnsmasqWriteConfig(
|
|||||||
func dnsmasqPmuxProcConfig(
|
func dnsmasqPmuxProcConfig(
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
runtimeDirPath, binDirPath string,
|
runtimeDirPath, binDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
pmuxlib.ProcessConfig, error,
|
pmuxlib.ProcessConfig, error,
|
||||||
) {
|
) {
|
||||||
confPath, err := dnsmasqWriteConfig(
|
confPath, err := dnsmasqWriteConfig(
|
||||||
runtimeDirPath, networkConfig, hostBootstrap,
|
runtimeDirPath, daemonConfig, hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
||||||
|
@ -23,12 +23,12 @@ func garageAdminClientLogger(logger *mlog.Logger) *mlog.Logger {
|
|||||||
func waitForGarage(
|
func waitForGarage(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
adminToken string,
|
adminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
allocs := networkConfig.Storage.Allocations
|
allocs := daemonConfig.Storage.Allocations
|
||||||
|
|
||||||
// if this host doesn't have any allocations specified then fall back to
|
// if this host doesn't have any allocations specified then fall back to
|
||||||
// waiting for nebula
|
// waiting for nebula
|
||||||
@ -108,7 +108,7 @@ func garagePmuxProcConfigs(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
rpcSecret, runtimeDirPath, binDirPath string,
|
rpcSecret, runtimeDirPath, binDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
adminToken string,
|
adminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
@ -116,7 +116,7 @@ func garagePmuxProcConfigs(
|
|||||||
) {
|
) {
|
||||||
var (
|
var (
|
||||||
pmuxProcConfigs = map[string]pmuxlib.ProcessConfig{}
|
pmuxProcConfigs = map[string]pmuxlib.ProcessConfig{}
|
||||||
allocs = networkConfig.Storage.Allocations
|
allocs = daemonConfig.Storage.Allocations
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(allocs) > 0 && rpcSecret == "" {
|
if len(allocs) > 0 && rpcSecret == "" {
|
||||||
|
@ -48,7 +48,7 @@ func waitForNebula(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func nebulaConfig(
|
func nebulaConfig(
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
map[string]any, error,
|
map[string]any, error,
|
||||||
@ -95,12 +95,12 @@ func nebulaConfig(
|
|||||||
"respond": true,
|
"respond": true,
|
||||||
},
|
},
|
||||||
"tun": map[string]any{
|
"tun": map[string]any{
|
||||||
"dev": networkConfig.VPN.Tun.Device,
|
"dev": daemonConfig.VPN.Tun.Device,
|
||||||
},
|
},
|
||||||
"firewall": networkConfig.VPN.Firewall,
|
"firewall": daemonConfig.VPN.Firewall,
|
||||||
}
|
}
|
||||||
|
|
||||||
if publicAddr := networkConfig.VPN.PublicAddr; publicAddr == "" {
|
if publicAddr := daemonConfig.VPN.PublicAddr; publicAddr == "" {
|
||||||
|
|
||||||
config["listen"] = map[string]string{
|
config["listen"] = map[string]string{
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
@ -137,12 +137,12 @@ func nebulaConfig(
|
|||||||
|
|
||||||
func nebulaWriteConfig(
|
func nebulaWriteConfig(
|
||||||
runtimeDirPath string,
|
runtimeDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
string, error,
|
string, error,
|
||||||
) {
|
) {
|
||||||
config, err := nebulaConfig(networkConfig, hostBootstrap)
|
config, err := nebulaConfig(daemonConfig, hostBootstrap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("creating nebula config: %w", err)
|
return "", fmt.Errorf("creating nebula config: %w", err)
|
||||||
}
|
}
|
||||||
@ -158,12 +158,12 @@ func nebulaWriteConfig(
|
|||||||
|
|
||||||
func nebulaPmuxProcConfig(
|
func nebulaPmuxProcConfig(
|
||||||
runtimeDirPath, binDirPath string,
|
runtimeDirPath, binDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
pmuxlib.ProcessConfig, error,
|
pmuxlib.ProcessConfig, error,
|
||||||
) {
|
) {
|
||||||
config, err := nebulaConfig(networkConfig, hostBootstrap)
|
config, err := nebulaConfig(daemonConfig, hostBootstrap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
return pmuxlib.ProcessConfig{}, fmt.Errorf(
|
||||||
"creating nebula config: %w", err,
|
"creating nebula config: %w", err,
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
func (c *Children) newPmuxConfig(
|
func (c *Children) newPmuxConfig(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
garageRPCSecret, binDirPath string,
|
garageRPCSecret, binDirPath string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
garageAdminToken string,
|
garageAdminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
@ -21,7 +21,7 @@ func (c *Children) newPmuxConfig(
|
|||||||
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(
|
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(
|
||||||
c.runtimeDir.Path,
|
c.runtimeDir.Path,
|
||||||
binDirPath,
|
binDirPath,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
hostBootstrap,
|
hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -32,7 +32,7 @@ func (c *Children) newPmuxConfig(
|
|||||||
c.logger,
|
c.logger,
|
||||||
c.runtimeDir.Path,
|
c.runtimeDir.Path,
|
||||||
binDirPath,
|
binDirPath,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
hostBootstrap,
|
hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,7 +47,7 @@ func (c *Children) newPmuxConfig(
|
|||||||
garageRPCSecret,
|
garageRPCSecret,
|
||||||
c.runtimeDir.Path,
|
c.runtimeDir.Path,
|
||||||
binDirPath,
|
binDirPath,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
garageAdminToken,
|
garageAdminToken,
|
||||||
hostBootstrap,
|
hostBootstrap,
|
||||||
)
|
)
|
||||||
@ -68,7 +68,7 @@ func (c *Children) newPmuxConfig(
|
|||||||
|
|
||||||
func (c *Children) postPmuxInit(
|
func (c *Children) postPmuxInit(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
garageAdminToken string,
|
garageAdminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) error {
|
) error {
|
||||||
@ -79,7 +79,7 @@ func (c *Children) postPmuxInit(
|
|||||||
|
|
||||||
c.logger.Info(ctx, "Waiting for garage instances to come online")
|
c.logger.Info(ctx, "Waiting for garage instances to come online")
|
||||||
err := waitForGarage(
|
err := waitForGarage(
|
||||||
ctx, c.logger, networkConfig, garageAdminToken, hostBootstrap,
|
ctx, c.logger, daemonConfig, garageAdminToken, hostBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("waiting for garage to start: %w", err)
|
return fmt.Errorf("waiting for garage to start: %w", err)
|
||||||
|
@ -86,15 +86,6 @@ func (c *rpcClient) GetNebulaCAPublicCredentials(ctx context.Context) (c2 nebula
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rpcClient) GetNetworks(ctx context.Context) (ca1 []bootstrap.CreationParams, err error) {
|
|
||||||
err = c.client.Call(
|
|
||||||
ctx,
|
|
||||||
&ca1,
|
|
||||||
"GetNetworks",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *rpcClient) JoinNetwork(ctx context.Context, j1 network.JoiningBootstrap) (err error) {
|
func (c *rpcClient) JoinNetwork(ctx context.Context, j1 network.JoiningBootstrap) (err error) {
|
||||||
err = c.client.Call(
|
err = c.client.Call(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"isle/bootstrap"
|
|
||||||
"isle/daemon/daecommon"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
@ -42,26 +40,6 @@ var HTTPSocketPath = sync.OnceValue(func() string {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
func pickNetworkConfig(
|
|
||||||
daemonConfig daecommon.Config, creationParams bootstrap.CreationParams,
|
|
||||||
) (
|
|
||||||
daecommon.NetworkConfig, bool,
|
|
||||||
) {
|
|
||||||
if len(daemonConfig.Networks) == 1 { // DEPRECATED
|
|
||||||
if c, ok := daemonConfig.Networks[daecommon.DeprecatedNetworkID]; ok {
|
|
||||||
return c, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for searchStr, networkConfig := range daemonConfig.Networks {
|
|
||||||
if creationParams.Matches(searchStr) {
|
|
||||||
return networkConfig, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return daecommon.NetworkConfig{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Jigs
|
// Jigs
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package daemon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"isle/daemon/jsonrpc2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const metaKeyNetworkSearchStr = "daemon.networkSearchStr"
|
|
||||||
|
|
||||||
// WithNetwork returns the Context so that, when used against a daemon RPC
|
|
||||||
// endpoint, the endpoint knows which network is being targetted for the call.
|
|
||||||
// The network can be identified by its ID, name, or domain.
|
|
||||||
func WithNetwork(ctx context.Context, searchStr string) context.Context {
|
|
||||||
return jsonrpc2.WithMeta(ctx, metaKeyNetworkSearchStr, searchStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNetworkSearchStr(ctx context.Context) string {
|
|
||||||
v, _ := jsonrpc2.GetMeta(ctx)[metaKeyNetworkSearchStr].(string)
|
|
||||||
return v
|
|
||||||
}
|
|
@ -4,21 +4,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"isle/bootstrap"
|
"isle/bootstrap"
|
||||||
"isle/toolkit"
|
"isle/yamlutil"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/imdario/mergo"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// Network ID used when translating from the old single-network daemon
|
|
||||||
// config to the multi-network config.
|
|
||||||
DeprecatedNetworkID = "_" // DEPRECATED
|
|
||||||
)
|
|
||||||
|
|
||||||
func defaultConfigPath(appDirPath string) string {
|
func defaultConfigPath(appDirPath string) string {
|
||||||
return filepath.Join(appDirPath, "etc", "daemon.yml")
|
return filepath.Join(appDirPath, "etc", "daemon.yml")
|
||||||
}
|
}
|
||||||
@ -28,8 +22,16 @@ type ConfigTun struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFirewall struct {
|
type ConfigFirewall struct {
|
||||||
Outbound []ConfigFirewallRule `yaml:"outbound"`
|
Conntrack ConfigConntrack `yaml:"conntrack"`
|
||||||
Inbound []ConfigFirewallRule `yaml:"inbound"`
|
Outbound []ConfigFirewallRule `yaml:"outbound"`
|
||||||
|
Inbound []ConfigFirewallRule `yaml:"inbound"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigConntrack struct {
|
||||||
|
TCPTimeout string `yaml:"tcp_timeout"`
|
||||||
|
UDPTimeout string `yaml:"udp_timeout"`
|
||||||
|
DefaultTimeout string `yaml:"default_timeout"`
|
||||||
|
MaxConnections int `yaml:"max_connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFirewallRule struct {
|
type ConfigFirewallRule struct {
|
||||||
@ -59,8 +61,8 @@ type ConfigStorageAllocation struct {
|
|||||||
Zone string `yaml:"zone"`
|
Zone string `yaml:"zone"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkConfig describes the configuration of a single network.
|
// Config describes the structure of the daemon config file.
|
||||||
type NetworkConfig struct {
|
type Config struct {
|
||||||
DNS struct {
|
DNS struct {
|
||||||
Resolvers []string `yaml:"resolvers"`
|
Resolvers []string `yaml:"resolvers"`
|
||||||
} `yaml:"dns"`
|
} `yaml:"dns"`
|
||||||
@ -74,37 +76,7 @@ type NetworkConfig struct {
|
|||||||
} `yaml:"storage"`
|
} `yaml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NetworkConfig) fillDefaults() {
|
func (c *Config) fillDefaults() {
|
||||||
if c.DNS.Resolvers == nil {
|
|
||||||
c.DNS.Resolvers = []string{
|
|
||||||
"1.1.1.1",
|
|
||||||
"8.8.8.8",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.VPN.Firewall.Outbound == nil {
|
|
||||||
c.VPN.Firewall.Outbound = []ConfigFirewallRule{
|
|
||||||
{
|
|
||||||
Port: "any",
|
|
||||||
Proto: "any",
|
|
||||||
Host: "any",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.VPN.Firewall.Inbound == nil {
|
|
||||||
c.VPN.Firewall.Inbound = []ConfigFirewallRule{
|
|
||||||
{
|
|
||||||
Port: "any",
|
|
||||||
Proto: "icmp",
|
|
||||||
Host: "any",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.VPN.Tun.Device == "" {
|
|
||||||
c.VPN.Tun.Device = "isle-tun"
|
|
||||||
}
|
|
||||||
|
|
||||||
var firewallGarageInbound []ConfigFirewallRule
|
var firewallGarageInbound []ConfigFirewallRule
|
||||||
|
|
||||||
@ -144,40 +116,6 @@ func (c *NetworkConfig) fillDefaults() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config describes the structure of the daemon config file.
|
|
||||||
type Config struct {
|
|
||||||
Networks map[string]NetworkConfig `yaml:"networks"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate asserts that the Config has no internal inconsistencies which would
|
|
||||||
// render it unusable.
|
|
||||||
func (c Config) Validate() error {
|
|
||||||
nebulaPorts := map[string]string{}
|
|
||||||
|
|
||||||
for id, network := range c.Networks {
|
|
||||||
if network.VPN.PublicAddr == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, port, err := net.SplitHostPort(network.VPN.PublicAddr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"invalid vpn.public_addr %q: %w", network.VPN.PublicAddr, err,
|
|
||||||
)
|
|
||||||
} else if otherID, ok := nebulaPorts[port]; ok {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"two networks with the same vpn.public_addr: %q and %q",
|
|
||||||
id,
|
|
||||||
otherID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
nebulaPorts[port] = id
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyDefaultConfig copies the daemon config file embedded in the AppDir into
|
// CopyDefaultConfig copies the daemon config file embedded in the AppDir into
|
||||||
// the given io.Writer.
|
// the given io.Writer.
|
||||||
func CopyDefaultConfig(into io.Writer, appDirPath string) error {
|
func CopyDefaultConfig(into io.Writer, appDirPath string) error {
|
||||||
@ -198,45 +136,51 @@ func CopyDefaultConfig(into io.Writer, appDirPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads the daemon config from userConfigPath.
|
// LoadConfig loads the daemon config from userConfigPath, merges it with
|
||||||
|
// the default found in the appDirPath, and returns the result.
|
||||||
//
|
//
|
||||||
// If userConfigPath is not given then the default is loaded and returned.
|
// If userConfigPath is not given then the default is loaded and returned.
|
||||||
func LoadConfig(userConfigPath string) (Config, error) {
|
func LoadConfig(
|
||||||
if userConfigPath == "" {
|
appDirPath, userConfigPath string,
|
||||||
return Config{}, nil
|
) (
|
||||||
|
Config, error,
|
||||||
|
) {
|
||||||
|
|
||||||
|
defaultConfigPath := defaultConfigPath(appDirPath)
|
||||||
|
|
||||||
|
var fullDaemon map[string]interface{}
|
||||||
|
|
||||||
|
if err := yamlutil.LoadYamlFile(&fullDaemon, defaultConfigPath); err != nil {
|
||||||
|
return Config{}, fmt.Errorf("parsing default daemon config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
userConfigB, err := os.ReadFile(userConfigPath)
|
if userConfigPath != "" {
|
||||||
if err != nil {
|
|
||||||
return Config{}, fmt.Errorf("reading from file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // DEPRECATED
|
var daemonConfig map[string]interface{}
|
||||||
var networkConfig NetworkConfig
|
if err := yamlutil.LoadYamlFile(&daemonConfig, userConfigPath); err != nil {
|
||||||
_ = yaml.Unmarshal(userConfigB, &networkConfig)
|
return Config{}, fmt.Errorf("parsing %q: %w", userConfigPath, err)
|
||||||
if !toolkit.IsZero(networkConfig) {
|
}
|
||||||
networkConfig.fillDefaults()
|
|
||||||
config := Config{
|
err := mergo.Merge(&fullDaemon, daemonConfig, mergo.WithOverride)
|
||||||
Networks: map[string]NetworkConfig{
|
if err != nil {
|
||||||
DeprecatedNetworkID: networkConfig,
|
return Config{}, fmt.Errorf("merging contents of file %q: %w", userConfigPath, err)
|
||||||
},
|
|
||||||
}
|
|
||||||
return config, config.Validate()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fullDaemonB, err := yaml.Marshal(fullDaemon)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, fmt.Errorf("yaml marshaling: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
if err := yaml.Unmarshal(userConfigB, &config); err != nil {
|
if err := yaml.Unmarshal(fullDaemonB, &config); err != nil {
|
||||||
return Config{}, fmt.Errorf("yaml unmarshaling back into Config struct: %w", err)
|
return Config{}, fmt.Errorf("yaml unmarshaling back into Config struct: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for id := range config.Networks {
|
config.fillDefaults()
|
||||||
network := config.Networks[id]
|
|
||||||
network.fillDefaults()
|
|
||||||
config.Networks[id] = network
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, config.Validate()
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BootstrapGarageHostForAlloc returns the bootstrap.GarageHostInstance which
|
// BootstrapGarageHostForAlloc returns the bootstrap.GarageHostInstance which
|
||||||
|
@ -4,7 +4,6 @@ package daemon
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"isle/bootstrap"
|
"isle/bootstrap"
|
||||||
"isle/daemon/children"
|
"isle/daemon/children"
|
||||||
@ -12,7 +11,6 @@ import (
|
|||||||
"isle/daemon/network"
|
"isle/daemon/network"
|
||||||
"isle/nebula"
|
"isle/nebula"
|
||||||
"isle/toolkit"
|
"isle/toolkit"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||||
@ -66,8 +64,8 @@ type Daemon struct {
|
|||||||
networksStateDir toolkit.Dir
|
networksStateDir toolkit.Dir
|
||||||
networksRuntimeDir toolkit.Dir
|
networksRuntimeDir toolkit.Dir
|
||||||
|
|
||||||
l sync.RWMutex
|
l sync.RWMutex
|
||||||
networks map[string]network.Network
|
network network.Network
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initializes and returns a Daemon.
|
// New initializes and returns a Daemon.
|
||||||
@ -80,24 +78,11 @@ func New(
|
|||||||
) (
|
) (
|
||||||
*Daemon, error,
|
*Daemon, error,
|
||||||
) {
|
) {
|
||||||
opts = opts.withDefaults()
|
|
||||||
|
|
||||||
if err := migrateToMultiNetworkStateDirectory(
|
|
||||||
ctx,
|
|
||||||
logger.WithNamespace("migration-multi-network-state-dir"),
|
|
||||||
opts.EnvVars,
|
|
||||||
); err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"migrating to multi-network state directory: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
d := &Daemon{
|
d := &Daemon{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
daemonConfig: daemonConfig,
|
daemonConfig: daemonConfig,
|
||||||
envBinDirPath: envBinDirPath,
|
envBinDirPath: envBinDirPath,
|
||||||
opts: opts,
|
opts: opts.withDefaults(),
|
||||||
networks: map[string]network.Network{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -115,14 +100,18 @@ func New(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadableNetworks, err := loadableNetworks(d.networksStateDir)
|
loadableNetworks, err := LoadableNetworks(d.networksStateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("listing loadable networks: %w", err)
|
return nil, fmt.Errorf("listing loadable networks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, creationParams := range loadableNetworks {
|
if len(loadableNetworks) > 1 {
|
||||||
id := creationParams.ID
|
return nil, fmt.Errorf(
|
||||||
ctx = mctx.WithAnnotator(ctx, creationParams)
|
"more then one loadable Network found: %+v", loadableNetworks,
|
||||||
|
)
|
||||||
|
} else if len(loadableNetworks) == 1 {
|
||||||
|
id := loadableNetworks[0].ID
|
||||||
|
ctx = mctx.WithAnnotator(ctx, loadableNetworks[0])
|
||||||
|
|
||||||
networkStateDir, networkRuntimeDir, err := networkDirs(
|
networkStateDir, networkRuntimeDir, err := networkDirs(
|
||||||
d.networksStateDir, d.networksRuntimeDir, id, true,
|
d.networksStateDir, d.networksRuntimeDir, id, true,
|
||||||
@ -133,13 +122,11 @@ func New(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
networkConfig, _ := pickNetworkConfig(daemonConfig, creationParams)
|
d.network, err = network.Load(
|
||||||
|
|
||||||
d.networks[id], err = network.Load(
|
|
||||||
ctx,
|
ctx,
|
||||||
logger.WithNamespace("network"),
|
logger.WithNamespace("network"),
|
||||||
id,
|
id,
|
||||||
networkConfig,
|
d.daemonConfig,
|
||||||
d.envBinDirPath,
|
d.envBinDirPath,
|
||||||
networkStateDir,
|
networkStateDir,
|
||||||
networkRuntimeDir,
|
networkRuntimeDir,
|
||||||
@ -175,19 +162,10 @@ func (d *Daemon) CreateNetwork(
|
|||||||
creationParams := bootstrap.NewCreationParams(name, domain)
|
creationParams := bootstrap.NewCreationParams(name, domain)
|
||||||
ctx = mctx.WithAnnotator(ctx, creationParams)
|
ctx = mctx.WithAnnotator(ctx, creationParams)
|
||||||
|
|
||||||
networkConfig, ok := pickNetworkConfig(
|
|
||||||
d.daemonConfig, creationParams,
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("couldn't find network config for network being created")
|
|
||||||
}
|
|
||||||
|
|
||||||
d.l.Lock()
|
d.l.Lock()
|
||||||
defer d.l.Unlock()
|
defer d.l.Unlock()
|
||||||
|
|
||||||
if joined, err := alreadyJoined(ctx, d.networks, creationParams); err != nil {
|
if d.network != nil {
|
||||||
return fmt.Errorf("checking if already joined to network: %w", err)
|
|
||||||
} else if joined {
|
|
||||||
return ErrAlreadyJoined
|
return ErrAlreadyJoined
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +184,7 @@ func (d *Daemon) CreateNetwork(
|
|||||||
n, err := network.Create(
|
n, err := network.Create(
|
||||||
ctx,
|
ctx,
|
||||||
d.logger.WithNamespace("network"),
|
d.logger.WithNamespace("network"),
|
||||||
networkConfig,
|
d.daemonConfig,
|
||||||
d.envBinDirPath,
|
d.envBinDirPath,
|
||||||
networkStateDir,
|
networkStateDir,
|
||||||
networkRuntimeDir,
|
networkRuntimeDir,
|
||||||
@ -222,7 +200,7 @@ func (d *Daemon) CreateNetwork(
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.logger.Info(ctx, "Network created successfully")
|
d.logger.Info(ctx, "Network created successfully")
|
||||||
d.networks[creationParams.ID] = n
|
d.network = n
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,20 +212,13 @@ func (d *Daemon) CreateNetwork(
|
|||||||
func (d *Daemon) JoinNetwork(
|
func (d *Daemon) JoinNetwork(
|
||||||
ctx context.Context, newBootstrap network.JoiningBootstrap,
|
ctx context.Context, newBootstrap network.JoiningBootstrap,
|
||||||
) error {
|
) error {
|
||||||
var (
|
networkID := newBootstrap.Bootstrap.NetworkCreationParams.ID
|
||||||
creationParams = newBootstrap.Bootstrap.NetworkCreationParams
|
|
||||||
networkConfig, _ = pickNetworkConfig(d.daemonConfig, creationParams)
|
|
||||||
networkID = creationParams.ID
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx = mctx.WithAnnotator(ctx, newBootstrap.Bootstrap.NetworkCreationParams)
|
ctx = mctx.WithAnnotator(ctx, newBootstrap.Bootstrap.NetworkCreationParams)
|
||||||
|
|
||||||
d.l.Lock()
|
d.l.Lock()
|
||||||
defer d.l.Unlock()
|
defer d.l.Unlock()
|
||||||
|
|
||||||
if joined, err := alreadyJoined(ctx, d.networks, creationParams); err != nil {
|
if d.network != nil {
|
||||||
return fmt.Errorf("checking if already joined to network: %w", err)
|
|
||||||
} else if joined {
|
|
||||||
return ErrAlreadyJoined
|
return ErrAlreadyJoined
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +235,7 @@ func (d *Daemon) JoinNetwork(
|
|||||||
n, err := network.Join(
|
n, err := network.Join(
|
||||||
ctx,
|
ctx,
|
||||||
d.logger.WithNamespace("network"),
|
d.logger.WithNamespace("network"),
|
||||||
networkConfig,
|
d.daemonConfig,
|
||||||
newBootstrap,
|
newBootstrap,
|
||||||
d.envBinDirPath,
|
d.envBinDirPath,
|
||||||
networkStateDir,
|
networkStateDir,
|
||||||
@ -280,7 +251,7 @@ func (d *Daemon) JoinNetwork(
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.logger.Info(ctx, "Network joined successfully")
|
d.logger.Info(ctx, "Network joined successfully")
|
||||||
d.networks[networkID] = n
|
d.network = n
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,42 +265,12 @@ func withNetwork[Res any](
|
|||||||
d.l.RLock()
|
d.l.RLock()
|
||||||
defer d.l.RUnlock()
|
defer d.l.RUnlock()
|
||||||
|
|
||||||
network, err := pickNetwork(ctx, d.networks, d.networksStateDir)
|
if d.network == nil {
|
||||||
if err != nil {
|
|
||||||
var zero Res
|
var zero Res
|
||||||
return zero, nil
|
return zero, ErrNoNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(ctx, network)
|
return fn(ctx, d.network)
|
||||||
}
|
|
||||||
|
|
||||||
// GetNetworks returns all networks which have been joined by the Daemon,
|
|
||||||
// ordered by their name.
|
|
||||||
func (d *Daemon) GetNetworks(
|
|
||||||
ctx context.Context,
|
|
||||||
) (
|
|
||||||
[]bootstrap.CreationParams, error,
|
|
||||||
) {
|
|
||||||
d.l.RLock()
|
|
||||||
defer d.l.RUnlock()
|
|
||||||
|
|
||||||
res := make([]bootstrap.CreationParams, 0, len(d.networks))
|
|
||||||
for id, network := range d.networks {
|
|
||||||
creationParams, err := network.GetNetworkCreationParams(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"getting network creation params of network %q: %w", id, err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
res = append(res, creationParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(res, func(i, j int) bool {
|
|
||||||
return res[i].Name < res[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHost implements the method for the network.RPC interface.
|
// GetHost implements the method for the network.RPC interface.
|
||||||
@ -449,28 +390,32 @@ func (d *Daemon) Shutdown() error {
|
|||||||
d.l.Lock()
|
d.l.Lock()
|
||||||
defer d.l.Unlock()
|
defer d.l.Unlock()
|
||||||
|
|
||||||
var (
|
if d.network != nil {
|
||||||
errCh = make(chan error, len(d.networks))
|
return d.network.Shutdown()
|
||||||
errs []error
|
|
||||||
)
|
|
||||||
|
|
||||||
for id := range d.networks {
|
|
||||||
var (
|
|
||||||
id = id
|
|
||||||
n = d.networks[id]
|
|
||||||
)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := n.Shutdown(); err != nil {
|
|
||||||
errCh <- fmt.Errorf("shutting down network %q: %w", id, err)
|
|
||||||
}
|
|
||||||
errCh <- nil
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
for range cap(errCh) {
|
//var (
|
||||||
errs = append(errs, <-errCh)
|
// errCh = make(chan error, len(d.networks))
|
||||||
}
|
// errs []error
|
||||||
|
//)
|
||||||
|
|
||||||
return errors.Join(errs...)
|
//for id := range d.networks {
|
||||||
|
// id := id
|
||||||
|
// n := d.networks[id]
|
||||||
|
// go func() {
|
||||||
|
// if err := n.Shutdown(); err != nil {
|
||||||
|
// errCh <- fmt.Errorf("shutting down network %q: %w", id, err)
|
||||||
|
// }
|
||||||
|
// errCh <- nil
|
||||||
|
// }()
|
||||||
|
//}
|
||||||
|
|
||||||
|
//for range cap(errCh) {
|
||||||
|
// if err := <-errCh; err != nil {
|
||||||
|
// errs = append(errs, err)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
errCodeNoNetwork = daecommon.ErrorCodeRangeDaemon + iota
|
errCodeNoNetwork = daecommon.ErrorCodeRangeDaemon + iota
|
||||||
errCodeAlreadyJoined
|
errCodeAlreadyJoined
|
||||||
errCodeNoMatchingNetworks
|
|
||||||
errCodeMultipleMatchingNetworks
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,19 +16,6 @@ var (
|
|||||||
ErrNoNetwork = jsonrpc2.NewError(errCodeNoNetwork, "No network configured")
|
ErrNoNetwork = jsonrpc2.NewError(errCodeNoNetwork, "No network configured")
|
||||||
|
|
||||||
// ErrAlreadyJoined is returned when the daemon is instructed to create or
|
// ErrAlreadyJoined is returned when the daemon is instructed to create or
|
||||||
// join a new network, but it is already joined to that network.
|
// join a new network, but it is already joined to a network.
|
||||||
ErrAlreadyJoined = jsonrpc2.NewError(errCodeAlreadyJoined, "Already joined to a network")
|
ErrAlreadyJoined = jsonrpc2.NewError(errCodeAlreadyJoined, "Already joined to a network")
|
||||||
|
|
||||||
// ErrNoMatchingNetworks is returned if the search string didn't match any
|
|
||||||
// networks.
|
|
||||||
ErrNoMatchingNetworks = jsonrpc2.NewError(
|
|
||||||
errCodeNoMatchingNetworks, "No networks matched the search string",
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrMultipleMatchingNetworks is returned if the search string matched
|
|
||||||
// multiple networks.
|
|
||||||
ErrMultipleMatchingNetworks = jsonrpc2.NewError(
|
|
||||||
errCodeMultipleMatchingNetworks,
|
|
||||||
"Multiple networks matched the search string",
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
@ -13,11 +13,7 @@ type Client interface {
|
|||||||
// receiver pointer, unless it is nil in which case the result will be
|
// receiver pointer, unless it is nil in which case the result will be
|
||||||
// discarded.
|
// discarded.
|
||||||
//
|
//
|
||||||
// If the Context was produced using WithMeta then that metadata will be
|
|
||||||
// carried with the request to the server via the Meta field of the
|
|
||||||
// RequestParams.
|
|
||||||
//
|
|
||||||
// If an error result is returned from the server that will be returned as
|
// If an error result is returned from the server that will be returned as
|
||||||
// an Error struct.
|
// an Error struct.
|
||||||
Call(ctx context.Context, rcv any, method string, args ...any) error
|
Call(ctx context.Context, rcv any, method string, params ...any) error
|
||||||
}
|
}
|
||||||
|
@ -49,14 +49,14 @@ func NewUnixHTTPClient(unixSocketPath, reqPath string) Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Call(
|
func (c *httpClient) Call(
|
||||||
ctx context.Context, rcv any, method string, args ...any,
|
ctx context.Context, rcv any, method string, params ...any,
|
||||||
) error {
|
) error {
|
||||||
var (
|
var (
|
||||||
body = new(bytes.Buffer)
|
body = new(bytes.Buffer)
|
||||||
enc = json.NewEncoder(body)
|
enc = json.NewEncoder(body)
|
||||||
)
|
)
|
||||||
|
|
||||||
id, err := encodeRequest(ctx, enc, method, args)
|
id, err := encodeRequest(enc, method, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("encoding request: %w", err)
|
return fmt.Errorf("encoding request: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ func NewReadWriterClient(rw io.ReadWriter) Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c rwClient) Call(
|
func (c rwClient) Call(
|
||||||
ctx context.Context, rcv any, method string, args ...any,
|
ctx context.Context, rcv any, method string, params ...any,
|
||||||
) error {
|
) error {
|
||||||
id, err := encodeRequest(ctx, c.enc, method, args)
|
id, err := encodeRequest(c.enc, method, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("encoding request: %w", err)
|
return fmt.Errorf("encoding request: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -18,21 +18,19 @@ type methodDispatchFunc func(context.Context, Request) (any, error)
|
|||||||
func newMethodDispatchFunc(
|
func newMethodDispatchFunc(
|
||||||
method reflect.Value,
|
method reflect.Value,
|
||||||
) methodDispatchFunc {
|
) methodDispatchFunc {
|
||||||
argTs := make([]reflect.Type, method.Type().NumIn()-1)
|
paramTs := make([]reflect.Type, method.Type().NumIn()-1)
|
||||||
for i := range argTs {
|
for i := range paramTs {
|
||||||
argTs[i] = method.Type().In(i + 1)
|
paramTs[i] = method.Type().In(i + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx context.Context, req Request) (any, error) {
|
return func(ctx context.Context, req Request) (any, error) {
|
||||||
ctx = context.WithValue(ctx, ctxKeyMeta(0), req.Params.Meta)
|
callVals := make([]reflect.Value, 0, len(paramTs)+1)
|
||||||
|
|
||||||
callVals := make([]reflect.Value, 0, len(argTs)+1)
|
|
||||||
callVals = append(callVals, reflect.ValueOf(ctx))
|
callVals = append(callVals, reflect.ValueOf(ctx))
|
||||||
|
|
||||||
for i, argT := range argTs {
|
for i, paramT := range paramTs {
|
||||||
argPtrV := reflect.New(argT)
|
paramPtrV := reflect.New(paramT)
|
||||||
|
|
||||||
err := json.Unmarshal(req.Params.Args[i], argPtrV.Interface())
|
err := json.Unmarshal(req.Params[i], paramPtrV.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// The JSON has already been validated, so this is not an
|
// The JSON has already been validated, so this is not an
|
||||||
// errCodeParse situation. We assume it's an invalid param then,
|
// errCodeParse situation. We assume it's an invalid param then,
|
||||||
@ -40,13 +38,13 @@ func newMethodDispatchFunc(
|
|||||||
// returning an Error of its own.
|
// returning an Error of its own.
|
||||||
if !errors.As(err, new(Error)) {
|
if !errors.As(err, new(Error)) {
|
||||||
err = NewInvalidParamsError(
|
err = NewInvalidParamsError(
|
||||||
"JSON unmarshaling arg %d into %T: %v", i, argT, err,
|
"JSON unmarshaling param %d into %T: %v", i, paramT, err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
callVals = append(callVals, argPtrV.Elem())
|
callVals = append(callVals, paramPtrV.Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -84,8 +82,7 @@ type dispatcher struct {
|
|||||||
// MethodName(context.Context, ...ParamType) (ResponseType, error)
|
// MethodName(context.Context, ...ParamType) (ResponseType, error)
|
||||||
// MethodName(context.Context, ...ParamType) error
|
// MethodName(context.Context, ...ParamType) error
|
||||||
//
|
//
|
||||||
// will be available via RPC calls. Any Meta data in the request can be obtained
|
// will be available via RPC calls.
|
||||||
// within the method handler by calling GetMeta on the method's Context.
|
|
||||||
func NewDispatchHandler(i any) Handler {
|
func NewDispatchHandler(i any) Handler {
|
||||||
v := reflect.ValueOf(i)
|
v := reflect.ValueOf(i)
|
||||||
if v.Kind() != reflect.Pointer {
|
if v.Kind() != reflect.Pointer {
|
||||||
|
@ -57,16 +57,15 @@ func NewMLogMiddleware(logger *mlog.Logger) Middleware {
|
|||||||
ctx,
|
ctx,
|
||||||
"rpcRequestID", req.ID,
|
"rpcRequestID", req.ID,
|
||||||
"rpcRequestMethod", req.Method,
|
"rpcRequestMethod", req.Method,
|
||||||
"rpcRequestMeta", req.Params.Meta,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if logger.MaxLevel() >= mlog.LevelDebug.Int() {
|
if logger.MaxLevel() >= mlog.LevelDebug.Int() {
|
||||||
ctx := ctx
|
ctx := ctx
|
||||||
for i := range req.Params.Args {
|
for i := range req.Params {
|
||||||
ctx = mctx.Annotate(
|
ctx = mctx.Annotate(
|
||||||
ctx,
|
ctx,
|
||||||
fmt.Sprintf("rpcRequestArgs%d", i),
|
fmt.Sprintf("rpcRequestParam%d", i),
|
||||||
string(req.Params.Args[i]),
|
string(req.Params[i]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
logger.Debug(ctx, "Handling RPC request")
|
logger.Debug(ctx, "Handling RPC request")
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package jsonrpc2
|
package jsonrpc2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -12,20 +11,12 @@ import (
|
|||||||
|
|
||||||
const version = "2.0"
|
const version = "2.0"
|
||||||
|
|
||||||
// RequestParams are the parameters passed in a Request. Meta contains
|
|
||||||
// information that is not directly related to what is being requested, while
|
|
||||||
// Args are the request's actual arguments.
|
|
||||||
type RequestParams struct {
|
|
||||||
Meta map[string]any `json:"meta,omitempty"`
|
|
||||||
Args []json.RawMessage `json:"args,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request encodes an RPC request according to the spec.
|
// Request encodes an RPC request according to the spec.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
Version string `json:"jsonrpc"` // must be "2.0"
|
Version string `json:"jsonrpc"` // must be "2.0"
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Params RequestParams `json:"params,omitempty"`
|
Params []json.RawMessage `json:"params,omitempty"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type response[Result any] struct {
|
type response[Result any] struct {
|
||||||
@ -46,18 +37,18 @@ func newID() string {
|
|||||||
// encodeRequest writes a request to an io.Writer, returning the ID of the
|
// encodeRequest writes a request to an io.Writer, returning the ID of the
|
||||||
// request.
|
// request.
|
||||||
func encodeRequest(
|
func encodeRequest(
|
||||||
ctx context.Context, enc *json.Encoder, method string, args []any,
|
enc *json.Encoder, method string, params []any,
|
||||||
) (
|
) (
|
||||||
string, error,
|
string, error,
|
||||||
) {
|
) {
|
||||||
var (
|
var (
|
||||||
argsBs = make([]json.RawMessage, len(args))
|
paramsBs = make([]json.RawMessage, len(params))
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for i := range args {
|
for i := range params {
|
||||||
argsBs[i], err = json.Marshal(args[i])
|
paramsBs[i], err = json.Marshal(params[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("encoding arg %d as JSON: %w", i, err)
|
return "", fmt.Errorf("encoding param %d as JSON: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +57,8 @@ func encodeRequest(
|
|||||||
reqEnvelope = Request{
|
reqEnvelope = Request{
|
||||||
Version: version,
|
Version: version,
|
||||||
Method: method,
|
Method: method,
|
||||||
Params: RequestParams{
|
Params: paramsBs,
|
||||||
Meta: GetMeta(ctx),
|
ID: id,
|
||||||
Args: argsBs,
|
|
||||||
},
|
|
||||||
ID: id,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,16 +48,6 @@ func (i dividerImpl) Noop(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i dividerImpl) Divide2FromMeta(ctx context.Context) (int, error) {
|
|
||||||
var (
|
|
||||||
meta = GetMeta(ctx)
|
|
||||||
top = int(meta["top"].(float64))
|
|
||||||
bottom = int(meta["bottom"].(float64))
|
|
||||||
)
|
|
||||||
|
|
||||||
return i.Divide2(ctx, top, bottom)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dividerImpl) Hidden(ctx context.Context, p struct{}) (int, error) {
|
func (dividerImpl) Hidden(ctx context.Context, p struct{}) (int, error) {
|
||||||
return 0, errors.New("Shouldn't be possible to call this!")
|
return 0, errors.New("Shouldn't be possible to call this!")
|
||||||
}
|
}
|
||||||
@ -67,7 +57,6 @@ type divider interface {
|
|||||||
Divide(ctx context.Context, p DivideParams) (int, error)
|
Divide(ctx context.Context, p DivideParams) (int, error)
|
||||||
One(ctx context.Context) (int, error)
|
One(ctx context.Context) (int, error)
|
||||||
Noop(ctx context.Context) error
|
Noop(ctx context.Context) error
|
||||||
Divide2FromMeta(ctx context.Context) (int, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var testHandler = func() Handler {
|
var testHandler = func() Handler {
|
||||||
@ -135,19 +124,6 @@ func testClient(t *testing.T, client Client) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("success/meta", func(t *testing.T) {
|
|
||||||
ctx = WithMeta(ctx, "top", 6)
|
|
||||||
ctx = WithMeta(ctx, "bottom", 2)
|
|
||||||
|
|
||||||
var res int
|
|
||||||
err := client.Call(ctx, &res, "Divide2FromMeta")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if res != 3 {
|
|
||||||
t.Fatalf("expected 2, got %d", res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("err/application", func(t *testing.T) {
|
t.Run("err/application", func(t *testing.T) {
|
||||||
err := client.Call(ctx, nil, "Divide", DivideParams{})
|
err := client.Call(ctx, nil, "Divide", DivideParams{})
|
||||||
if !errors.Is(err, ErrDivideByZero) {
|
if !errors.Is(err, ErrDivideByZero) {
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package jsonrpc2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ctxKeyMeta int
|
|
||||||
|
|
||||||
// WithMeta returns a Context where the given key will be set to the given value
|
|
||||||
// in the Meta field of all JSONRPC2 requests made using Clients from this
|
|
||||||
// package.
|
|
||||||
func WithMeta(ctx context.Context, key string, value any) context.Context {
|
|
||||||
m, _ := ctx.Value(ctxKeyMeta(0)).(map[string]any)
|
|
||||||
if m == nil {
|
|
||||||
m = map[string]any{}
|
|
||||||
} else {
|
|
||||||
m = maps.Clone(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
m[key] = value
|
|
||||||
return context.WithValue(ctx, ctxKeyMeta(0), m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMeta returns all key/values which have been set on the Context using
|
|
||||||
// WithMeta. This may return nil if WithMeta was never called.
|
|
||||||
func GetMeta(ctx context.Context) map[string]any {
|
|
||||||
m, _ := ctx.Value(ctxKeyMeta(0)).(map[string]any)
|
|
||||||
return m
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package daemon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"isle/daemon/daecommon"
|
|
||||||
"isle/jsonutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
|
||||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
func migrateToMultiNetworkStateDirectory(
|
|
||||||
ctx context.Context, logger *mlog.Logger, envVars daecommon.EnvVars,
|
|
||||||
) error {
|
|
||||||
var (
|
|
||||||
legacyBootstrapPath = filepath.Join(
|
|
||||||
envVars.StateDir.Path, "bootstrap.json",
|
|
||||||
)
|
|
||||||
legacySecretsPath = filepath.Join(envVars.StateDir.Path, "secrets")
|
|
||||||
)
|
|
||||||
|
|
||||||
if _, err := os.Stat(legacyBootstrapPath); errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return nil // no bootstrap in the legacy path
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("checking file %q: %w", legacyBootstrapPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bootstrapBody struct {
|
|
||||||
NetworkCreationParams struct {
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := jsonutil.LoadFile(
|
|
||||||
&bootstrapBody, legacyBootstrapPath,
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"loading bootstrap from %q: %w", legacyBootstrapPath, err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
networkStateDirPath = filepath.Join(
|
|
||||||
envVars.StateDir.Path,
|
|
||||||
"networks",
|
|
||||||
bootstrapBody.NetworkCreationParams.ID,
|
|
||||||
)
|
|
||||||
|
|
||||||
newBootstrapPath = filepath.Join(networkStateDirPath, "bootstrap.json")
|
|
||||||
newSecretsPath = filepath.Join(networkStateDirPath, "secrets")
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx = mctx.Annotate(
|
|
||||||
ctx,
|
|
||||||
"legacyBootstrapPath", legacyBootstrapPath,
|
|
||||||
"legacySecretsPath", legacySecretsPath,
|
|
||||||
"newBootstrapPath", newBootstrapPath,
|
|
||||||
"newSecretsPath", newSecretsPath,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.Info(ctx, "Migrating to multi-network state directory layout")
|
|
||||||
|
|
||||||
if err := os.MkdirAll(networkStateDirPath, 0700); err != nil {
|
|
||||||
return fmt.Errorf("creating %q: %w", networkStateDirPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(legacyBootstrapPath, newBootstrapPath); err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"renaming %q to %q: %w", legacyBootstrapPath, newBootstrapPath, err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(legacySecretsPath, newSecretsPath); err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"renaming %q to %q: %w", legacySecretsPath, newSecretsPath, err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"isle/bootstrap"
|
"isle/bootstrap"
|
||||||
"isle/daemon/network"
|
"isle/daemon/network"
|
||||||
@ -42,9 +41,9 @@ func networkDirs(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadableNetworks returns the CreationParams for each Network which is able to
|
// LoadableNetworks returns the CreationParams for each Network which is able to
|
||||||
// be loaded.
|
// be loaded.
|
||||||
func loadableNetworks(
|
func LoadableNetworks(
|
||||||
networksStateDir toolkit.Dir,
|
networksStateDir toolkit.Dir,
|
||||||
) (
|
) (
|
||||||
[]bootstrap.CreationParams, error,
|
[]bootstrap.CreationParams, error,
|
||||||
@ -72,60 +71,3 @@ func loadableNetworks(
|
|||||||
|
|
||||||
return creationParams, nil
|
return creationParams, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pickNetwork(
|
|
||||||
ctx context.Context,
|
|
||||||
networks map[string]network.Network,
|
|
||||||
networksStateDir toolkit.Dir,
|
|
||||||
) (
|
|
||||||
network.Network, error,
|
|
||||||
) {
|
|
||||||
if len(networks) == 0 {
|
|
||||||
return nil, ErrNoNetwork
|
|
||||||
}
|
|
||||||
|
|
||||||
creationParams, err := loadableNetworks(networksStateDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("getting loadable networks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
networkSearchStr = getNetworkSearchStr(ctx)
|
|
||||||
matchingNetworkIDs = make([]string, 0, len(networks))
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, creationParam := range creationParams {
|
|
||||||
if networkSearchStr == "" || creationParam.Matches(networkSearchStr) {
|
|
||||||
matchingNetworkIDs = append(matchingNetworkIDs, creationParam.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(matchingNetworkIDs) == 0 {
|
|
||||||
return nil, ErrNoMatchingNetworks
|
|
||||||
} else if len(matchingNetworkIDs) > 1 {
|
|
||||||
return nil, ErrMultipleMatchingNetworks
|
|
||||||
}
|
|
||||||
|
|
||||||
return networks[matchingNetworkIDs[0]], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func alreadyJoined(
|
|
||||||
ctx context.Context,
|
|
||||||
networks map[string]network.Network,
|
|
||||||
creationParams bootstrap.CreationParams,
|
|
||||||
) (
|
|
||||||
bool, error,
|
|
||||||
) {
|
|
||||||
for networkID, network := range networks {
|
|
||||||
existingCreationParams, err := network.GetNetworkCreationParams(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf(
|
|
||||||
"getting creation params of network %q: %w", networkID, err,
|
|
||||||
)
|
|
||||||
} else if existingCreationParams.Conflicts(creationParams) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
@ -29,8 +29,8 @@ func writeBootstrapToStateDir(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func coalesceNetworkConfigAndBootstrap(
|
func coalesceDaemonConfigAndBootstrap(
|
||||||
networkConfig daecommon.NetworkConfig, hostBootstrap bootstrap.Bootstrap,
|
daemonConfig daecommon.Config, hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
bootstrap.Bootstrap, error,
|
bootstrap.Bootstrap, error,
|
||||||
) {
|
) {
|
||||||
@ -38,12 +38,12 @@ func coalesceNetworkConfigAndBootstrap(
|
|||||||
HostAssigned: hostBootstrap.HostAssigned,
|
HostAssigned: hostBootstrap.HostAssigned,
|
||||||
HostConfigured: bootstrap.HostConfigured{
|
HostConfigured: bootstrap.HostConfigured{
|
||||||
Nebula: bootstrap.NebulaHost{
|
Nebula: bootstrap.NebulaHost{
|
||||||
PublicAddr: networkConfig.VPN.PublicAddr,
|
PublicAddr: daemonConfig.VPN.PublicAddr,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if allocs := networkConfig.Storage.Allocations; len(allocs) > 0 {
|
if allocs := daemonConfig.Storage.Allocations; len(allocs) > 0 {
|
||||||
|
|
||||||
for i, alloc := range allocs {
|
for i, alloc := range allocs {
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ func garageAdminClientLogger(logger *mlog.Logger) *mlog.Logger {
|
|||||||
// or it will _panic_ if there is no local instance configured.
|
// or it will _panic_ if there is no local instance configured.
|
||||||
func newGarageAdminClient(
|
func newGarageAdminClient(
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
adminToken string,
|
adminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) *garage.AdminClient {
|
) *garage.AdminClient {
|
||||||
@ -68,7 +68,7 @@ func newGarageAdminClient(
|
|||||||
garageAdminClientLogger(logger),
|
garageAdminClientLogger(logger),
|
||||||
net.JoinHostPort(
|
net.JoinHostPort(
|
||||||
thisHost.IP().String(),
|
thisHost.IP().String(),
|
||||||
strconv.Itoa(networkConfig.Storage.Allocations[0].AdminPort),
|
strconv.Itoa(daemonConfig.Storage.Allocations[0].AdminPort),
|
||||||
),
|
),
|
||||||
adminToken,
|
adminToken,
|
||||||
)
|
)
|
||||||
@ -77,18 +77,18 @@ func newGarageAdminClient(
|
|||||||
func garageApplyLayout(
|
func garageApplyLayout(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
adminToken string,
|
adminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
adminClient = newGarageAdminClient(
|
adminClient = newGarageAdminClient(
|
||||||
logger, networkConfig, adminToken, hostBootstrap,
|
logger, daemonConfig, adminToken, hostBootstrap,
|
||||||
)
|
)
|
||||||
thisHost = hostBootstrap.ThisHost()
|
thisHost = hostBootstrap.ThisHost()
|
||||||
hostName = thisHost.Name
|
hostName = thisHost.Name
|
||||||
allocs = networkConfig.Storage.Allocations
|
allocs = daemonConfig.Storage.Allocations
|
||||||
peers = make([]garage.PeerLayout, len(allocs))
|
peers = make([]garage.PeerLayout, len(allocs))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,14 +115,14 @@ func garageApplyLayout(
|
|||||||
func garageInitializeGlobalBucket(
|
func garageInitializeGlobalBucket(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
adminToken string,
|
adminToken string,
|
||||||
hostBootstrap bootstrap.Bootstrap,
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
garage.S3APICredentials, error,
|
garage.S3APICredentials, error,
|
||||||
) {
|
) {
|
||||||
adminClient := newGarageAdminClient(
|
adminClient := newGarageAdminClient(
|
||||||
logger, networkConfig, adminToken, hostBootstrap,
|
logger, daemonConfig, adminToken, hostBootstrap,
|
||||||
)
|
)
|
||||||
|
|
||||||
creds, err := adminClient.CreateS3APICredentials(
|
creds, err := adminClient.CreateS3APICredentials(
|
||||||
|
14
go/daemon/network/jigs.go
Normal file
14
go/daemon/network/jigs.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func randStr(l int) string {
|
||||||
|
b := make([]byte, l)
|
||||||
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(b)
|
||||||
|
}
|
@ -18,6 +18,7 @@ import (
|
|||||||
"isle/nebula"
|
"isle/nebula"
|
||||||
"isle/secrets"
|
"isle/secrets"
|
||||||
"isle/toolkit"
|
"isle/toolkit"
|
||||||
|
"log"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
@ -152,8 +153,8 @@ func (o *Opts) withDefaults() *Opts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type network struct {
|
type network struct {
|
||||||
logger *mlog.Logger
|
logger *mlog.Logger
|
||||||
networkConfig daecommon.NetworkConfig
|
daemonConfig daecommon.Config
|
||||||
|
|
||||||
envBinDirPath string
|
envBinDirPath string
|
||||||
stateDir toolkit.Dir
|
stateDir toolkit.Dir
|
||||||
@ -177,20 +178,21 @@ type network struct {
|
|||||||
func instatiateNetwork(
|
func instatiateNetwork(
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkID string,
|
networkID string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
stateDir toolkit.Dir,
|
stateDir toolkit.Dir,
|
||||||
runtimeDir toolkit.Dir,
|
runtimeDir toolkit.Dir,
|
||||||
opts *Opts,
|
opts *Opts,
|
||||||
) *network {
|
) *network {
|
||||||
|
log.Printf("DEBUG: network stateDir:%+v runtimeDir:%+v", stateDir, runtimeDir)
|
||||||
return &network{
|
return &network{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
networkConfig: networkConfig,
|
daemonConfig: daemonConfig,
|
||||||
envBinDirPath: envBinDirPath,
|
envBinDirPath: envBinDirPath,
|
||||||
stateDir: stateDir,
|
stateDir: stateDir,
|
||||||
runtimeDir: runtimeDir,
|
runtimeDir: runtimeDir,
|
||||||
opts: opts.withDefaults(),
|
opts: opts.withDefaults(),
|
||||||
garageAdminToken: toolkit.RandStr(32),
|
garageAdminToken: randStr(32),
|
||||||
shutdownCh: make(chan struct{}),
|
shutdownCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +227,7 @@ func Load(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkID string,
|
networkID string,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
stateDir toolkit.Dir,
|
stateDir toolkit.Dir,
|
||||||
runtimeDir toolkit.Dir,
|
runtimeDir toolkit.Dir,
|
||||||
@ -236,7 +238,7 @@ func Load(
|
|||||||
n := instatiateNetwork(
|
n := instatiateNetwork(
|
||||||
logger,
|
logger,
|
||||||
networkID,
|
networkID,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
envBinDirPath,
|
envBinDirPath,
|
||||||
stateDir,
|
stateDir,
|
||||||
runtimeDir,
|
runtimeDir,
|
||||||
@ -270,7 +272,7 @@ func Load(
|
|||||||
func Join(
|
func Join(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
joiningBootstrap JoiningBootstrap,
|
joiningBootstrap JoiningBootstrap,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
stateDir toolkit.Dir,
|
stateDir toolkit.Dir,
|
||||||
@ -282,7 +284,7 @@ func Join(
|
|||||||
n := instatiateNetwork(
|
n := instatiateNetwork(
|
||||||
logger,
|
logger,
|
||||||
joiningBootstrap.Bootstrap.NetworkCreationParams.ID,
|
joiningBootstrap.Bootstrap.NetworkCreationParams.ID,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
envBinDirPath,
|
envBinDirPath,
|
||||||
stateDir,
|
stateDir,
|
||||||
runtimeDir,
|
runtimeDir,
|
||||||
@ -322,7 +324,7 @@ func Join(
|
|||||||
func Create(
|
func Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
networkConfig daecommon.NetworkConfig,
|
daemonConfig daecommon.Config,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
stateDir toolkit.Dir,
|
stateDir toolkit.Dir,
|
||||||
runtimeDir toolkit.Dir,
|
runtimeDir toolkit.Dir,
|
||||||
@ -333,7 +335,7 @@ func Create(
|
|||||||
) (
|
) (
|
||||||
Network, error,
|
Network, error,
|
||||||
) {
|
) {
|
||||||
if len(networkConfig.Storage.Allocations) < 3 {
|
if len(daemonConfig.Storage.Allocations) < 3 {
|
||||||
return nil, ErrInvalidConfig.WithData(
|
return nil, ErrInvalidConfig.WithData(
|
||||||
"At least three storage allocations are required.",
|
"At least three storage allocations are required.",
|
||||||
)
|
)
|
||||||
@ -344,12 +346,12 @@ func Create(
|
|||||||
return nil, fmt.Errorf("creating nebula CA cert: %w", err)
|
return nil, fmt.Errorf("creating nebula CA cert: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
garageRPCSecret := toolkit.RandStr(32)
|
garageRPCSecret := randStr(32)
|
||||||
|
|
||||||
n := instatiateNetwork(
|
n := instatiateNetwork(
|
||||||
logger,
|
logger,
|
||||||
creationParams.ID,
|
creationParams.ID,
|
||||||
networkConfig,
|
daemonConfig,
|
||||||
envBinDirPath,
|
envBinDirPath,
|
||||||
stateDir,
|
stateDir,
|
||||||
runtimeDir,
|
runtimeDir,
|
||||||
@ -407,8 +409,8 @@ func (n *network) initialize(
|
|||||||
// by the daemon config. This way the network has the most up-to-date
|
// by the daemon config. This way the network has the most up-to-date
|
||||||
// possible bootstrap. This updated bootstrap will later get updated in
|
// possible bootstrap. This updated bootstrap will later get updated in
|
||||||
// garage as a background task, so other hosts will see it as well.
|
// garage as a background task, so other hosts will see it as well.
|
||||||
currBootstrap, err := coalesceNetworkConfigAndBootstrap(
|
currBootstrap, err := coalesceDaemonConfigAndBootstrap(
|
||||||
n.networkConfig, currBootstrap,
|
n.daemonConfig, currBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("combining configuration into bootstrap: %w", err)
|
return fmt.Errorf("combining configuration into bootstrap: %w", err)
|
||||||
@ -427,7 +429,7 @@ func (n *network) initialize(
|
|||||||
n.logger.WithNamespace("children"),
|
n.logger.WithNamespace("children"),
|
||||||
n.envBinDirPath,
|
n.envBinDirPath,
|
||||||
n.secretsStore,
|
n.secretsStore,
|
||||||
n.networkConfig,
|
n.daemonConfig,
|
||||||
n.runtimeDir,
|
n.runtimeDir,
|
||||||
n.garageAdminToken,
|
n.garageAdminToken,
|
||||||
currBootstrap,
|
currBootstrap,
|
||||||
@ -465,10 +467,10 @@ func (n *network) initialize(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) postInit(ctx context.Context) error {
|
func (n *network) postInit(ctx context.Context) error {
|
||||||
if len(n.networkConfig.Storage.Allocations) > 0 {
|
if len(n.daemonConfig.Storage.Allocations) > 0 {
|
||||||
n.logger.Info(ctx, "Applying garage layout")
|
n.logger.Info(ctx, "Applying garage layout")
|
||||||
if err := garageApplyLayout(
|
if err := garageApplyLayout(
|
||||||
ctx, n.logger, n.networkConfig, n.garageAdminToken, n.currBootstrap,
|
ctx, n.logger, n.daemonConfig, n.garageAdminToken, n.currBootstrap,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("applying garage layout: %w", err)
|
return fmt.Errorf("applying garage layout: %w", err)
|
||||||
}
|
}
|
||||||
@ -487,7 +489,7 @@ func (n *network) postInit(ctx context.Context) error {
|
|||||||
garageGlobalBucketCreds, err := garageInitializeGlobalBucket(
|
garageGlobalBucketCreds, err := garageInitializeGlobalBucket(
|
||||||
ctx,
|
ctx,
|
||||||
n.logger,
|
n.logger,
|
||||||
n.networkConfig,
|
n.daemonConfig,
|
||||||
n.garageAdminToken,
|
n.garageAdminToken,
|
||||||
n.currBootstrap,
|
n.currBootstrap,
|
||||||
)
|
)
|
||||||
@ -566,7 +568,7 @@ func (n *network) reload(
|
|||||||
newBootstrap.Hosts[thisHost.Name] = thisHost
|
newBootstrap.Hosts[thisHost.Name] = thisHost
|
||||||
|
|
||||||
diff, err := children.CalculateReloadDiff(
|
diff, err := children.CalculateReloadDiff(
|
||||||
n.networkConfig, currBootstrap, newBootstrap,
|
n.daemonConfig, currBootstrap, newBootstrap,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calculating diff between bootstraps: %w", err)
|
return fmt.Errorf("calculating diff between bootstraps: %w", err)
|
||||||
|
@ -2,7 +2,6 @@ package daemon
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"isle/bootstrap"
|
|
||||||
"isle/daemon/jsonrpc2"
|
"isle/daemon/jsonrpc2"
|
||||||
"isle/daemon/network"
|
"isle/daemon/network"
|
||||||
"isle/nebula"
|
"isle/nebula"
|
||||||
@ -23,19 +22,9 @@ type RPC interface {
|
|||||||
|
|
||||||
JoinNetwork(context.Context, network.JoiningBootstrap) error
|
JoinNetwork(context.Context, network.JoiningBootstrap) error
|
||||||
|
|
||||||
GetNetworks(context.Context) ([]bootstrap.CreationParams, error)
|
|
||||||
|
|
||||||
// All network.RPC methods are automatically implemented by Daemon using the
|
// All network.RPC methods are automatically implemented by Daemon using the
|
||||||
// currently joined network. If no network is joined then any call to these
|
// currently joined network. If no network is joined then any call to these
|
||||||
// methods will return ErrNoNetwork.
|
// methods will return ErrNoNetwork.
|
||||||
//
|
|
||||||
// All calls to these methods must be accompanied with a context produced by
|
|
||||||
// WithNetwork, in order to choose the network. These methods may return
|
|
||||||
// these errors, in addition to those documented on the individual methods:
|
|
||||||
//
|
|
||||||
// Errors:
|
|
||||||
// - ErrNoMatchingNetworks
|
|
||||||
// - ErrMultipleMatchingNetworks
|
|
||||||
network.RPC
|
network.RPC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
// Package toolkit contains useful utilities which are not specific to any
|
// Package toolkit contains useful utilities which are not specific to any
|
||||||
// specific part of isle.
|
// specific part of isle.
|
||||||
package toolkit
|
package toolkit
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
// IsZero returns true if the value is equal to its zero value according to
|
|
||||||
// reflect.DeepEqual.
|
|
||||||
func IsZero[T any](v T) bool {
|
|
||||||
var zero T
|
|
||||||
return reflect.DeepEqual(v, zero)
|
|
||||||
}
|
|
||||||
|
@ -33,23 +33,21 @@ if [ ! -d "$XDG_RUNTIME_DIR/isle" ]; then
|
|||||||
mkdir c
|
mkdir c
|
||||||
|
|
||||||
cat >daemon.yml <<EOF
|
cat >daemon.yml <<EOF
|
||||||
networks:
|
vpn:
|
||||||
testing:
|
public_addr: 127.0.0.1:60000
|
||||||
vpn:
|
tun:
|
||||||
public_addr: 127.0.0.1:60000
|
device: isle-primus
|
||||||
tun:
|
storage:
|
||||||
device: isle-primus
|
allocations:
|
||||||
storage:
|
- data_path: a/data
|
||||||
allocations:
|
meta_path: a/meta
|
||||||
- data_path: a/data
|
capacity: 1
|
||||||
meta_path: a/meta
|
- data_path: b/data
|
||||||
capacity: 1
|
meta_path: b/meta
|
||||||
- data_path: b/data
|
capacity: 1
|
||||||
meta_path: b/meta
|
- data_path: c/data
|
||||||
capacity: 1
|
meta_path: c/meta
|
||||||
- data_path: c/data
|
capacity: 1
|
||||||
meta_path: c/meta
|
|
||||||
capacity: 1
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
isle daemon -l debug --config-path daemon.yml >daemon.log 2>&1 &
|
isle daemon -l debug --config-path daemon.yml >daemon.log 2>&1 &
|
||||||
|
Loading…
Reference in New Issue
Block a user