Skip to content

Commit

Permalink
Do not restore old backups when the upgrade fails
Browse files Browse the repository at this point in the history
The backup only will be restored when the ID and VERSION_ID matches in
both, the current and backed os-release file.
  • Loading branch information
dgdavid committed Sep 18, 2018
1 parent c5449ff commit 4e7e600
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 16 deletions.
59 changes: 50 additions & 9 deletions src/modules/Update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -809,19 +809,60 @@ def clean_backup
::FileUtils.rm_r(File.join(Installation.destdir, BACKUP_DIR), :force => true, :secure => true)
end

# restores backup
# Restores the available backup(s)
#
# If the VERSION_ID in the backup os-release file matches with the value stored in
# /etc/os-release (see bsc#1097297), the available backup scripts (restores-*.sh) will be
# executed **in the expected order** (see bsc#1089643).
#
# @see #restore_backup?
def restore_backup
log.info "Restoring backup"
mounted_root = Installation.destdir
script_glob = File.join(mounted_root, BACKUP_DIR,"restore-*.sh")
# sort the scripts to execute them in the expected order
::Dir.glob(script_glob).sort.each do |path|
cmd = "sh #{path} #{File.join("/", mounted_root)}"
res = SCR.Execute(path(".target.bash_output"), cmd)
log.info "Restoring with script #{cmd} result: #{res}"
if restore_backup?
log.info "Restoring backup"

mounted_root = Installation.destdir
available_restore_scripts = ::Dir.glob(File.join(mounted_root, BACKUP_DIR, "restore-*.sh"))

available_restore_scripts.sort.each do |path|
cmd = "sh #{path} #{File.join("/", mounted_root)}"
res = SCR.Execute(path(".target.bash_output"), cmd)

log.info "Restoring with script #{cmd} result: #{res}"
end
else
log.error "Backup was not restored because its version info does not match"
end
end

# Check if backup must be restored, based on the version info (bsc#1097297)
#
# @see #version_from
#
# @return [Boolean] true if update and backup have the same VERSION_ID; false otherwise
def restore_backup?
current_release = Pathname.new("#{Installation.destdir}/etc/os-release")
backed_release = Pathname.new("#{Installation.destdir}/#{BACKUP_DIR}/os-release")

version_from(current_release) == version_from(backed_release)
end

# Returns the ID and VERSION_ID from given file
#
# @see https://www.freedesktop.org/software/systemd/man/os-release.html
#
# @param file [File|Pathname] Operating system identification file
#
# @return [String] a string holding the ID and VERSION_ID or empty if something went wrong
def version_from(file)
content = file.read
id = content[/^ID=.*/].split("=", 2).last
version_id = content[/^VERSION_ID=.*/].split("=", 2).last

"#{id}-#{version_id}"
rescue
""
end

publish :variable => :packages_to_install, :type => "integer"
publish :variable => :packages_to_update, :type => "integer"
publish :variable => :packages_to_remove, :type => "integer"
Expand Down
11 changes: 11 additions & 0 deletions test/data/etc/leap-15-os-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NAME="openSUSE Leap"
VERSION="15.0"
ID="opensuse-leap"
ID_LIKE="suse opensuse"
VERSION_ID="15.0"
PRETTY_NAME="openSUSE Leap 15.0"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:leap:15.0"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"

11 changes: 11 additions & 0 deletions test/data/etc/tw-os-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NAME="openSUSE Tumbleweed"
VERSION="20180911"
ID="opensuse-tumbleweed"
ID_LIKE="opensuse suse"
VERSION_ID="20180911"
PRETTY_NAME="openSUSE Tumbleweed"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:tumbleweed:20180911"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"

60 changes: 53 additions & 7 deletions test/update_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,63 @@ def default_SetDesktopPattern_stubs
end

describe "#restore_backup" do
it "call all restore scripts in backup directory" do
expect(::Dir).to receive(:glob).and_return(["restore-a.sh", "restore-b.sh"])
expect(Yast::SCR).to receive(:Execute).with(Yast::Path.new(".target.bash_output"), /sh .*restore-a.sh \/mnt/).
and_return({"exit" => 0})
expect(Yast::SCR).to receive(:Execute).with(Yast::Path.new(".target.bash_output"), /sh .*restore-b.sh \/mnt/).
and_return({"exit" => 0})
let(:os_release_pathname) { double }
let(:os_backup_release_pathname) { double }
let(:os_release_content) { File.new("#{DATA_DIR}/etc/leap-15-os-release").read }
let(:os_backup_release_content) { File.new("#{DATA_DIR}/etc/tw-os-release").read }

before do
allow(::Dir).to receive(:glob).and_return(["restore-a.sh", "restore-b.sh"])

allow(Pathname).to receive(:new)
.with("#{Yast::Installation.destdir}/etc/os-release")
.and_return(os_release_pathname)
allow(Pathname).to receive(:new)
.with("#{Yast::Installation.destdir}/#{Yast::UpdateClass::BACKUP_DIR}/os-release")
.and_return(os_backup_release_pathname)
allow(os_release_pathname).to receive(:read).and_return(os_release_content)
allow(os_backup_release_pathname).to receive(:read).and_return(os_backup_release_content)
end

it "check the release info files" do
expect(Pathname).to receive(:new)
.with("#{Yast::Installation.destdir}/etc/os-release")
expect(Pathname).to receive(:new)
.with("#{Yast::Installation.destdir}/#{Yast::UpdateClass::BACKUP_DIR}/os-release")

Yast::Update.restore_backup
end
end

context "when the release info match" do
let(:os_backup_release_content) { os_release_content }

it "call all restore scripts in backup directory" do
expect(Yast::SCR).to receive(:Execute)
.with(Yast::Path.new(".target.bash_output"), /sh .*restore-a.sh \/mnt/)
expect(Yast::SCR).to receive(:Execute)
.with(Yast::Path.new(".target.bash_output"), /sh .*restore-b.sh \/mnt/)

Yast::Update.restore_backup
end
end

context "when the release info does not match" do
it "logs an error" do
expect(Yast::Update.log).to receive(:error).with(/not restored/)

Yast::Update.restore_backup
end

it "does not continue" do
expect(Yast::SCR).to_not receive(:Execute)
.with(Yast::Path.new(".target.bash_output"), /sh .*restore-a.sh \/mnt/)
expect(Yast::SCR).to_not receive(:Execute)
.with(Yast::Path.new(".target.bash_output"), /sh .*restore-b.sh \/mnt/)

Yast::Update.restore_backup
end
end
end

describe "#SetDesktopPattern" do
context "if there is no definition of window manager upgrade path in control file" do
Expand Down

0 comments on commit 4e7e600

Please sign in to comment.