-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #221 from SiaFoundation/nate/siad-migrate
utility
- Loading branch information
Showing
18 changed files
with
2,700 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
name: Publish - Migration Utility | ||
|
||
# Controls when the action will run. | ||
on: | ||
# Triggers the workflow on new SemVer tags | ||
push: | ||
branches: | ||
- master | ||
tags: | ||
- 'v[0-9]+.[0-9]+.[0-9]+' | ||
- 'v[0-9]+.[0-9]+.[0-9]+-**' | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: read | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 'stable' | ||
- name: Test | ||
uses: ./.github/actions/test | ||
build-linux: | ||
runs-on: ubuntu-latest | ||
needs: [ test ] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 'stable' | ||
- name: Setup | ||
run: | | ||
sudo apt update | ||
sudo apt install -y gcc-aarch64-linux-gnu | ||
go generate ./... | ||
- name: Build amd64 | ||
env: | ||
CGO_ENABLED: 1 | ||
GOOS: linux | ||
GOARCH: amd64 | ||
run: | | ||
mkdir -p release | ||
ZIP_OUTPUT=release/migrate_${GOOS}_${GOARCH}.zip | ||
go build -tags='netgo' -trimpath -o bin/ -a -ldflags '-s -w -linkmode external -extldflags "-static"' ./cmd/migrate | ||
cp README.md LICENSE bin/ | ||
zip -qj $ZIP_OUTPUT bin/* | ||
- name: Build arm64 | ||
env: | ||
CGO_ENABLED: 1 | ||
GOOS: linux | ||
GOARCH: arm64 | ||
CC: aarch64-linux-gnu-gcc | ||
run: | | ||
mkdir -p release | ||
ZIP_OUTPUT=release/migrate_${GOOS}_${GOARCH}.zip | ||
go build -tags='netgo' -trimpath -o bin/ -a -ldflags '-s -w' ./cmd/migrate | ||
cp README.md LICENSE bin/ | ||
zip -qj $ZIP_OUTPUT bin/* | ||
- uses: actions/upload-artifact@v3 | ||
with: | ||
name: migrate | ||
path: release/ | ||
build-mac: | ||
runs-on: macos-latest | ||
needs: [ test ] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 'stable' | ||
- name: Setup | ||
env: | ||
APPLE_CERT_ID: ${{ secrets.APPLE_CERT_ID }} | ||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | ||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | ||
APPLE_KEY_B64: ${{ secrets.APPLE_KEY_B64 }} | ||
APPLE_CERT_B64: ${{ secrets.APPLE_CERT_B64 }} | ||
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} | ||
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | ||
run: | | ||
# extract apple cert | ||
APPLE_CERT_PATH=$RUNNER_TEMP/apple_cert.p12 | ||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | ||
echo -n "$APPLE_CERT_B64" | base64 --decode --output $APPLE_CERT_PATH | ||
# extract apple key | ||
mkdir -p ~/private_keys | ||
APPLE_API_KEY_PATH=~/private_keys/AuthKey_$APPLE_API_KEY.p8 | ||
echo -n "$APPLE_KEY_B64" | base64 --decode --output $APPLE_API_KEY_PATH | ||
# create temp keychain | ||
security create-keychain -p "$APPLE_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | ||
security default-keychain -s $KEYCHAIN_PATH | ||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | ||
security unlock-keychain -p "$APPLE_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | ||
# import keychain | ||
security import $APPLE_CERT_PATH -P $APPLE_CERT_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | ||
security find-identity -v $KEYCHAIN_PATH -p codesigning | ||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $APPLE_KEYCHAIN_PASSWORD $KEYCHAIN_PATH | ||
# generate | ||
go generate ./... | ||
- name: Build amd64 | ||
env: | ||
APPLE_CERT_ID: ${{ secrets.APPLE_CERT_ID }} | ||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | ||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | ||
APPLE_KEY_B64: ${{ secrets.APPLE_KEY_B64 }} | ||
APPLE_CERT_B64: ${{ secrets.APPLE_CERT_B64 }} | ||
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} | ||
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | ||
CGO_ENABLED: 1 | ||
GOOS: darwin | ||
GOARCH: amd64 | ||
run: | | ||
ZIP_OUTPUT=release/migrate_${GOOS}_${GOARCH}.zip | ||
mkdir -p release | ||
go build -tags='netgo' -trimpath -o bin/ -a -ldflags '-s -w' ./cmd/migrate | ||
cp README.md LICENSE bin/ | ||
/usr/bin/codesign --deep -f -v --timestamp -o runtime,library -s $APPLE_CERT_ID bin/migrate | ||
ditto -ck bin $ZIP_OUTPUT | ||
xcrun notarytool submit -k ~/private_keys/AuthKey_$APPLE_API_KEY.p8 -d $APPLE_API_KEY -i $APPLE_API_ISSUER --wait --timeout 10m $ZIP_OUTPUT | ||
- name: Build arm64 | ||
env: | ||
APPLE_CERT_ID: ${{ secrets.APPLE_CERT_ID }} | ||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | ||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | ||
APPLE_KEY_B64: ${{ secrets.APPLE_KEY_B64 }} | ||
APPLE_CERT_B64: ${{ secrets.APPLE_CERT_B64 }} | ||
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} | ||
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | ||
CGO_ENABLED: 1 | ||
GOOS: darwin | ||
GOARCH: arm64 | ||
run: | | ||
ZIP_OUTPUT=release/migrate_${GOOS}_${GOARCH}.zip | ||
mkdir -p release | ||
go build -tags='netgo' -trimpath -o bin/ -a -ldflags '-s -w' ./cmd/migrate | ||
cp README.md LICENSE bin/ | ||
/usr/bin/codesign --deep -f -v --timestamp -o runtime,library -s $APPLE_CERT_ID bin/migrate | ||
ditto -ck bin $ZIP_OUTPUT | ||
xcrun notarytool submit -k ~/private_keys/AuthKey_$APPLE_API_KEY.p8 -d $APPLE_API_KEY -i $APPLE_API_ISSUER --wait --timeout 10m $ZIP_OUTPUT | ||
- uses: actions/upload-artifact@v3 | ||
with: | ||
name: migrate | ||
path: release/ | ||
build-windows: | ||
runs-on: windows-latest | ||
needs: [ test ] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 'stable' | ||
- name: Setup | ||
shell: bash | ||
run: | | ||
dotnet tool install --global AzureSignTool | ||
go generate ./... | ||
- name: Build amd64 | ||
env: | ||
CGO_ENABLED: 1 | ||
GOOS: windows | ||
GOARCH: amd64 | ||
shell: bash | ||
run: | | ||
mkdir -p release | ||
ZIP_OUTPUT=release/migrate_${GOOS}_${GOARCH}.zip | ||
go build -tags='netgo' -trimpath -o bin/ -a -ldflags '-s -w -linkmode external -extldflags "-static"' ./cmd/migrate | ||
azuresigntool sign -kvu "${{ secrets.AZURE_KEY_VAULT_URI }}" -kvi "${{ secrets.AZURE_CLIENT_ID }}" -kvt "${{ secrets.AZURE_TENANT_ID }}" -kvs "${{ secrets.AZURE_CLIENT_SECRET }}" -kvc ${{ secrets.AZURE_CERT_NAME }} -tr http://timestamp.digicert.com -v bin/migrate.exe | ||
cp README.md LICENSE bin/ | ||
7z a $ZIP_OUTPUT ./bin/* | ||
- uses: actions/upload-artifact@v3 | ||
with: | ||
name: migrate | ||
path: release/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"flag" | ||
"fmt" | ||
"os" | ||
"os/signal" | ||
"path/filepath" | ||
"syscall" | ||
"time" | ||
|
||
"go.sia.tech/hostd/internal/migrate" | ||
"go.sia.tech/hostd/persist/sqlite" | ||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
) | ||
|
||
// read a line of input from stdin | ||
func readInput(context string) (string, error) { | ||
fmt.Printf("%s: ", context) | ||
input, err := bufio.NewReader(os.Stdin).ReadString('\n') | ||
fmt.Println() | ||
return string(input), err | ||
} | ||
|
||
func verifyDirectory(dataPath string) error { | ||
// check if the directory exists | ||
if stat, err := os.Stat(dataPath); err != nil { | ||
return fmt.Errorf("failed to stat directory: %w", err) | ||
} else if !stat.IsDir() { | ||
return fmt.Errorf("not a directory: %s", dataPath) | ||
} | ||
|
||
requiredPaths := []string{ | ||
filepath.Join(dataPath, "consensus", "consensus.db"), | ||
filepath.Join(dataPath, "host", "host.json"), | ||
filepath.Join(dataPath, "host", "host.db"), | ||
filepath.Join(dataPath, "host", "contractmanager", "contractmanager.json"), | ||
} | ||
|
||
for _, path := range requiredPaths { | ||
if _, err := os.Stat(path); err != nil { | ||
return fmt.Errorf("failed to stat required file %q: %w", path, err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func main() { | ||
var logLevel string | ||
flag.StringVar(&logLevel, "log.level", "info", "set the log level") | ||
flag.Parse() | ||
|
||
// configure console logging note: this is configured before anything else | ||
// to have consistent logging. File logging will be added after the cli | ||
// flags and config is parsed | ||
consoleCfg := zap.NewProductionEncoderConfig() | ||
consoleCfg.TimeKey = "" // prevent duplicate timestamps | ||
consoleCfg.EncodeTime = zapcore.RFC3339TimeEncoder | ||
consoleCfg.EncodeDuration = zapcore.StringDurationEncoder | ||
consoleCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder | ||
consoleCfg.StacktraceKey = "" | ||
consoleCfg.CallerKey = "" | ||
consoleEncoder := zapcore.NewConsoleEncoder(consoleCfg) | ||
|
||
// configure logging | ||
var level zap.AtomicLevel | ||
switch logLevel { | ||
case "debug": | ||
level = zap.NewAtomicLevelAt(zap.DebugLevel) | ||
case "info": | ||
level = zap.NewAtomicLevelAt(zap.InfoLevel) | ||
case "warn": | ||
level = zap.NewAtomicLevelAt(zap.WarnLevel) | ||
case "error": | ||
level = zap.NewAtomicLevelAt(zap.ErrorLevel) | ||
default: | ||
panic("invalid log level") | ||
} | ||
|
||
// only log info messages to console unless stdout logging is enabled | ||
consoleCore := zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), level) | ||
log := zap.New(consoleCore, zap.AddCaller()) | ||
defer log.Sync() | ||
// redirect stdlib log to zap | ||
zap.RedirectStdLog(log) | ||
|
||
fmt.Println("siad Host Migrator") | ||
fmt.Println("This tool will migrate your old siad host to hostd") | ||
fmt.Println("It will migrate any existing contracts, storage folders, and settings") | ||
fmt.Println("It will not migrate your wallet, but you can sweep it to a new hostd seed after migration") | ||
fmt.Println("") | ||
fmt.Println("Please make sure your computer will not go to turn off during the migration") | ||
readInput("Press enter to continue") | ||
|
||
// read the siad directory | ||
fmt.Println("Where is your siad data directory? Enter the path and press enter to continue.") | ||
dir, err := readInput("siad data directory") | ||
if err != nil { | ||
log.Fatal("failed to read input", zap.Error(err)) | ||
} | ||
|
||
// check to make sure everything is in order | ||
fmt.Println("Checking directory structure...") | ||
if err := verifyDirectory(dir); err != nil { | ||
log.Fatal("failed to verify siad directory structure", zap.Error(err)) | ||
} | ||
|
||
// ask if the migration should be destructive | ||
var destructive bool | ||
fmt.Println("Do you want to delete the old data files during migration?") | ||
fmt.Println("Unless you have double the available disk space, it is required to delete the old data files to free up space for the new storage volumes") | ||
fmt.Println("This will free up disk space, but you will no longer be able to use siad. If the migration fails, you may be left in a broken state.") | ||
|
||
for { | ||
answer, err := readInput("delete old data files? (yes/no)") | ||
if err != nil { | ||
log.Fatal("failed to read input", zap.Error(err)) | ||
} | ||
switch answer { | ||
case "yes": | ||
destructive = true | ||
case "no": | ||
destructive = false | ||
default: | ||
fmt.Println("Please enter yes or no") | ||
fmt.Println("") | ||
continue | ||
} | ||
break | ||
} | ||
|
||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT) | ||
defer cancel() | ||
|
||
db, err := sqlite.OpenDatabase(filepath.Join(dir, "hostd.db"), log.Named("sqlite3")) | ||
if err != nil { | ||
log.Fatal("failed to open database", zap.Error(err)) | ||
} | ||
defer db.Close() | ||
|
||
log.Info("starting siad migration", zap.String("siadDir", dir), zap.Bool("destructive", destructive)) | ||
|
||
start := time.Now() | ||
if err := migrate.Siad(ctx, db, dir, destructive, log.Named("migrate")); err != nil { | ||
log.Fatal("siad migration failed", zap.Error(err)) | ||
} | ||
|
||
log.Info("siad migration complete!!!", zap.Duration("elapsed", time.Since(start))) | ||
log.Info("please start hostd with the same data directory as siad to continue using your host") | ||
log.Info("you will also need to generate a new 12-word wallet seed and send your balance from the old wallet to the new wallet") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.