2017-11-28 22:45:10 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-12-19 17:05:32 +00:00
|
|
|
"encoding/json"
|
2017-11-28 22:45:10 +00:00
|
|
|
"errors"
|
2017-12-19 17:05:32 +00:00
|
|
|
"io"
|
2017-11-28 22:45:10 +00:00
|
|
|
"io/ioutil"
|
2017-11-29 13:32:26 +00:00
|
|
|
|
2017-11-28 22:45:10 +00:00
|
|
|
ipfscluster "github.com/ipfs/ipfs-cluster"
|
2017-12-19 17:05:32 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
2017-11-28 22:45:10 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/consensus/raft"
|
2017-11-29 13:32:26 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/state/mapstate"
|
2017-11-28 22:45:10 +00:00
|
|
|
)
|
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
var errNoSnapshot = errors.New("no snapshot found")
|
2017-12-08 00:04:14 +00:00
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
func upgrade() error {
|
|
|
|
newState, err := restoreStateFromDisk()
|
2017-12-05 03:46:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-12-19 17:05:32 +00:00
|
|
|
|
|
|
|
cfg, clusterCfg, _, _, consensusCfg, _, _, _, _ := makeConfigs()
|
2017-12-05 03:46:52 +00:00
|
|
|
|
|
|
|
err = cfg.LoadJSONFromFile(configPath)
|
2017-11-28 22:45:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
return raft.SnapshotSave(consensusCfg, newState, clusterCfg.ID)
|
|
|
|
}
|
2017-11-28 22:45:10 +00:00
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
func export(w io.Writer) error {
|
|
|
|
stateToExport, err := restoreStateFromDisk()
|
2017-11-28 22:45:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-12-19 17:05:32 +00:00
|
|
|
|
|
|
|
return exportState(stateToExport, w)
|
|
|
|
}
|
|
|
|
|
|
|
|
func restoreStateFromDisk() (*mapstate.MapState, error) {
|
|
|
|
cfg, _, _, _, consensusCfg, _, _, _, _ := makeConfigs()
|
|
|
|
|
|
|
|
err := cfg.LoadJSONFromFile(configPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
r, snapExists, err := raft.LastStateRaw(consensusCfg)
|
2017-11-28 22:45:10 +00:00
|
|
|
if !snapExists {
|
2017-12-19 17:05:32 +00:00
|
|
|
err = errNoSnapshot
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
stateFromSnap := mapstate.NewMapState()
|
|
|
|
err = stateFromSnap.Migrate(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return stateFromSnap, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func stateImport(r io.Reader) error {
|
|
|
|
cfg, clusterCfg, _, _, consensusCfg, _, _, _, _ := makeConfigs()
|
|
|
|
|
|
|
|
err := cfg.LoadJSONFromFile(configPath)
|
2017-11-28 22:45:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-12-19 17:05:32 +00:00
|
|
|
pinSerials := make([]api.PinSerial, 0)
|
|
|
|
dec := json.NewDecoder(r)
|
|
|
|
err = dec.Decode(&pinSerials)
|
2017-11-28 22:45:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-12-19 17:05:32 +00:00
|
|
|
|
|
|
|
stateToImport := mapstate.NewMapState()
|
|
|
|
for _, pS := range pinSerials {
|
|
|
|
err = stateToImport.Add(pS.ToPin())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return raft.SnapshotSave(consensusCfg, stateToImport, clusterCfg.ID)
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func validateVersion(cfg *ipfscluster.Config, cCfg *raft.Config) error {
|
|
|
|
state := mapstate.NewMapState()
|
|
|
|
r, snapExists, err := raft.LastStateRaw(cCfg)
|
|
|
|
if !snapExists && err != nil {
|
2017-12-06 12:45:35 +00:00
|
|
|
logger.Error("error before reading latest snapshot.")
|
2017-11-28 22:45:10 +00:00
|
|
|
} else if snapExists && err != nil {
|
2017-12-06 12:45:35 +00:00
|
|
|
logger.Error("error after reading last snapshot. Snapshot potentially corrupt.")
|
2017-11-28 22:45:10 +00:00
|
|
|
} else if snapExists && err == nil {
|
2018-01-15 19:03:14 +00:00
|
|
|
raw, err2 := ioutil.ReadAll(r)
|
|
|
|
if err2 != nil {
|
|
|
|
return err2
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|
2018-01-15 19:03:14 +00:00
|
|
|
err2 = state.Unmarshal(raw)
|
|
|
|
if err2 != nil {
|
2017-12-06 12:45:35 +00:00
|
|
|
logger.Error("error unmarshalling snapshot. Snapshot potentially corrupt.")
|
2018-01-15 19:03:14 +00:00
|
|
|
return err2
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|
2018-01-15 19:03:14 +00:00
|
|
|
if state.GetVersion() != mapstate.Version {
|
2017-11-28 22:45:10 +00:00
|
|
|
logger.Error("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
|
|
|
logger.Error("Out of date ipfs-cluster state is saved.")
|
|
|
|
logger.Error("To migrate to the new version, run ipfs-cluster-service state upgrade.")
|
|
|
|
logger.Error("To launch a node without this state, rename the consensus data directory.")
|
|
|
|
logger.Error("Hint, the default is .ipfs-cluster/ipfs-cluster-data.")
|
|
|
|
logger.Error("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
2017-12-19 17:05:32 +00:00
|
|
|
err = errors.New("outdated state version stored")
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|
|
|
|
} // !snapExists && err == nil // no existing state, no check needed
|
2017-12-19 17:05:32 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExportState saves a json representation of a state
|
|
|
|
func exportState(state *mapstate.MapState, w io.Writer) error {
|
|
|
|
// Serialize pins
|
|
|
|
pins := state.List()
|
|
|
|
pinSerials := make([]api.PinSerial, len(pins), len(pins))
|
|
|
|
for i, pin := range pins {
|
|
|
|
pinSerials[i] = pin.ToSerial()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write json to output file
|
|
|
|
enc := json.NewEncoder(w)
|
|
|
|
enc.SetIndent("", " ")
|
|
|
|
return enc.Encode(pinSerials)
|
2017-11-28 22:45:10 +00:00
|
|
|
}
|