diff --git a/go/daemon/daemon.go b/go/daemon/daemon.go index d820ee0..7960b97 100644 --- a/go/daemon/daemon.go +++ b/go/daemon/daemon.go @@ -78,11 +78,23 @@ func New( ) ( *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{ logger: logger, daemonConfig: daemonConfig, envBinDirPath: envBinDirPath, - opts: opts.withDefaults(), + opts: opts, } { diff --git a/go/daemon/migrations.go b/go/daemon/migrations.go new file mode 100644 index 0000000..f174567 --- /dev/null +++ b/go/daemon/migrations.go @@ -0,0 +1,85 @@ +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" +) + +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 +}