func (n *nomadFSM) Restore(old io.ReadCloser) error { defer old.Close() // Create a new state store newState, err := state.NewStateStore(n.logOutput) if err != nil { return err } n.state = newState // Start the state restore restore, err := newState.Restore() if err != nil { return err } defer restore.Abort() // Create a decoder dec := codec.NewDecoder(old, structs.MsgpackHandle) // Read in the header var header snapshotHeader if err := dec.Decode(&header); err != nil { return err } // Populate the new state msgType := make([]byte, 1) for { // Read the message type _, err := old.Read(msgType) if err == io.EOF { break } else if err != nil { return err } // Decode switch SnapshotType(msgType[0]) { case TimeTableSnapshot: if err := n.timetable.Deserialize(dec); err != nil { return fmt.Errorf("time table deserialize failed: %v", err) } case NodeSnapshot: node := new(structs.Node) if err := dec.Decode(node); err != nil { return err } if err := restore.NodeRestore(node); err != nil { return err } case JobSnapshot: job := new(structs.Job) if err := dec.Decode(job); err != nil { return err } // COMPAT: Remove in 0.5 // Empty maps and slices should be treated as nil to avoid // un-intended destructive updates in scheduler since we use // reflect.DeepEqual. Starting Nomad 0.4.1, job submission sanatizes // the incoming job. job.Canonicalize() if err := restore.JobRestore(job); err != nil { return err } case EvalSnapshot: eval := new(structs.Evaluation) if err := dec.Decode(eval); err != nil { return err } if err := restore.EvalRestore(eval); err != nil { return err } case AllocSnapshot: alloc := new(structs.Allocation) if err := dec.Decode(alloc); err != nil { return err } if err := restore.AllocRestore(alloc); err != nil { return err } case IndexSnapshot: idx := new(state.IndexEntry) if err := dec.Decode(idx); err != nil { return err } if err := restore.IndexRestore(idx); err != nil { return err } case PeriodicLaunchSnapshot: launch := new(structs.PeriodicLaunch) if err := dec.Decode(launch); err != nil { return err } if err := restore.PeriodicLaunchRestore(launch); err != nil { return err } case JobSummarySnapshot: summary := new(structs.JobSummary) if err := dec.Decode(summary); err != nil { return err } if err := restore.JobSummaryRestore(summary); err != nil { return err } case VaultAccessorSnapshot: accessor := new(structs.VaultAccessor) if err := dec.Decode(accessor); err != nil { return err } if err := restore.VaultAccessorRestore(accessor); err != nil { return err } default: return fmt.Errorf("Unrecognized snapshot type: %v", msgType) } } restore.Commit() // Create Job Summaries // COMPAT 0.4 -> 0.4.1 // We can remove this in 0.5. This exists so that the server creates job // summaries if they were not present previously. When users upgrade to 0.5 // from 0.4.1, the snapshot will contain job summaries so it will be safe to // remove this block. index, err := n.state.Index("job_summary") if err != nil { return fmt.Errorf("couldn't fetch index of job summary table: %v", err) } // If the index is 0 that means there is no job summary in the snapshot so // we will have to create them if index == 0 { // query the latest index latestIndex, err := n.state.LatestIndex() if err != nil { return fmt.Errorf("unable to query latest index: %v", index) } if err := n.state.ReconcileJobSummaries(latestIndex); err != nil { return fmt.Errorf("error reconciling summaries: %v", err) } } return nil }