Remove Bootstrap from Env
This commit is contained in:
parent
08f47bd514
commit
b23a4cafa6
@ -25,6 +25,18 @@ const (
|
|||||||
hostNamePath = "hostname"
|
hostNamePath = "hostname"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DataDirPath returns the path within the user's data directory where the
|
||||||
|
// bootstrap file is stored.
|
||||||
|
func DataDirPath(dataDirPath string) string {
|
||||||
|
return filepath.Join(dataDirPath, "bootstrap.tgz")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppDirPath returns the path within the AppDir where an embedded bootstrap
|
||||||
|
// file might be found.
|
||||||
|
func AppDirPath(appDirPath string) string {
|
||||||
|
return filepath.Join(appDirPath, "share/bootstrap.tgz")
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap is used for accessing all information contained within a
|
// Bootstrap is used for accessing all information contained within a
|
||||||
// bootstrap.tgz file.
|
// bootstrap.tgz file.
|
||||||
type Bootstrap struct {
|
type Bootstrap struct {
|
||||||
|
@ -148,7 +148,7 @@ var subCmdAdminCreateNetwork = subCmd{
|
|||||||
return fmt.Errorf("creating nebula cert for host: %w", err)
|
return fmt.Errorf("creating nebula cert for host: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Bootstrap = bootstrap.Bootstrap{
|
hostBootstrap := bootstrap.Bootstrap{
|
||||||
AdminCreationParams: adminCreationParams,
|
AdminCreationParams: adminCreationParams,
|
||||||
Hosts: map[string]bootstrap.Host{
|
Hosts: map[string]bootstrap.Host{
|
||||||
*hostName: bootstrap.Host{
|
*hostName: bootstrap.Host{
|
||||||
@ -165,16 +165,16 @@ var subCmdAdminCreateNetwork = subCmd{
|
|||||||
GarageGlobalBucketS3APICredentials: garage.NewS3APICredentials(),
|
GarageGlobalBucketS3APICredentials: garage.NewS3APICredentials(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if env, err = mergeDaemonConfigIntoBootstrap(env, daemonConfig); err != nil {
|
if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(env, hostBootstrap, daemonConfig); err != nil {
|
||||||
return fmt.Errorf("merging daemon config into bootstrap data: %w", err)
|
return fmt.Errorf("merging daemon config into bootstrap data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, daemonConfig)
|
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, hostBootstrap, daemonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("generating nebula config: %w", err)
|
return fmt.Errorf("generating nebula config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, daemonConfig)
|
garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, hostBootstrap, daemonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("generating garage configs: %w", err)
|
return fmt.Errorf("generating garage configs: %w", err)
|
||||||
}
|
}
|
||||||
@ -206,17 +206,17 @@ var subCmdAdminCreateNetwork = subCmd{
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
fmt.Fprintln(os.Stderr, "waiting for garage instances to come online")
|
fmt.Fprintln(os.Stderr, "waiting for garage instances to come online")
|
||||||
if err := waitForGarageAndNebula(ctx, env, daemonConfig); err != nil {
|
if err := waitForGarageAndNebula(ctx, hostBootstrap, daemonConfig); err != nil {
|
||||||
return fmt.Errorf("waiting for garage to start up: %w", err)
|
return fmt.Errorf("waiting for garage to start up: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(os.Stderr, "applying initial garage layout")
|
fmt.Fprintln(os.Stderr, "applying initial garage layout")
|
||||||
if err := garageApplyLayout(ctx, env, daemonConfig); err != nil {
|
if err := garageApplyLayout(ctx, hostBootstrap, daemonConfig); err != nil {
|
||||||
return fmt.Errorf("applying initial garage layout: %w", err)
|
return fmt.Errorf("applying initial garage layout: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(os.Stderr, "initializing garage shared global bucket")
|
fmt.Fprintln(os.Stderr, "initializing garage shared global bucket")
|
||||||
err = garageInitializeGlobalBucket(ctx, env, daemonConfig)
|
err = garageInitializeGlobalBucket(ctx, hostBootstrap, daemonConfig)
|
||||||
|
|
||||||
if cErr := (garage.AdminClientError{}); errors.As(err, &cErr) && cErr.StatusCode == 409 {
|
if cErr := (garage.AdminClientError{}); errors.As(err, &cErr) && cErr.StatusCode == 409 {
|
||||||
return fmt.Errorf("shared global bucket has already been created, are the storage allocations from a previously initialized cryptic-net being used?")
|
return fmt.Errorf("shared global bucket has already been created, are the storage allocations from a previously initialized cryptic-net being used?")
|
||||||
@ -230,8 +230,8 @@ var subCmdAdminCreateNetwork = subCmd{
|
|||||||
err = admin.Admin{
|
err = admin.Admin{
|
||||||
CreationParams: adminCreationParams,
|
CreationParams: adminCreationParams,
|
||||||
NebulaCACert: nebulaCACert,
|
NebulaCACert: nebulaCACert,
|
||||||
GarageRPCSecret: env.Bootstrap.GarageRPCSecret,
|
GarageRPCSecret: hostBootstrap.GarageRPCSecret,
|
||||||
GarageGlobalBucketS3APICredentials: env.Bootstrap.GarageGlobalBucketS3APICredentials,
|
GarageGlobalBucketS3APICredentials: hostBootstrap.GarageGlobalBucketS3APICredentials,
|
||||||
GarageAdminBucketS3APICredentials: garage.NewS3APICredentials(),
|
GarageAdminBucketS3APICredentials: garage.NewS3APICredentials(),
|
||||||
}.WriteTo(os.Stdout)
|
}.WriteTo(os.Stdout)
|
||||||
|
|
||||||
@ -271,17 +271,22 @@ var subCmdAdminMakeBootstrap = subCmd{
|
|||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
|
|
||||||
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
adm, err := readAdmin(*adminPath)
|
adm, err := readAdmin(*adminPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading admin.tgz with --admin-path of %q: %w", *adminPath, err)
|
return fmt.Errorf("reading admin.tgz with --admin-path of %q: %w", *adminPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := env.Bootstrap.GlobalBucketS3APIClient()
|
client := hostBootstrap.GlobalBucketS3APIClient()
|
||||||
|
|
||||||
// NOTE this isn't _technically_ required, but if the `hosts add`
|
// NOTE this isn't _technically_ required, but if the `hosts add`
|
||||||
// command for this host has been run recently then it might not have
|
// command for this host has been run recently then it might not have
|
||||||
// made it into the bootstrap file yet, and so won't be in
|
// made it into the bootstrap file yet, and so won't be in
|
||||||
// `env.Bootstrap`.
|
// `hostBootstrap`.
|
||||||
hosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, client)
|
hosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("retrieving host info from garage: %w", err)
|
return fmt.Errorf("retrieving host info from garage: %w", err)
|
||||||
@ -302,7 +307,7 @@ var subCmdAdminMakeBootstrap = subCmd{
|
|||||||
return fmt.Errorf("creating new nebula host key/cert: %w", err)
|
return fmt.Errorf("creating new nebula host key/cert: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newBootstrap := bootstrap.Bootstrap{
|
newHostBootstrap := bootstrap.Bootstrap{
|
||||||
AdminCreationParams: adm.CreationParams,
|
AdminCreationParams: adm.CreationParams,
|
||||||
|
|
||||||
Hosts: hosts,
|
Hosts: hosts,
|
||||||
@ -315,7 +320,7 @@ var subCmdAdminMakeBootstrap = subCmd{
|
|||||||
GarageGlobalBucketS3APICredentials: adm.GarageGlobalBucketS3APICredentials,
|
GarageGlobalBucketS3APICredentials: adm.GarageGlobalBucketS3APICredentials,
|
||||||
}
|
}
|
||||||
|
|
||||||
return newBootstrap.WriteTo(os.Stdout)
|
return newHostBootstrap.WriteTo(os.Stdout)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
entrypoint/src/cmd/entrypoint/bootstrap_util.go
Normal file
44
entrypoint/src/cmd/entrypoint/bootstrap_util.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cryptic-net/bootstrap"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadHostBootstrap(dataDirPath string) (bootstrap.Bootstrap, error) {
|
||||||
|
|
||||||
|
dataDirPath = bootstrap.DataDirPath(dataDirPath)
|
||||||
|
|
||||||
|
hostBootstrap, err := bootstrap.FromFile(dataDirPath)
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return bootstrap.Bootstrap{}, errors.New("%q not found, has the daemon ever been run?")
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return bootstrap.Bootstrap{}, fmt.Errorf("loading %q: %w", dataDirPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostBootstrap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBootstrapToDataDir(dataDirPath string, hostBootstrap bootstrap.Bootstrap) error {
|
||||||
|
|
||||||
|
path := bootstrap.DataDirPath(dataDirPath)
|
||||||
|
dirPath := filepath.Dir(path)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(dirPath, 0700); err != nil {
|
||||||
|
return fmt.Errorf("creating directory %q: %w", dirPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating file %q: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return hostBootstrap.WriteTo(f)
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -38,71 +39,76 @@ import (
|
|||||||
|
|
||||||
// creates a new bootstrap file using available information from the network. If
|
// creates a new bootstrap file using available information from the network. If
|
||||||
// the new bootstrap file is different than the existing one, the existing one
|
// the new bootstrap file is different than the existing one, the existing one
|
||||||
// is overwritten, env's bootstrap is reloaded, true is returned.
|
// is overwritten and true is returned.
|
||||||
func reloadBootstrap(env crypticnet.Env, s3Client garage.S3APIClient) (crypticnet.Env, bool, error) {
|
func reloadBootstrap(
|
||||||
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
s3Client garage.S3APIClient,
|
||||||
|
) (
|
||||||
|
bootstrap.Bootstrap, bool, error,
|
||||||
|
) {
|
||||||
|
|
||||||
newHosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, s3Client)
|
newHosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, s3Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, false, fmt.Errorf("getting hosts from garage: %w", err)
|
return bootstrap.Bootstrap{}, false, fmt.Errorf("getting hosts from garage: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newHostsHash, err := bootstrap.HostsHash(newHosts)
|
newHostsHash, err := bootstrap.HostsHash(newHosts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, false, fmt.Errorf("calculating hash of new hosts: %w", err)
|
return bootstrap.Bootstrap{}, false, fmt.Errorf("calculating hash of new hosts: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
currHostsHash, err := bootstrap.HostsHash(env.Bootstrap.Hosts)
|
currHostsHash, err := bootstrap.HostsHash(hostBootstrap.Hosts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, false, fmt.Errorf("calculating hash of current hosts: %w", err)
|
return bootstrap.Bootstrap{}, false, fmt.Errorf("calculating hash of current hosts: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(newHostsHash, currHostsHash) {
|
if bytes.Equal(newHostsHash, currHostsHash) {
|
||||||
return crypticnet.Env{}, false, nil
|
return hostBootstrap, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
newHostBootstrap := hostBootstrap.WithHosts(newHosts)
|
||||||
if err := env.Bootstrap.WithHosts(newHosts).WriteTo(buf); err != nil {
|
|
||||||
return crypticnet.Env{}, false, fmt.Errorf("writing new bootstrap file to buffer: %w", err)
|
if err := writeBootstrapToDataDir(env.DataDirPath, newHostBootstrap); err != nil {
|
||||||
|
return bootstrap.Bootstrap{}, false, fmt.Errorf("writing new bootstrap.tgz to data dir: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if env, err = copyBootstrapToDataDirAndReload(env, buf); err != nil {
|
return newHostBootstrap, true, nil
|
||||||
return crypticnet.Env{}, false, fmt.Errorf("copying new bootstrap file to data dir: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return env, true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// runs a single pmux process of daemon, returning only once the env.Context has
|
// runs a single pmux process of daemon, returning only once the env.Context has
|
||||||
// been canceled or bootstrap info has been changed. This will always block
|
// been canceled or bootstrap info has been changed. This will always block
|
||||||
// until the spawned pmux has returned, and returns a copy of Env with updated
|
// until the spawned pmux has returned, and returns a copy of hostBootstrap with
|
||||||
// boostrap info.
|
// updated boostrap info.
|
||||||
func runDaemonPmuxOnce(
|
func runDaemonPmuxOnce(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) (
|
) (
|
||||||
crypticnet.Env, error,
|
bootstrap.Bootstrap, error,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
thisHost := env.Bootstrap.ThisHost()
|
thisHost := hostBootstrap.ThisHost()
|
||||||
fmt.Fprintf(os.Stderr, "host name is %q, ip is %q\n", thisHost.Name, thisHost.Nebula.IP)
|
fmt.Fprintf(os.Stderr, "host name is %q, ip is %q\n", thisHost.Name, thisHost.Nebula.IP)
|
||||||
|
|
||||||
// create s3Client anew on every loop, in case the topology has
|
// create s3Client anew on every loop, in case the topology has
|
||||||
// changed and we should be connecting to a different garage
|
// changed and we should be connecting to a different garage
|
||||||
// endpoint.
|
// endpoint.
|
||||||
s3Client := env.Bootstrap.GlobalBucketS3APIClient()
|
s3Client := hostBootstrap.GlobalBucketS3APIClient()
|
||||||
|
|
||||||
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, daemonConfig)
|
nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, hostBootstrap, daemonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, fmt.Errorf("generating nebula config: %w", err)
|
return bootstrap.Bootstrap{}, fmt.Errorf("generating nebula config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsmasqPmuxProcConfig, err := dnsmasqPmuxProcConfig(env, daemonConfig)
|
dnsmasqPmuxProcConfig, err := dnsmasqPmuxProcConfig(env, hostBootstrap, daemonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, fmt.Errorf("generating dnsmasq config: %w", err)
|
return bootstrap.Bootstrap{}, fmt.Errorf("generating dnsmasq config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, daemonConfig)
|
garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, hostBootstrap, daemonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return crypticnet.Env{}, fmt.Errorf("generating garage children configs: %w", err)
|
return bootstrap.Bootstrap{}, fmt.Errorf("generating garage children configs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pmuxConfig := pmuxlib.Config{
|
pmuxConfig := pmuxlib.Config{
|
||||||
@ -133,12 +139,12 @@ func runDaemonPmuxOnce(
|
|||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if err := waitForGarageAndNebula(ctx, env, daemonConfig); err != nil {
|
if err := waitForGarageAndNebula(ctx, hostBootstrap, daemonConfig); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "aborted waiting for garage instances to be accessible: %v\n", err)
|
fmt.Fprintf(os.Stderr, "aborted waiting for garage instances to be accessible: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
thisHost := env.Bootstrap.ThisHost()
|
thisHost := hostBootstrap.ThisHost()
|
||||||
|
|
||||||
err := doOnce(ctx, func(ctx context.Context) error {
|
err := doOnce(ctx, func(ctx context.Context) error {
|
||||||
fmt.Fprintln(os.Stderr, "updating host info in garage")
|
fmt.Fprintln(os.Stderr, "updating host info in garage")
|
||||||
@ -155,14 +161,14 @@ func runDaemonPmuxOnce(
|
|||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if err := waitForGarageAndNebula(ctx, env, daemonConfig); err != nil {
|
if err := waitForGarageAndNebula(ctx, hostBootstrap, daemonConfig); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "aborted waiting for garage instances to be accessible: %v\n", err)
|
fmt.Fprintf(os.Stderr, "aborted waiting for garage instances to be accessible: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := doOnce(ctx, func(ctx context.Context) error {
|
err := doOnce(ctx, func(ctx context.Context) error {
|
||||||
fmt.Fprintln(os.Stderr, "applying garage layout")
|
fmt.Fprintln(os.Stderr, "applying garage layout")
|
||||||
return garageApplyLayout(ctx, env, daemonConfig)
|
return garageApplyLayout(ctx, hostBootstrap, daemonConfig)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -178,7 +184,7 @@ func runDaemonPmuxOnce(
|
|||||||
select {
|
select {
|
||||||
|
|
||||||
case <-doneCh:
|
case <-doneCh:
|
||||||
return crypticnet.Env{}, env.Context.Err()
|
return bootstrap.Bootstrap{}, env.Context.Err()
|
||||||
|
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
|
||||||
@ -189,12 +195,12 @@ func runDaemonPmuxOnce(
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if env, changed, err = reloadBootstrap(env, s3Client); err != nil {
|
if hostBootstrap, changed, err = reloadBootstrap(env, hostBootstrap, s3Client); err != nil {
|
||||||
return crypticnet.Env{}, fmt.Errorf("reloading bootstrap: %w", err)
|
return bootstrap.Bootstrap{}, fmt.Errorf("reloading bootstrap: %w", err)
|
||||||
|
|
||||||
} else if changed {
|
} else if changed {
|
||||||
fmt.Fprintln(os.Stderr, "bootstrap info has changed, restarting all processes")
|
fmt.Fprintln(os.Stderr, "bootstrap info has changed, restarting all processes")
|
||||||
return env, nil
|
return hostBootstrap, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,34 +259,51 @@ var subCmdDaemon = subCmd{
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// If the bootstrap file is not being stored in the data dir, move it
|
var (
|
||||||
// there and reload the bootstrap info
|
bootstrapDataDirPath = bootstrap.DataDirPath(env.DataDirPath)
|
||||||
if env.BootstrapPath != env.DataDirBootstrapPath() {
|
bootstrapAppDirPath = bootstrap.AppDirPath(env.AppDirPath)
|
||||||
|
|
||||||
path := env.BootstrapPath
|
hostBootstrapPath string
|
||||||
|
hostBootstrap bootstrap.Bootstrap
|
||||||
|
foundHostBootstrap bool
|
||||||
|
|
||||||
// If there's no BootstrapPath then no bootstrap file could be
|
err error
|
||||||
// found. In this case we require the user to provide one on the
|
)
|
||||||
// command-line.
|
|
||||||
if path == "" {
|
|
||||||
|
|
||||||
if *bootstrapPath == "" {
|
tryLoadBootstrap := func(path string) bool {
|
||||||
return errors.New("No bootstrap.tgz file could be found, and one is not provided with --bootstrap-path")
|
|
||||||
}
|
|
||||||
|
|
||||||
path = *bootstrapPath
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("opening file %q: %w", env.BootstrapPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
env, err = copyBootstrapToDataDirAndReload(env, f)
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("copying bootstrap file from %q: %w", path, err)
|
return false
|
||||||
|
|
||||||
|
} else if hostBootstrap, err = bootstrap.FromFile(path); errors.Is(err, fs.ErrNotExist) {
|
||||||
|
err = nil
|
||||||
|
return false
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
err = fmt.Errorf("parsing bootstrap.tgz at %q: %w", path, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
hostBootstrapPath = path
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
foundHostBootstrap = tryLoadBootstrap(bootstrapDataDirPath)
|
||||||
|
foundHostBootstrap = !foundHostBootstrap && *bootstrapPath != "" && tryLoadBootstrap(*bootstrapPath)
|
||||||
|
foundHostBootstrap = !foundHostBootstrap && tryLoadBootstrap(bootstrapAppDirPath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("attempting to load bootstrap.tgz file: %w", err)
|
||||||
|
|
||||||
|
} else if !foundHostBootstrap {
|
||||||
|
return errors.New("No bootstrap.tgz file could be found, and one is not provided with --bootstrap-path")
|
||||||
|
|
||||||
|
} else if hostBootstrapPath != bootstrapDataDirPath {
|
||||||
|
|
||||||
|
// If the bootstrap file is not being stored in the data dir, copy
|
||||||
|
// it there, so it can be loaded from there next time.
|
||||||
|
if err := writeBootstrapToDataDir(env.DataDirPath, hostBootstrap); err != nil {
|
||||||
|
return fmt.Errorf("writing bootstrap.tgz to data dir: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,13 +317,13 @@ var subCmdDaemon = subCmd{
|
|||||||
// up-to-date possible bootstrap. This updated bootstrap will later get
|
// up-to-date possible bootstrap. This updated bootstrap will later get
|
||||||
// updated in garage using bootstrap.PutGarageBoostrapHost, so other
|
// updated in garage using bootstrap.PutGarageBoostrapHost, so other
|
||||||
// hosts will see it as well.
|
// hosts will see it as well.
|
||||||
if env, err = mergeDaemonConfigIntoBootstrap(env, daemonConfig); err != nil {
|
if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(env, hostBootstrap, daemonConfig); err != nil {
|
||||||
return fmt.Errorf("merging daemon config into bootstrap data: %w", err)
|
return fmt.Errorf("merging daemon config into bootstrap data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
env, err = runDaemonPmuxOnce(env, daemonConfig)
|
hostBootstrap, err = runDaemonPmuxOnce(env, hostBootstrap, daemonConfig)
|
||||||
|
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,48 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
crypticnet "cryptic-net"
|
crypticnet "cryptic-net"
|
||||||
"cryptic-net/bootstrap"
|
"cryptic-net/bootstrap"
|
||||||
"cryptic-net/daemon"
|
"cryptic-net/daemon"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func copyBootstrapToDataDirAndReload(env crypticnet.Env, r io.Reader) (crypticnet.Env, error) {
|
|
||||||
|
|
||||||
path := env.DataDirBootstrapPath()
|
|
||||||
dirPath := filepath.Dir(path)
|
|
||||||
|
|
||||||
if err := os.MkdirAll(dirPath, 0700); err != nil {
|
|
||||||
return crypticnet.Env{}, fmt.Errorf("creating directory %q: %w", dirPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(path)
|
|
||||||
if err != nil {
|
|
||||||
return crypticnet.Env{}, fmt.Errorf("creating file %q: %w", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.Copy(f, r)
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return crypticnet.Env{}, fmt.Errorf("copying bootstrap file to %q: %w", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return env.LoadBootstrap(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeDaemonConfigIntoBootstrap(
|
func mergeDaemonConfigIntoBootstrap(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) (
|
) (
|
||||||
crypticnet.Env, error,
|
bootstrap.Bootstrap, error,
|
||||||
) {
|
) {
|
||||||
host := env.Bootstrap.ThisHost()
|
host := hostBootstrap.ThisHost()
|
||||||
|
|
||||||
host.Nebula.PublicAddr = daemonConfig.VPN.PublicAddr
|
host.Nebula.PublicAddr = daemonConfig.VPN.PublicAddr
|
||||||
|
|
||||||
@ -60,14 +34,13 @@ func mergeDaemonConfigIntoBootstrap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Bootstrap.Hosts[host.Name] = host
|
hostBootstrap.Hosts[host.Name] = host
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
if err := writeBootstrapToDataDir(env.DataDirPath, hostBootstrap); err != nil {
|
||||||
if err := env.Bootstrap.WithHosts(env.Bootstrap.Hosts).WriteTo(buf); err != nil {
|
return bootstrap.Bootstrap{}, fmt.Errorf("writing bootstrap file: %w", err)
|
||||||
return crypticnet.Env{}, fmt.Errorf("writing new bootstrap file to buffer: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return copyBootstrapToDataDirAndReload(env, buf)
|
return hostBootstrap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doOnce(ctx context.Context, fn func(context.Context) error) error {
|
func doOnce(ctx context.Context, fn func(context.Context) error) error {
|
||||||
|
@ -13,15 +13,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func dnsmasqPmuxProcConfig(
|
func dnsmasqPmuxProcConfig(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) (
|
) (
|
||||||
pmuxlib.ProcessConfig, error,
|
pmuxlib.ProcessConfig, error,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
confPath := filepath.Join(env.RuntimeDirPath, "dnsmasq.conf")
|
confPath := filepath.Join(env.RuntimeDirPath, "dnsmasq.conf")
|
||||||
|
|
||||||
hostsSlice := make([]bootstrap.Host, 0, len(env.Bootstrap.Hosts))
|
hostsSlice := make([]bootstrap.Host, 0, len(hostBootstrap.Hosts))
|
||||||
for _, host := range env.Bootstrap.Hosts {
|
for _, host := range hostBootstrap.Hosts {
|
||||||
hostsSlice = append(hostsSlice, host)
|
hostsSlice = append(hostsSlice, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +33,8 @@ func dnsmasqPmuxProcConfig(
|
|||||||
|
|
||||||
confData := dnsmasq.ConfData{
|
confData := dnsmasq.ConfData{
|
||||||
Resolvers: daemonConfig.DNS.Resolvers,
|
Resolvers: daemonConfig.DNS.Resolvers,
|
||||||
Domain: env.Bootstrap.AdminCreationParams.Domain,
|
Domain: hostBootstrap.AdminCreationParams.Domain,
|
||||||
IP: env.Bootstrap.ThisHost().Nebula.IP,
|
IP: hostBootstrap.ThisHost().Nebula.IP,
|
||||||
Hosts: hostsSlice,
|
Hosts: hostsSlice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,16 +30,21 @@ var subCmdGarageMC = subCmd{
|
|||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
|
|
||||||
s3APIAddr := env.Bootstrap.ChooseGaragePeer().S3APIAddr()
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s3APIAddr := hostBootstrap.ChooseGaragePeer().S3APIAddr()
|
||||||
|
|
||||||
if *keyID == "" || *keySecret == "" {
|
if *keyID == "" || *keySecret == "" {
|
||||||
|
|
||||||
if *keyID == "" {
|
if *keyID == "" {
|
||||||
*keyID = env.Bootstrap.GarageGlobalBucketS3APICredentials.ID
|
*keyID = hostBootstrap.GarageGlobalBucketS3APICredentials.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
if *keySecret == "" {
|
if *keySecret == "" {
|
||||||
*keyID = env.Bootstrap.GarageGlobalBucketS3APICredentials.Secret
|
*keyID = hostBootstrap.GarageGlobalBucketS3APICredentials.Secret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,13 +90,18 @@ var subCmdGarageCLI = subCmd{
|
|||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
|
|
||||||
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
binPath = "garage"
|
binPath = "garage"
|
||||||
args = append([]string{"garage"}, subCmdCtx.args...)
|
args = append([]string{"garage"}, subCmdCtx.args...)
|
||||||
cliEnv = append(
|
cliEnv = append(
|
||||||
os.Environ(),
|
os.Environ(),
|
||||||
"GARAGE_RPC_HOST="+env.Bootstrap.ChooseGaragePeer().RPCAddr(),
|
"GARAGE_RPC_HOST="+hostBootstrap.ChooseGaragePeer().RPCAddr(),
|
||||||
"GARAGE_RPC_SECRET="+env.Bootstrap.GarageRPCSecret,
|
"GARAGE_RPC_SECRET="+hostBootstrap.GarageRPCSecret,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
crypticnet "cryptic-net"
|
crypticnet "cryptic-net"
|
||||||
|
"cryptic-net/bootstrap"
|
||||||
"cryptic-net/daemon"
|
"cryptic-net/daemon"
|
||||||
"cryptic-net/garage"
|
"cryptic-net/garage"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -17,22 +18,24 @@ import (
|
|||||||
// newGarageAdminClient will return an AdminClient for a local garage instance,
|
// newGarageAdminClient will return an AdminClient for a local garage instance,
|
||||||
// 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(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config,
|
||||||
) *garage.AdminClient {
|
) *garage.AdminClient {
|
||||||
|
|
||||||
thisHost := env.Bootstrap.ThisHost()
|
thisHost := hostBootstrap.ThisHost()
|
||||||
|
|
||||||
return garage.NewAdminClient(
|
return garage.NewAdminClient(
|
||||||
net.JoinHostPort(
|
net.JoinHostPort(
|
||||||
thisHost.Nebula.IP,
|
thisHost.Nebula.IP,
|
||||||
strconv.Itoa(daemonConfig.Storage.Allocations[0].AdminPort),
|
strconv.Itoa(daemonConfig.Storage.Allocations[0].AdminPort),
|
||||||
),
|
),
|
||||||
env.Bootstrap.GarageAdminToken,
|
hostBootstrap.GarageAdminToken,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForGarageAndNebula(
|
func waitForGarageAndNebula(
|
||||||
ctx context.Context, env crypticnet.Env, daemonConfig daemon.Config,
|
ctx context.Context,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
allocs := daemonConfig.Storage.Allocations
|
allocs := daemonConfig.Storage.Allocations
|
||||||
@ -40,19 +43,19 @@ func waitForGarageAndNebula(
|
|||||||
// 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
|
||||||
if len(allocs) == 0 {
|
if len(allocs) == 0 {
|
||||||
return waitForNebula(ctx, env)
|
return waitForNebula(ctx, hostBootstrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, alloc := range allocs {
|
for _, alloc := range allocs {
|
||||||
|
|
||||||
adminAddr := net.JoinHostPort(
|
adminAddr := net.JoinHostPort(
|
||||||
env.Bootstrap.ThisHost().Nebula.IP,
|
hostBootstrap.ThisHost().Nebula.IP,
|
||||||
strconv.Itoa(alloc.AdminPort),
|
strconv.Itoa(alloc.AdminPort),
|
||||||
)
|
)
|
||||||
|
|
||||||
adminClient := garage.NewAdminClient(
|
adminClient := garage.NewAdminClient(
|
||||||
adminAddr,
|
adminAddr,
|
||||||
env.Bootstrap.GarageAdminToken,
|
hostBootstrap.GarageAdminToken,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := adminClient.Wait(ctx); err != nil {
|
if err := adminClient.Wait(ctx); err != nil {
|
||||||
@ -66,6 +69,7 @@ func waitForGarageAndNebula(
|
|||||||
|
|
||||||
func garageWriteChildConfig(
|
func garageWriteChildConfig(
|
||||||
env crypticnet.Env,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
alloc daemon.ConfigStorageAllocation,
|
alloc daemon.ConfigStorageAllocation,
|
||||||
) (
|
) (
|
||||||
string, error,
|
string, error,
|
||||||
@ -75,7 +79,7 @@ func garageWriteChildConfig(
|
|||||||
return "", fmt.Errorf("making directory %q: %w", alloc.MetaPath, err)
|
return "", fmt.Errorf("making directory %q: %w", alloc.MetaPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
thisHost := env.Bootstrap.ThisHost()
|
thisHost := hostBootstrap.ThisHost()
|
||||||
|
|
||||||
peer := garage.Peer{
|
peer := garage.Peer{
|
||||||
IP: thisHost.Nebula.IP,
|
IP: thisHost.Nebula.IP,
|
||||||
@ -103,14 +107,14 @@ func garageWriteChildConfig(
|
|||||||
MetaPath: alloc.MetaPath,
|
MetaPath: alloc.MetaPath,
|
||||||
DataPath: alloc.DataPath,
|
DataPath: alloc.DataPath,
|
||||||
|
|
||||||
RPCSecret: env.Bootstrap.GarageRPCSecret,
|
RPCSecret: hostBootstrap.GarageRPCSecret,
|
||||||
AdminToken: env.Bootstrap.GarageAdminToken,
|
AdminToken: hostBootstrap.GarageAdminToken,
|
||||||
|
|
||||||
RPCAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.RPCPort)),
|
RPCAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.RPCPort)),
|
||||||
APIAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.S3APIPort)),
|
APIAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.S3APIPort)),
|
||||||
AdminAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.AdminPort)),
|
AdminAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.AdminPort)),
|
||||||
|
|
||||||
BootstrapPeers: env.Bootstrap.GarageRPCPeerAddrs(),
|
BootstrapPeers: hostBootstrap.GarageRPCPeerAddrs(),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -121,7 +125,9 @@ func garageWriteChildConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func garagePmuxProcConfigs(
|
func garagePmuxProcConfigs(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) (
|
) (
|
||||||
[]pmuxlib.ProcessConfig, error,
|
[]pmuxlib.ProcessConfig, error,
|
||||||
) {
|
) {
|
||||||
@ -130,7 +136,7 @@ func garagePmuxProcConfigs(
|
|||||||
|
|
||||||
for _, alloc := range daemonConfig.Storage.Allocations {
|
for _, alloc := range daemonConfig.Storage.Allocations {
|
||||||
|
|
||||||
childConfigPath, err := garageWriteChildConfig(env, alloc)
|
childConfigPath, err := garageWriteChildConfig(env, hostBootstrap, alloc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("writing child config file for alloc %+v: %w", alloc, err)
|
return nil, fmt.Errorf("writing child config file for alloc %+v: %w", alloc, err)
|
||||||
@ -141,7 +147,7 @@ func garagePmuxProcConfigs(
|
|||||||
Cmd: "garage",
|
Cmd: "garage",
|
||||||
Args: []string{"-c", childConfigPath, "server"},
|
Args: []string{"-c", childConfigPath, "server"},
|
||||||
StartAfterFunc: func(ctx context.Context) error {
|
StartAfterFunc: func(ctx context.Context) error {
|
||||||
return waitForNebula(ctx, env)
|
return waitForNebula(ctx, hostBootstrap)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -150,12 +156,14 @@ func garagePmuxProcConfigs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func garageInitializeGlobalBucket(
|
func garageInitializeGlobalBucket(
|
||||||
ctx context.Context, env crypticnet.Env, daemonConfig daemon.Config,
|
ctx context.Context,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
adminClient = newGarageAdminClient(env, daemonConfig)
|
adminClient = newGarageAdminClient(hostBootstrap, daemonConfig)
|
||||||
globalBucketCreds = env.Bootstrap.GarageGlobalBucketS3APICredentials
|
globalBucketCreds = hostBootstrap.GarageGlobalBucketS3APICredentials
|
||||||
)
|
)
|
||||||
|
|
||||||
// first attempt to import the key
|
// first attempt to import the key
|
||||||
@ -210,12 +218,14 @@ func garageInitializeGlobalBucket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func garageApplyLayout(
|
func garageApplyLayout(
|
||||||
ctx context.Context, env crypticnet.Env, daemonConfig daemon.Config,
|
ctx context.Context,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
adminClient = newGarageAdminClient(env, daemonConfig)
|
adminClient = newGarageAdminClient(hostBootstrap, daemonConfig)
|
||||||
thisHost = env.Bootstrap.ThisHost()
|
thisHost = hostBootstrap.ThisHost()
|
||||||
hostName = thisHost.Name
|
hostName = thisHost.Name
|
||||||
ip = thisHost.Nebula.IP
|
ip = thisHost.Nebula.IP
|
||||||
allocs = daemonConfig.Storage.Allocations
|
allocs = daemonConfig.Storage.Allocations
|
||||||
|
@ -60,7 +60,13 @@ var subCmdHostsAdd = subCmd{
|
|||||||
// TODO validate that the IP is in the correct CIDR
|
// TODO validate that the IP is in the correct CIDR
|
||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
client := env.Bootstrap.GlobalBucketS3APIClient()
|
|
||||||
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := hostBootstrap.GlobalBucketS3APIClient()
|
||||||
|
|
||||||
host := bootstrap.Host{
|
host := bootstrap.Host{
|
||||||
Name: *name,
|
Name: *name,
|
||||||
@ -81,7 +87,12 @@ var subCmdHostsList = subCmd{
|
|||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
|
|
||||||
client := env.Bootstrap.GlobalBucketS3APIClient()
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := hostBootstrap.GlobalBucketS3APIClient()
|
||||||
|
|
||||||
hostsMap, err := bootstrap.GetGarageBootstrapHosts(env.Context, client)
|
hostsMap, err := bootstrap.GetGarageBootstrapHosts(env.Context, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -121,7 +132,13 @@ var subCmdHostsDelete = subCmd{
|
|||||||
}
|
}
|
||||||
|
|
||||||
env := subCmdCtx.env
|
env := subCmdCtx.env
|
||||||
client := env.Bootstrap.GlobalBucketS3APIClient()
|
|
||||||
|
hostBootstrap, err := loadHostBootstrap(env.DataDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := hostBootstrap.GlobalBucketS3APIClient()
|
||||||
|
|
||||||
return bootstrap.RemoveGarageBootstrapHost(env.Context, client, *name)
|
return bootstrap.RemoveGarageBootstrapHost(env.Context, client, *name)
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
crypticnet "cryptic-net"
|
crypticnet "cryptic-net"
|
||||||
@ -14,13 +13,9 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
env, err := crypticnet.NewEnv(true)
|
env := crypticnet.NewEnv()
|
||||||
|
|
||||||
if err != nil {
|
err := subCmdCtx{
|
||||||
panic(fmt.Sprintf("loading environment: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = subCmdCtx{
|
|
||||||
args: os.Args[1:],
|
args: os.Args[1:],
|
||||||
env: env,
|
env: env,
|
||||||
}.doSubCmd(
|
}.doSubCmd(
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
crypticnet "cryptic-net"
|
crypticnet "cryptic-net"
|
||||||
|
"cryptic-net/bootstrap"
|
||||||
"cryptic-net/daemon"
|
"cryptic-net/daemon"
|
||||||
"cryptic-net/yamlutil"
|
"cryptic-net/yamlutil"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -16,9 +17,9 @@ import (
|
|||||||
// this by attempting to create a UDP connection which has the nebula IP set as
|
// this by attempting to create a UDP connection which has the nebula IP set as
|
||||||
// its source. If this succeeds we can assume that at the very least the nebula
|
// its source. If this succeeds we can assume that at the very least the nebula
|
||||||
// interface has been initialized.
|
// interface has been initialized.
|
||||||
func waitForNebula(ctx context.Context, env crypticnet.Env) error {
|
func waitForNebula(ctx context.Context, hostBootstrap bootstrap.Bootstrap) error {
|
||||||
|
|
||||||
ipStr := env.Bootstrap.ThisHost().Nebula.IP
|
ipStr := hostBootstrap.ThisHost().Nebula.IP
|
||||||
ip := net.ParseIP(ipStr)
|
ip := net.ParseIP(ipStr)
|
||||||
|
|
||||||
lUdpAddr := &net.UDPAddr{IP: ip, Port: 0}
|
lUdpAddr := &net.UDPAddr{IP: ip, Port: 0}
|
||||||
@ -35,7 +36,9 @@ func waitForNebula(ctx context.Context, env crypticnet.Env) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func nebulaPmuxProcConfig(
|
func nebulaPmuxProcConfig(
|
||||||
env crypticnet.Env, daemonConfig daemon.Config,
|
env crypticnet.Env,
|
||||||
|
hostBootstrap bootstrap.Bootstrap,
|
||||||
|
daemonConfig daemon.Config,
|
||||||
) (
|
) (
|
||||||
pmuxlib.ProcessConfig, error,
|
pmuxlib.ProcessConfig, error,
|
||||||
) {
|
) {
|
||||||
@ -45,7 +48,7 @@ func nebulaPmuxProcConfig(
|
|||||||
staticHostMap = map[string][]string{}
|
staticHostMap = map[string][]string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, host := range env.Bootstrap.Hosts {
|
for _, host := range hostBootstrap.Hosts {
|
||||||
|
|
||||||
if host.Nebula.PublicAddr == "" {
|
if host.Nebula.PublicAddr == "" {
|
||||||
continue
|
continue
|
||||||
@ -57,9 +60,9 @@ func nebulaPmuxProcConfig(
|
|||||||
|
|
||||||
config := map[string]interface{}{
|
config := map[string]interface{}{
|
||||||
"pki": map[string]string{
|
"pki": map[string]string{
|
||||||
"ca": env.Bootstrap.NebulaHostCert.CACert,
|
"ca": hostBootstrap.NebulaHostCert.CACert,
|
||||||
"cert": env.Bootstrap.NebulaHostCert.HostCert,
|
"cert": hostBootstrap.NebulaHostCert.HostCert,
|
||||||
"key": env.Bootstrap.NebulaHostCert.HostKey,
|
"key": hostBootstrap.NebulaHostCert.HostKey,
|
||||||
},
|
},
|
||||||
"static_host_map": staticHostMap,
|
"static_host_map": staticHostMap,
|
||||||
"punchy": map[string]bool{
|
"punchy": map[string]bool{
|
||||||
|
@ -2,10 +2,7 @@ package crypticnet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"cryptic-net/bootstrap"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -22,11 +19,6 @@ type Env struct {
|
|||||||
AppDirPath string
|
AppDirPath string
|
||||||
RuntimeDirPath string
|
RuntimeDirPath string
|
||||||
DataDirPath string
|
DataDirPath string
|
||||||
|
|
||||||
// If NewEnv is called with bootstrapOptional, and a bootstrap file is not
|
|
||||||
// found, then these fields will not be set.
|
|
||||||
BootstrapPath string
|
|
||||||
Bootstrap bootstrap.Bootstrap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAppDirPath() string {
|
func getAppDirPath() string {
|
||||||
@ -38,11 +30,7 @@ func getAppDirPath() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewEnv calculates an Env instance based on the APPDIR and XDG envvars.
|
// NewEnv calculates an Env instance based on the APPDIR and XDG envvars.
|
||||||
//
|
func NewEnv() Env {
|
||||||
// If bootstrapOptional is true then NewEnv will first check if a bootstrap file
|
|
||||||
// can be found in the expected places, and if not then it will not populate
|
|
||||||
// BootstrapFS or any other fields based on it.
|
|
||||||
func NewEnv(bootstrapOptional bool) (Env, error) {
|
|
||||||
|
|
||||||
runtimeDirPath := filepath.Join(xdg.RuntimeDir, "cryptic-net")
|
runtimeDirPath := filepath.Join(xdg.RuntimeDir, "cryptic-net")
|
||||||
appDirPath := getAppDirPath()
|
appDirPath := getAppDirPath()
|
||||||
@ -53,79 +41,8 @@ func NewEnv(bootstrapOptional bool) (Env, error) {
|
|||||||
DataDirPath: filepath.Join(xdg.DataHome, "cryptic-net"),
|
DataDirPath: filepath.Join(xdg.DataHome, "cryptic-net"),
|
||||||
}
|
}
|
||||||
|
|
||||||
return env.init(bootstrapOptional)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataDirBootstrapPath returns the path to the bootstrap file within the user's
|
|
||||||
// data dir. If the file does not exist there it will be found in the AppDirPath
|
|
||||||
// by ReloadBootstrap.
|
|
||||||
func (e Env) DataDirBootstrapPath() string {
|
|
||||||
return filepath.Join(e.DataDirPath, "bootstrap.tgz")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadBootstrap loads a Bootstrap from the given path, and returns a copy of
|
|
||||||
// the Env with that Bootstrap set along with the BootstrapPath (or an error).
|
|
||||||
func (e Env) LoadBootstrap(path string) (Env, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if e.Bootstrap, err = bootstrap.FromFile(path); err != nil {
|
|
||||||
return Env{}, fmt.Errorf("parsing bootstrap.tgz at %q: %w", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
e.BootstrapPath = path
|
|
||||||
|
|
||||||
return e, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Env) initBootstrap(bootstrapOptional bool) (Env, error) {
|
|
||||||
|
|
||||||
exists := func(path string) (bool, error) {
|
|
||||||
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return false, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return false, fmt.Errorf("stat'ing %q: %w", path, err)
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// start by checking if a bootstrap can be found in the user's data
|
|
||||||
// directory. This will only not be the case if daemon has never been
|
|
||||||
// successfully started.
|
|
||||||
{
|
|
||||||
bootstrapPath := e.DataDirBootstrapPath()
|
|
||||||
|
|
||||||
if exists, err := exists(bootstrapPath); err != nil {
|
|
||||||
return Env{}, fmt.Errorf("determining if %q exists: %w", bootstrapPath, err)
|
|
||||||
|
|
||||||
} else if exists {
|
|
||||||
return e.LoadBootstrap(bootstrapPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to checking within the AppDir for a bootstrap which has been
|
|
||||||
// embedded into the binary.
|
|
||||||
{
|
|
||||||
bootstrapPath := filepath.Join(e.AppDirPath, "share/bootstrap.tgz")
|
|
||||||
|
|
||||||
if exists, err := exists(bootstrapPath); err != nil {
|
|
||||||
return Env{}, fmt.Errorf("determining if %q exists: %w", bootstrapPath, err)
|
|
||||||
|
|
||||||
} else if !exists && !bootstrapOptional {
|
|
||||||
return Env{}, fmt.Errorf("boostrap file not found at %q", bootstrapPath)
|
|
||||||
|
|
||||||
} else if exists {
|
|
||||||
return e.LoadBootstrap(bootstrapPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return e, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Env) init(bootstrapOptional bool) (Env, error) {
|
|
||||||
|
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
e.Context, cancel = context.WithCancel(context.Background())
|
env.Context, cancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
signalCh := make(chan os.Signal, 2)
|
signalCh := make(chan os.Signal, 2)
|
||||||
signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
@ -142,5 +59,5 @@ func (e Env) init(bootstrapOptional bool) (Env, error) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return e.initBootstrap(bootstrapOptional)
|
return env
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user