Change:
return true, fmt.Errorf("fail to get etcd pod's hash: %v", err) } <del> // Write the updated etcd static Pod manifest into the temporary directory </del> <ins> // Write the updated etcd static Pod manifest into the temporary directory, at this point no etcd change // has occured in any aspects. </ins> if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.TempManifestDir(), cfg); err != nil { <del> return true, rollbackEtcdData(cfg, fmt.Errorf("error creating local etcd static pod manifest file: %v", err), pathMgr) </del> <ins> return true, fmt.Errorf("error creating local etcd static pod manifest file: %v", err) </ins> } // Perform etcd upgrade using common to all control plane components function if err := upgradeComponent(constants.Etcd, waiter, pathMgr, cfg, beforeEtcdPodHash, recoverManifests); err != nil { <del> return true, rollbackEtcdData(cfg, err, pathMgr) </del> <ins> // Since etcd upgrade component failed, the old manifest has been restored // now we need to check the heatlth of etcd cluster if it came back up with old manifest if _, err := etcdCluster.GetEtcdClusterStatus(); err != nil { // At this point we know that etcd cluster is dead and it is safe to copy backup datastore and to rollback old etcd manifest if err := rollbackEtcdData(cfg, fmt.Errorf("etcd cluster is not healthy after upgrade: %v rolling back", err), pathMgr); err != nil { // Even copying back datastore failed, no options for recovery left, bailing out return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } // Old datastore has been copied, rolling back old manifests if err := rollbackOldManifests(recoverManifests, err, pathMgr, true); err != nil { // Rolling back to old manifests failed, no options for recovery left, bailing out return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } // Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster if _, err := etcdCluster.GetEtcdClusterStatus(); err != nil { // Nothing else left to try to recover etcd cluster return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, rolled the state back to pre-upgrade state", err) } // Since etcd cluster came back up with the old manifest return true, fmt.Errorf("fatal error when trying to upgrade the etcd cluster: %v, rolled the state back to pre-upgrade state", err) </ins> } // Checking health state of etcd after the upgrade <del> etcdStatus, err = etcdCluster.GetEtcdClusterStatus() if err != nil { return true, rollbackEtcdData(cfg, fmt.Errorf("etcd cluster is not healthy after upgrade: %v rolling back", err), pathMgr) </del> <ins> if _, err = etcdCluster.GetEtcdClusterStatus(); err != nil { // Despite the fact that upgradeComponent was sucessfull, there is something wrong with etcd cluster // First step is to restore back up of datastore if err := rollbackEtcdData(cfg, fmt.Errorf("etcd cluster is not healthy after upgrade: %v rolling back", err), pathMgr); err != nil { // Even copying back datastore failed, no options for recovery left, bailing out return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } // Old datastore has been copied, rolling back old manifests if err := rollbackOldManifests(recoverManifests, err, pathMgr, true); err != nil { // Rolling back to old manifests failed, no options for recovery left, bailing out return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } // Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster if _, err := etcdCluster.GetEtcdClusterStatus(); err != nil { // Nothing else left to try to recover etcd cluster return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir) } return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, rolled the state back to pre-upgrade state", err) </ins> } return false, nil

Discussion:
kubeadm etcd upgrade modifying recovery steps /assign /sig cluster-lifecycle /kind bug