New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow full migration of /dev/disk/by-id/devices #1450
Conversation
- Apply device mapping to diskbyid_mappings file to replace device in case of migration. - use full path in diskbyid_mappings file. - Add /etc/default/grub_installdevice to target FILES. - Use /dev/mapper/device instead of /dev/dm- device in diskbyid_mappings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't test it and trust your tests. Thanks.
# Apply device mapping to replace device in case of migration. | ||
tmp_layout="$LAYOUT_FILE" | ||
LAYOUT_FILE="$OLD_ID_FILE" | ||
source $SHARE_DIR/layout/prepare/default/320_apply_mappings.sh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather see the relevant code from the other script extracted into functions and those functions used here. That will help to create a clean interface for this functionality and it will help us with future refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I just wonder if I should add this new function to lib/layout-functions.sh
or create a new one named lib/apply-mappings-functions.sh
... or elsewhere ?
test -s "$sed_change_monitor" && sed_change=1 | ||
|
||
sed -i "s#$ID_FULL\$#/dev/$DEV_NAME#w $sed_change_monitor" "$realfile" | ||
test -s "$sed_change_monitor" && sed_change=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to check this file after every call of sed
? Isn't it enough to check it once at the end of the while
loop before printing out the change info?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file will be written by sed
if changes are made into $realfile
.
But it is overwritten (no append).
So if on the last sed
didn't make any change, the file $sed_change_monitor
will be empty even if a previous sed
made a change.
# udevinfo is deprecated by udevadm (SLES 10 still uses udevinfo) | ||
UdevSymlinkName="" | ||
type -p udevinfo >/dev/null && UdevSymlinkName="udevinfo -r / -q symlink -n" | ||
type -p udevadm >/dev/null && UdevSymlinkName="udevadm info --root --query=symlink --name" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we have this now more than once in the ReaR code I think that we would benefit from extracting that into a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question: where, in your opinion, should I put this function ?
UdevSymlinkName="" | ||
type -p udevinfo >/dev/null && UdevSymlinkName="udevinfo -r / -q symlink -n" | ||
type -p udevadm >/dev/null && UdevSymlinkName="udevadm info --root --query=symlink --name" | ||
|
||
[[ -z "$UdevQueryName" ]] && { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No check for UdevSymlinkName
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I'll do it
- move 320_apply_mappings.sh into function to be called by other scripts
@schabrolles I would put all these functions into |
@schlomo for your review. Tested during a disk migration on :
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think code like
test -z "$var" && BugIfError "..."
cannot work because *IfError functions
check if $? is not zero
(see lib/_input-output-functions.sh)
but '&&' means $? is zero.
E.g. on commandline:
# test -z "" && echo $? 0
I would keep it simple and do
test "$var" || BugError "..."
to ensure var is not empty and
test $var || BugError "..."
to ensure var is neither empty nor only spaces, cf. on commandline:
# var="" ; test "$var" || echo empty empty # var=" " ; test "$var" || echo empty # var=" " ; test $var || echo empty or blank empty or blank
In general, please try to use positive logic as much as possible. It helps a lot to read code and understand the logic. Good:
Bad:
The negated check makes one stop and think what does it actually mean. |
FYI: StopIfError "USB device '$USB_DEVICE' is already mounted on $(grep -E "^$REAL_USB_DEVICE\\s" /proc/mounts | cut -d' ' -f2 |tail -1)" did never error out as intended because the pipe after 'grep' always |
What about : |
for that type of thing I prefer |
@schabrolles test "$var" || Error "var must not be empty" or even test $var || Error "var must not be empty (or only spaces)" But technically test -z "$var" && Error "var must not be empty" is also right and sufficiently well understandable. In contrast oversophisticated stuff like ! test -z "$var" || Error "var must not be empty" is bad because it is needlessly hard to understand Ultimately it is your code so that the final decision |
I made evil typos in my prevois comment that I fixed now. test "$var" || Error "var must not be empty" and test $var || Error "var must not be empty (or only spaces)" @schabrolles BugError should only be used when the cause is a bug in ReaR. Error should be used when the cause is not in ReaR itself. For example when in script 100_prepare_it.sh a variable is set # var must have been set in 100_prepare_it.sh: test $var || BugError "var empty (or only spaces)" but in 100_prepare_it.sh it would be usually a test like # ... [ code that sets var ] ... test $var || Error "Failed to set var (empty or only spaces)" when the root cause why it failed to set var is not a bug in ReaR test $var || Error "var must not be empty (or only spaces)" |
- more info in (rear#1450)
@jsmeix If yes, I see this example (in
What so you think about this implementation ? |
@schabrolles |
@schabrolles if test $sed_change -eq 1 ; then which may show unwanted bash errors # sed_change=" 1 " ; if test $sed_change -eq 1 ; then echo OK ; fi OK # sed_change="X" ; if test $sed_change -eq 1 ; then echo OK ; fi -bash: test: X: integer expression expected # sed_change="" ; if test $sed_change -eq 1 ; then echo OK ; fi -bash: test: -eq: unary operator expected # unset sed_change ; if test $sed_change -eq 1 ; then echo OK ; fi -bash: test: -eq: unary operator expected # sed_change=" 1 " ; if test "$sed_change" -eq 1 ; then echo OK ; fi OK # sed_change="X" ; if test "$sed_change" -eq 1 ; then echo OK ; fi -bash: test: X: integer expression expected # sed_change="" ; if test "$sed_change" -eq 1 ; then echo OK ; fi -bash: test: : integer expression expected # unset sed_change ; if test "$sed_change" -eq 1 ; then echo OK ; fi -bash: test: : integer expression expected so that - as far as I know - all what one can do is to # Avoid stderr if sed_change is not set or empty or not an integer value: if test "$sed_change" -eq 1 2>/dev/null ; then (c.f. what I do in the UserInput function). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@schabrolles
I do no longer see real issues.
Feel free to merge it when it is o.k. for you.
I need to correct my wrong In general I would avoid the *IfError functions because they cannot work reliably in all cases because they test $? but $? can be an unexpected value That reason is nonsense because also COMMAND || Error "..." test the exit code (i.e. $?) of COMMAND. The actual reason why I avoid the *IfError functions # ( set -e ; cat qqq ; if (( $? != 0 )) ; then echo ERROR ; fi ) cat: qqq: No such file or directory # ( set -e ; cat qqq || echo ERROR ) cat: qqq: No such file or directory ERROR # ( set -e ; if ! cat qqq ; then echo ERROR ; fi ) cat: qqq: No such file or directory ERROR The crucial point is that 'cat qqq || echo ERROR' |
@schabrolles @jsmeix maybe I have an idea for a much simpler solution to the sed change monitor problem: Instead of writing to a special file write to STDOUT like this: $ rm changed
$ date > d ; sed -i -e 's/2017/XXX/w /dev/stdout' d >>changed
$ date > d ; sed -i -e 's/2016/XXX/w /dev/stdout' d >>changed
$ wc -l changed
1 changed
$ cat changed
Fr 25. Aug 13:15:10 CEST XXX
$ if test $(wc -l < changed) -gt 0 ; then echo changed ; fi
changed This trick also makes the code shorter and removes the need to reset the change tracking file every time. You can collect all the change infos from all the sed calls and then check in the end. The other thing I noticed is that there is no /g flag in the sed substitution which means that sed will only replace the first occurrence of an ID on a single line. If this is not intentional then better add |
@schlomo sed -i -e 's/THIS/THAT/gw /dev/stdout' file >>all_changes over sed -i -e 's/THIS/THAT/gw current_changes' file is that appending various sed's STDOUT into all_changes |
@jsmeix yes, that is the idea. Saves you from checking the result file after every sed call and counting the lines in this file avoids the problem with the quoting that you mentioned above. |
@schlomo thanks for the tip ... it is implemented now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, found some small things you can decide to leave or to improve.
|
||
# apply-mappings need one argument (file which contains disk device to migrate). | ||
if [ -z "$1" ] ; then | ||
LogError "apply-mappings function called without argument (file_to_migrate)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd call BugError
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. Do you think we should generalize this test for all the function which must have an argument ?
part_base="${original}p" # append p between main device and partitions | ||
;; | ||
*mapper[/!]*) | ||
case $OS_VENDOR in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this after @jsmeix changed the way it works, but I'd have expected here $OS_MASTER_VENDOR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then indeed it might be better to use $OS_MASTER_VENDOR
because it will catch you all Debian derivatives under Debian etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsmeix can you give me more information about this ?
- difference between
$OS_VENDOR
and$OS_MASTER_VENDOR
- Is there a variable which could act as a "family" name like FEDORA=(redhat,centos,fedora) DEBIAN=(ubuntu,debian).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsmeix Ok I got my answer from config-functions.sh
part_base="${original}p" # append p between main device and partitions | ||
fi | ||
;; | ||
Ubuntu) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about Debian?
# for example : /dev/mapper/mpatha-part1 | ||
part_base="${original}-part" # append -part between main device and partitions | ||
;; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about Arch, Gentoo etc.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have Arch or Gentoo (not available on POWER), so I don't know.
In the current script, they will use the default /dev/mapper/mpatha1
partition name scheme.
;; | ||
Ubuntu) | ||
# Ubuntu 16.04 (need to check for other version) named muiltipathed partitions with | ||
# [mapth device name] + "-part" + [part number] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should probably read
[mpath device name] + "-part" + [part number]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected. thanks
target="${target}p" # append p between main device and partitions | ||
;; | ||
*mapper[/!]*) | ||
case $OS_VENDOR in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above. Since this is the same logic, could you extract that into a function like format_device_name
or something like this? Makes it also easier to keep it in sync if something changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. I've named it get_part_device_name_format()
... it is a bit long, but format_device_name
sound a bit "dangerous" and make me nervous :) (=> formatting a device ????)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@schabrolles
don't worry when meaningful names become longer.
But worry about meaningful and unambiguous names
(unambiguous also means names that are not misleading)
cf. https://github.com/rear/rear/wiki/Coding-Style
@schabrolles |
Currently,
/dev/disk/by-id/
devices are not "always" migrated.finalize/GNU/Linux/260_rename_diskbyid.sh
script; but in its actual form, this script only migrate NEW by-id name if the real device (/dev/name) has the same name between source and target system.example: (
diskbyid_mappings
file)=>
/dev/disk/by-id/virtio-a1bd20bf-f66d-442c-8
will be renamed only if/dev/vda
is present on the target system./etc/lilo.conf /etc/yaboot.conf /etc/default/grub_installdevice
are not part of the list of file to be migrated byfinalize/GNU/Linux/260_rename_diskbyid.sh
/etc/default/grub_installdevice
is used in SuSe Linux and use/dev/disk/by-id/
devices to point to the bootloader partition. If we forget to migrate this file,yast bootloader
will fail.Proposal:
1- Add
/etc/lilo.conf /etc/yaboot.conf /etc/default/grub_installdevice
toFILES
variable infinalize/GNU/Linux/260_rename_diskbyid.sh
2- Use
$SHARE_DIR/layout/prepare/default/320_apply_mappings.sh
to apply device mapping ondiskbyid_mappings
file to migrate/dev/old_device
to/dev/new_device
in case of recover on a different system.Add this section at the beginning of
finalize/GNU/Linux/260_rename_diskbyid.sh
But, in order to migrate
real device
fromdiskbyid_mappings
file (second column), with320_apply_mappings.sh
, those one should be in absolute PATH.Tested with sles11 and sles12 on POWER
example of output with sles12 (/etc/default/grub_installdevice)