github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/backups/backups_linux.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build linux 5 6 package backups 7 8 import ( 9 "fmt" 10 11 "github.com/juju/errors" 12 "github.com/juju/names" 13 14 "github.com/juju/juju/agent" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/juju/paths" 17 "github.com/juju/juju/network" 18 "github.com/juju/juju/state" 19 ) 20 21 // Restore handles either returning or creating a state server to a backed up status: 22 // * extracts the content of the given backup file and: 23 // * runs mongorestore with the backed up mongo dump 24 // * updates and writes configuration files 25 // * updates existing db entries to make sure they hold no references to 26 // old instances 27 // * updates config in all agents. 28 func (b *backups) Restore(backupId string, args params.RestoreArgs) error { 29 meta, backupReader, err := b.Get(backupId) 30 if err != nil { 31 return errors.Annotatef(err, "could not fetch backup %q", backupId) 32 } 33 34 defer backupReader.Close() 35 36 workspace, err := NewArchiveWorkspaceReader(backupReader) 37 if err != nil { 38 return errors.Annotate(err, "cannot unpack backup file") 39 } 40 defer workspace.Close() 41 42 // TODO(perrito666) Create a compatibility table of sorts. 43 version := meta.Origin.Version 44 backupMachine := names.NewMachineTag(meta.Origin.Machine) 45 46 // delete all the files to be replaced 47 if err := PrepareMachineForRestore(); err != nil { 48 return errors.Annotate(err, "cannot delete existing files") 49 } 50 51 if err := workspace.UnpackFilesBundle(filesystemRoot()); err != nil { 52 return errors.Annotate(err, "cannot obtain system files from backup") 53 } 54 55 if err := updateBackupMachineTag(backupMachine, args.NewInstTag); err != nil { 56 return errors.Annotate(err, "cannot update paths to reflect current machine id") 57 } 58 59 var agentConfig agent.ConfigSetterWriter 60 datadir, err := paths.DataDir(args.NewInstSeries) 61 if err != nil { 62 return errors.Annotate(err, "cannot determine DataDir for the restored machine") 63 } 64 agentConfigFile := agent.ConfigPath(datadir, args.NewInstTag) 65 if agentConfig, err = agent.ReadConfig(agentConfigFile); err != nil { 66 return errors.Annotate(err, "cannot load agent config from disk") 67 } 68 ssi, ok := agentConfig.StateServingInfo() 69 if !ok { 70 return errors.Errorf("cannot determine state serving info") 71 } 72 agentConfig.SetValue("tag", args.NewInstTag.String()) 73 APIHostPort := network.HostPort{ 74 Address: network.Address{ 75 Value: args.PrivateAddress, 76 Type: network.DeriveAddressType(args.PrivateAddress), 77 }, 78 Port: ssi.APIPort} 79 agentConfig.SetAPIHostPorts([][]network.HostPort{{APIHostPort}}) 80 if err := agentConfig.Write(); err != nil { 81 return errors.Annotate(err, "cannot write new agent configuration") 82 } 83 84 // Restore mongodb from backup 85 if err := placeNewMongo(workspace.DBDumpDir, version); err != nil { 86 return errors.Annotate(err, "error restoring state from backup") 87 } 88 89 // Re-start replicaset with the new value for server address 90 dialInfo, err := newDialInfo(args.PrivateAddress, agentConfig) 91 if err != nil { 92 return errors.Annotate(err, "cannot produce dial information") 93 } 94 95 memberHostPort := fmt.Sprintf("%s:%d", args.PrivateAddress, ssi.StatePort) 96 err = resetReplicaSet(dialInfo, memberHostPort) 97 if err != nil { 98 return errors.Annotate(err, "cannot reset replicaSet") 99 } 100 101 err = updateMongoEntries(args.NewInstId, args.NewInstTag.Id(), dialInfo) 102 if err != nil { 103 return errors.Annotate(err, "cannot update mongo entries") 104 } 105 106 // From here we work with the restored state server 107 mgoInfo, ok := agentConfig.MongoInfo() 108 if !ok { 109 return errors.Errorf("cannot retrieve info to connect to mongo") 110 } 111 112 st, err := newStateConnection(mgoInfo) 113 if err != nil { 114 return errors.Trace(err) 115 } 116 defer st.Close() 117 118 // update all agents known to the new state server. 119 // TODO(perrito666): We should never stop process because of this. 120 // updateAllMachines will not return errors for individual 121 // agent update failures 122 machines, err := st.AllMachines() 123 if err != nil { 124 return errors.Trace(err) 125 } 126 if err = updateAllMachines(args.PrivateAddress, machines); err != nil { 127 return errors.Annotate(err, "cannot update agents") 128 } 129 130 info, err := st.EnsureRestoreInfo() 131 132 if err != nil { 133 return errors.Trace(err) 134 } 135 136 // Mark restoreInfo as Finished so upon restart of the apiserver 137 // the client can reconnect and determine if we where succesful. 138 err = info.SetStatus(state.RestoreFinished) 139 140 return errors.Annotate(err, "failed to set status to finished") 141 }