Skip to content
This repository has been archived by the owner on Aug 29, 2018. It is now read-only.

fixes #21198 - unmounts/removes snapshots if failure #549

Merged
merged 1 commit into from
Oct 12, 2017

Conversation

cfouant
Copy link
Member

@cfouant cfouant commented Oct 4, 2017

No description provided.

@theforeman-bot
Copy link

Issues: #21198

@cfouant
Copy link
Member Author

cfouant commented Oct 4, 2017

@evgeni - could you review this please? You're the best versed at snapshots 💯

Copy link
Member

@evgeni evgeni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the change looks fine from a logic perspective, but I think we can refactor the code to be cleaner ;)

@@ -13,7 +13,7 @@ def error_message
end

def foreman_rpm_installed?
system("rpm -q foreman")
system("rpm -q foreman >/dev/null")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change relevant here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It prints the output needlessly, and since we aren't doing anything except distinguishing satellite from capsule, I don't think the output created should be displayed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has been fixed via http://projects.theforeman.org/issues/21219 now

@@ -32,6 +32,12 @@ def cleanup(exitstatus=-1)
puts "Cleaning up backup folder and starting any stopped services... "
FileUtils.cd("/")
FileUtils.rm_rf @dir unless @options[:no_subdir]
if @options[:snapshot]
@databases.each do |database|
system("umount #{File.join(@mountdir, database)} >/dev/null")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more or less duplicating code from https://github.com/cfouant/katello-packaging/blob/86547ae08f4eaebbddc6a5623ec847c68c42be41/katello/backup.rb#L195-L200, shall we move these lines into an own function and call it here and in L195?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was considering the same, however, I wanted to suppress the output here, as the output is terrible if there are no mounted filesystems. I will add that into the function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I think these do need to be kept separate. We want the process in backup/destroy to go through the run_cmd method; however, as we've previously found in calling run_cmd in cleanup, we can end up caught in an endless loop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha. right. I wonder if we should teach run_cmd something like "ignore_all_errors" next to the list of accepted exit codes. anyways, that is a discussion for another PR/redmine.

let me see how this code actually runs, and ack that PR afterwards.

would you mind adding a comment "not using run_cmd here because …" so that we don't forget that in the future?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely :)

if @options[:snapshot]
@databases.each do |database|
system("umount #{File.join(@mountdir, database)} >/dev/null")
system("lvremove -f #{get_snapshot_location(database)} >/dev/null")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should first get get_snapshot_location(database) and only execute lvremove if the get actually returned anything. Otherwise (when the snapshot in question does not exist), you end up with ugly errors:

No command with matching syntax recognised.  Run 'lvremove --help' for more information.
Correct command syntax is:

def cleanup(exitstatus=-1)
puts "Cleaning up backup folder and starting any stopped services... "
FileUtils.cd("/")
FileUtils.rm_rf @dir unless @options[:no_subdir]
if @options[:snapshot]
@databases.each do |database|
system("umount #{File.join(@mountdir, database)} >/dev/null")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will still output an error (but continue), if the mount point is not mounted:

umount: /var/snap/mongodb: mountpoint not found

@cfouant
Copy link
Member Author

cfouant commented Oct 6, 2017

@evgeni - thanks for the suggestions, thanks for testing!
@johnpmitsch - i changed the command in helper.rb because system() automatically returns true/false and is less expensive than backtick calls. (just learned this, and thinking we might want to test using system() throughout, although doubt it would work everywhere). Let me know what you think! I can take it out if you prefer.

# using backticks here so there is no output
`rpm -q foreman`
$?.success?
system("rpm -q foreman >/dev/null")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way works fine for me as long as there is no output. Do you mind adding a space after then > pipe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to update to anything across the scripts, using http://ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html#method-c-popen3 would be ideal. It starts a new external process that can be monitored. I'm not saying this should be done in this PR, but would be worth looking into more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely do not want to update across the scripts at this time. system() returns a true/false/nil value, and run_cmd returns output. Updating with the space now 👍

@@ -28,10 +28,20 @@ def initialize(foreman_proxy_content, foreman_proxy, program, accepted_scenarios
setup_opt_parser
end

# do not use run_cmd() inside this method, to avoid a recursive loop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind being a bit more verbose and say you aren't using run_cmd inside cleanup method because run_cmd calls cleanup and will cause an infinite loop? (I only ask because I was confused to where the loop would come from at first)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

@cfouant
Copy link
Member Author

cfouant commented Oct 11, 2017

ping @evgeni @johnpmitsch - could i haz re-review when you get the opportunity? Thanks!

@johnpmitsch
Copy link
Contributor

johnpmitsch commented Oct 11, 2017

LGTM 👍 (I'll let evgeni approve to merge)

if @options[:snapshot]
@databases.each do |database|
mount_location = File.join(@mountdir, database)
system("umount #{mount_location}") if system("mount | grep #{mount_location}")
Copy link
Member

@evgeni evgeni Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of doing mount | grep, how about that function:

def is_mounted(path)
  mounts = File.readlines('/proc/mounts')
  mounts.each do |mount|
    mount = mount.split
    return true if mount[1] == path
  end
  return false
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems much more costly and clunkier? I think it's also in the style guidelines to do avoid 'return true/false'.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about
if File.readlines('/proc/mounts').grep(/#{mount_location}).any?

Copy link
Member

@evgeni evgeni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 🐑

@jlsherrill jlsherrill merged commit 123c432 into Katello:master Oct 12, 2017
@jlsherrill
Copy link
Member

merged! thanks @cfouant !

@cfouant cfouant deleted the snap-cleanup branch October 16, 2017 18:58
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants