@@ -84,18 +84,22 @@ func NewUpgradeRecoveryAction(config *types.RunConfig, spec *types.UpgradeSpec,
8484 return u , nil
8585}
8686
87- func (u UpgradeRecoveryAction ) Info (s string , args ... interface {}) {
87+ func (u UpgradeRecoveryAction ) Infof (s string , args ... interface {}) {
8888 u .cfg .Logger .Infof (s , args ... )
8989}
9090
91- func (u UpgradeRecoveryAction ) Debug (s string , args ... interface {}) {
91+ func (u UpgradeRecoveryAction ) Debugf (s string , args ... interface {}) {
9292 u .cfg .Logger .Debugf (s , args ... )
9393}
9494
95- func (u UpgradeRecoveryAction ) Error (s string , args ... interface {}) {
95+ func (u UpgradeRecoveryAction ) Errorf (s string , args ... interface {}) {
9696 u .cfg .Logger .Errorf (s , args ... )
9797}
9898
99+ func (u UpgradeRecoveryAction ) Warnf (s string , args ... interface {}) {
100+ u .cfg .Logger .Warnf (s , args ... )
101+ }
102+
99103func (u * UpgradeRecoveryAction ) mountRWPartitions (cleanup * utils.CleanStack ) error {
100104 umount , err := elemental .MountRWPartition (u .cfg .Config , u .spec .Partitions .Recovery )
101105 if err != nil {
@@ -146,48 +150,79 @@ func (u *UpgradeRecoveryAction) Run() (err error) {
146150 return err
147151 }
148152
149- // Create recovery /boot dir if not exists
150- bootDir := filepath .Join (u .spec .Partitions .Recovery .MountPoint , "boot" )
151- if err := utils .MkdirAll (u .cfg .Fs , bootDir , constants .DirPerm ); err != nil {
152- u .cfg .Logger .Errorf ("failed creating recovery boot dir: %v" , err )
153- return elementalError .NewFromError (err , elementalError .CreateDir )
153+ // Remove any traces of previously errored upgrades
154+ transitionDir := filepath .Join (u .spec .Partitions .Recovery .MountPoint , constants .BootTransitionDir )
155+ u .Debugf ("removing any orphaned recovery system %s" , transitionDir )
156+ err = utils .RemoveAll (u .cfg .Fs , transitionDir )
157+ if err != nil {
158+ u .Errorf ("failed removing orphaned recovery image: %s" , err .Error ())
159+ return err
154160 }
155161
156- // Upgrade recovery
157- err = elemental .DeployRecoverySystem (u .cfg .Config , & u .spec .RecoverySystem , bootDir )
162+ // Deploy recovery system to transition dir
163+ err = elemental .DeployRecoverySystem (u .cfg .Config , & u .spec .RecoverySystem )
158164 if err != nil {
159- u .cfg .Logger .Errorf ("failed deploying recovery image: %v " , err )
165+ u .cfg .Logger .Errorf ("failed deploying recovery image: %s " , err . Error () )
160166 return elementalError .NewFromError (err , elementalError .DeployImage )
161167 }
162- recoveryFile := filepath .Join (u .spec .Partitions .Recovery .MountPoint , constants .RecoveryImgFile )
163- transitionFile := filepath .Join (u .spec .Partitions .Recovery .MountPoint , constants .TransitionImgFile )
164- if ok , _ := utils .Exists (u .cfg .Fs , recoveryFile ); ok {
165- err = u .cfg .Fs .Remove (recoveryFile )
168+
169+ // Switch places on /boot and transition-dir
170+ bootDir := filepath .Join (u .spec .Partitions .Recovery .MountPoint , constants .BootDir )
171+ oldBootDir := filepath .Join (u .spec .Partitions .Recovery .MountPoint , constants .OldBootDir )
172+
173+ // If a previous upgrade failed, remove old boot-dir
174+ err = utils .RemoveAll (u .cfg .Fs , oldBootDir )
175+ if err != nil {
176+ u .Errorf ("failed removing orphaned recovery image: %s" , err .Error ())
177+ return err
178+ }
179+
180+ // Rename current boot-dir in case we need to use it again
181+ if ok , _ := utils .Exists (u .cfg .Fs , bootDir ); ok {
182+ err = u .cfg .Fs .Rename (bootDir , oldBootDir )
166183 if err != nil {
167- u .Error ("failed removing old recovery image" )
184+ u .Errorf ("failed removing old recovery image: %s" , err . Error () )
168185 return err
169186 }
170187 }
171- err = u .cfg .Fs .Rename (transitionFile , recoveryFile )
188+
189+ // Move new boot-dir to /boot
190+ err = u .cfg .Fs .Rename (transitionDir , bootDir )
172191 if err != nil {
173- u .Error ("failed renaming transition recovery image" )
192+ u .cfg .Logger .Errorf ("failed renaming transition recovery image: %s" , err .Error ())
193+
194+ // Try to salvage old recovery system
195+ if ok , _ := utils .Exists (u .cfg .Fs , oldBootDir ); ok {
196+ err = u .cfg .Fs .Rename (oldBootDir , bootDir )
197+ if err != nil {
198+ u .cfg .Logger .Errorf ("failed salvaging old recovery system: %s" , err .Error ())
199+ }
200+ }
201+
174202 return err
175203 }
176204
205+ // Remove old boot-dir when new recovery system is in place
206+ err = utils .RemoveAll (u .cfg .Fs , oldBootDir )
207+ if err != nil {
208+ u .Warnf ("failed removing old recovery image: %s" , err .Error ())
209+ }
210+
177211 // Update state.yaml file on recovery and state partitions
178212 if u .updateInstallState {
179213 err = u .upgradeInstallStateYaml ()
180214 if err != nil {
181- u .Error ("failed upgrading installation metadata" )
215+ u .Errorf ("failed upgrading installation metadata: %s" , err . Error () )
182216 return err
183217 }
184218 }
185219
186- u .Info ("Recovery upgrade completed" )
220+ u .Infof ("Recovery upgrade completed" )
187221
188222 // Do not reboot/poweroff on cleanup errors
189223 err = cleanup .Cleanup (err )
190224 if err != nil {
225+ u .Errorf ("failed cleanup: %s" , err .Error ())
191226 return elementalError .NewFromError (err , elementalError .Cleanup )
192227 }
193228
0 commit comments