Merge lp:~trapnine/maas/fix-1526542-1.9 into lp:maas/1.9

Proposed by Jeffrey C Jones
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4539
Proposed branch: lp:~trapnine/maas/fix-1526542-1.9
Merge into: lp:maas/1.9
Diff against target: 282 lines (+252/-2)
2 files modified
src/metadataserver/models/commissioningscript.py (+16/-2)
src/metadataserver/models/tests/test_commissioningscript.py (+236/-0)
To merge this branch: bzr merge lp:~trapnine/maas/fix-1526542-1.9
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+285061@code.launchpad.net

Commit message

Skip block devices with duplicate serial numbers to fix multipath issue.

Description of the change

Skip block devices with duplicate serial numbers to fix multipath issue.

Backport from trunk.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/metadataserver/models/commissioningscript.py'
--- src/metadataserver/models/commissioningscript.py 2015-12-11 01:22:49 +0000
+++ src/metadataserver/models/commissioningscript.py 2016-02-04 13:53:50 +0000
@@ -476,7 +476,8 @@
476 "ID_ATA_SATA": "SATA",476 "ID_ATA_SATA": "SATA",
477 "ID_ATA_ROTATION_RATE_RPM": "RPM"477 "ID_ATA_ROTATION_RATE_RPM": "RPM"
478 }478 }
479 del_blocks = []479 del_blocks = set()
480 seen_devices = set()
480 for block_info in blockdevs:481 for block_info in blockdevs:
481 # Some RAID devices return the name of the device seperated with "!",482 # Some RAID devices return the name of the device seperated with "!",
482 # but udevadm expects it to be a "/".483 # but udevadm expects it to be a "/".
@@ -496,7 +497,20 @@
496 if k == "ID_CDROM" and v == "1":497 if k == "ID_CDROM" and v == "1":
497 # Remove any type of CDROM from the blockdevs, as we498 # Remove any type of CDROM from the blockdevs, as we
498 # cannot use this device for installation.499 # cannot use this device for installation.
499 del_blocks.append(block_name)500 del_blocks.add(block_name)
501 break
502
503 if block_name in del_blocks:
504 continue
505
506 # Skip duplicate (serial, model) for multipath.
507 serial = block_info.get("SERIAL")
508 if serial:
509 model = block_info.get("MODEL", "").strip()
510 if (serial, model) in seen_devices:
511 del_blocks.add(block_name)
512 continue
513 seen_devices.add((serial, model))
500514
501 # Remove any devices that need to be removed.515 # Remove any devices that need to be removed.
502 blockdevs = [516 blockdevs = [
503517
=== modified file 'src/metadataserver/models/tests/test_commissioningscript.py'
--- src/metadataserver/models/tests/test_commissioningscript.py 2015-10-27 20:53:16 +0000
+++ src/metadataserver/models/tests/test_commissioningscript.py 2016-02-04 13:53:50 +0000
@@ -776,6 +776,242 @@
776 "RPM": "5400",776 "RPM": "5400",
777 }], self.call_gather_physical_block_devices(byidroot))777 }], self.call_gather_physical_block_devices(byidroot))
778778
779 def test__removes_duplicate_block_device_same_serial_and_model(self):
780 """Multipath disks get multiple IDs, but same serial/model is same
781 device and should only be enumerated once."""
782 name = factory.make_name('name')
783 model = factory.make_name('model')
784 serial = factory.make_name('serial')
785 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
786 block_size = random.choice([512, 1024, 4096])
787 check_output = self.patch(subprocess, "check_output")
788
789 name2 = factory.make_name('name')
790
791 # Create simulated /dev tree.
792 devroot = self.make_dir()
793 os.mkdir(os.path.join(devroot, 'disk'))
794 byidroot = os.path.join(devroot, 'disk', 'by_id')
795 os.mkdir(byidroot)
796
797 os.mknod(os.path.join(devroot, name))
798 os.symlink(os.path.join(devroot, name),
799 os.path.join(byidroot, 'deviceid'))
800
801 os.mknod(os.path.join(devroot, name2))
802 os.symlink(os.path.join(devroot, name2),
803 os.path.join(byidroot, 'deviceid2'))
804
805 check_output.side_effect = [
806 b"\n".join([
807 self.make_lsblk_output(name=name, model=model),
808 self.make_lsblk_output(name=name2, model=model)]),
809 self.make_udevadm_output(name, serial=serial, dev=devroot),
810 self.make_udevadm_output(name2, serial=serial, dev=devroot),
811 b'%d' % size,
812 b'%d' % block_size,
813 b'%d' % size,
814 b'%d' % block_size,
815 ]
816
817 self.assertEqual([{
818 "NAME": name,
819 "PATH": os.path.join(devroot, name),
820 "ID_PATH": os.path.join(byidroot, 'deviceid'),
821 "RO": "0",
822 "RM": "0",
823 "MODEL": model,
824 "ROTA": "1",
825 "SATA": "1",
826 "SERIAL": serial,
827 "SIZE": "%s" % size,
828 "BLOCK_SIZE": "%s" % block_size,
829 "RPM": "5400",
830 }], self.call_gather_physical_block_devices(byidroot))
831
832 def test__removes_duplicate_block_device_same_serial_blank_model(self):
833 """Multipath disks get multiple IDs, but same serial is same device."""
834 name = factory.make_name('name')
835 model = ""
836 serial = factory.make_name('serial')
837 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
838 block_size = random.choice([512, 1024, 4096])
839 check_output = self.patch(subprocess, "check_output")
840
841 name2 = factory.make_name('name')
842
843 # Create simulated /dev tree.
844 devroot = self.make_dir()
845 os.mkdir(os.path.join(devroot, 'disk'))
846 byidroot = os.path.join(devroot, 'disk', 'by_id')
847 os.mkdir(byidroot)
848
849 os.mknod(os.path.join(devroot, name))
850 os.symlink(os.path.join(devroot, name),
851 os.path.join(byidroot, 'deviceid'))
852
853 os.mknod(os.path.join(devroot, name2))
854 os.symlink(os.path.join(devroot, name2),
855 os.path.join(byidroot, 'deviceid2'))
856
857 check_output.side_effect = [
858 b"\n".join([
859 self.make_lsblk_output(name=name, model=model),
860 self.make_lsblk_output(name=name2, model=model)]),
861 self.make_udevadm_output(name, serial=serial, dev=devroot),
862 self.make_udevadm_output(name2, serial=serial, dev=devroot),
863 b'%d' % size,
864 b'%d' % block_size,
865 b'%d' % size,
866 b'%d' % block_size,
867 ]
868
869 self.assertEqual([{
870 "NAME": name,
871 "PATH": os.path.join(devroot, name),
872 "ID_PATH": os.path.join(byidroot, 'deviceid'),
873 "RO": "0",
874 "RM": "0",
875 "MODEL": model,
876 "ROTA": "1",
877 "SATA": "1",
878 "SERIAL": serial,
879 "SIZE": "%s" % size,
880 "BLOCK_SIZE": "%s" % block_size,
881 "RPM": "5400",
882 }], self.call_gather_physical_block_devices(byidroot))
883
884 def test__keeps_block_device_same_serial_different_model(self):
885 """Multipath disks get multiple IDs, but same serial is same device."""
886 name = factory.make_name('name')
887 model = factory.make_name('model')
888 serial = factory.make_name('serial')
889 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
890 block_size = random.choice([512, 1024, 4096])
891 check_output = self.patch(subprocess, "check_output")
892
893 name2 = factory.make_name('name')
894 model2 = factory.make_name('model')
895
896 # Create simulated /dev tree.
897 devroot = self.make_dir()
898 os.mkdir(os.path.join(devroot, 'disk'))
899 byidroot = os.path.join(devroot, 'disk', 'by_id')
900 os.mkdir(byidroot)
901
902 os.mknod(os.path.join(devroot, name))
903 os.symlink(os.path.join(devroot, name),
904 os.path.join(byidroot, 'deviceid'))
905
906 os.mknod(os.path.join(devroot, name2))
907 os.symlink(os.path.join(devroot, name2),
908 os.path.join(byidroot, 'deviceid2'))
909
910 check_output.side_effect = [
911 b"\n".join([
912 self.make_lsblk_output(name=name, model=model),
913 self.make_lsblk_output(name=name2, model=model2)]),
914 self.make_udevadm_output(name, serial=serial, dev=devroot),
915 self.make_udevadm_output(name2, serial=serial, dev=devroot),
916 b'%d' % size,
917 b'%d' % block_size,
918 b'%d' % size,
919 b'%d' % block_size,
920 ]
921
922 self.assertEqual([{
923 "NAME": name,
924 "PATH": os.path.join(devroot, name),
925 "ID_PATH": os.path.join(byidroot, 'deviceid'),
926 "RO": "0",
927 "RM": "0",
928 "MODEL": model,
929 "ROTA": "1",
930 "SATA": "1",
931 "SERIAL": serial,
932 "SIZE": "%s" % size,
933 "BLOCK_SIZE": "%s" % block_size,
934 "RPM": "5400",
935 }, {
936 "NAME": name2,
937 "PATH": os.path.join(devroot, name2),
938 "ID_PATH": os.path.join(byidroot, 'deviceid2'),
939 "RO": "0",
940 "RM": "0",
941 "MODEL": model2,
942 "ROTA": "1",
943 "SATA": "1",
944 "SERIAL": serial,
945 "SIZE": "%s" % size,
946 "BLOCK_SIZE": "%s" % block_size,
947 "RPM": "5400",
948 }], self.call_gather_physical_block_devices(byidroot))
949
950 def test__keeps_block_device_blank_serial_same_model(self):
951 """Multipath disks get multiple IDs, but same serial is same device."""
952 name = factory.make_name('name')
953 model = factory.make_name('model')
954 serial = ''
955 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
956 block_size = random.choice([512, 1024, 4096])
957 check_output = self.patch(subprocess, "check_output")
958
959 name2 = factory.make_name('name')
960
961 # Create simulated /dev tree.
962 devroot = self.make_dir()
963 os.mkdir(os.path.join(devroot, 'disk'))
964 byidroot = os.path.join(devroot, 'disk', 'by_id')
965 os.mkdir(byidroot)
966
967 os.mknod(os.path.join(devroot, name))
968 os.symlink(os.path.join(devroot, name),
969 os.path.join(byidroot, 'deviceid'))
970
971 os.mknod(os.path.join(devroot, name2))
972 os.symlink(os.path.join(devroot, name2),
973 os.path.join(byidroot, 'deviceid2'))
974
975 check_output.side_effect = [
976 b"\n".join([
977 self.make_lsblk_output(name=name, model=model),
978 self.make_lsblk_output(name=name2, model=model)]),
979 self.make_udevadm_output(name, serial=serial, dev=devroot),
980 self.make_udevadm_output(name2, serial=serial, dev=devroot),
981 b'%d' % size,
982 b'%d' % block_size,
983 b'%d' % size,
984 b'%d' % block_size,
985 ]
986
987 self.assertEqual([{
988 "NAME": name,
989 "PATH": os.path.join(devroot, name),
990 "ID_PATH": os.path.join(byidroot, 'deviceid'),
991 "RO": "0",
992 "RM": "0",
993 "MODEL": model,
994 "ROTA": "1",
995 "SATA": "1",
996 "SERIAL": serial,
997 "SIZE": "%s" % size,
998 "BLOCK_SIZE": "%s" % block_size,
999 "RPM": "5400",
1000 }, {
1001 "NAME": name2,
1002 "PATH": os.path.join(devroot, name2),
1003 "ID_PATH": os.path.join(byidroot, 'deviceid2'),
1004 "RO": "0",
1005 "RM": "0",
1006 "MODEL": model,
1007 "ROTA": "1",
1008 "SATA": "1",
1009 "SERIAL": serial,
1010 "SIZE": "%s" % size,
1011 "BLOCK_SIZE": "%s" % block_size,
1012 "RPM": "5400",
1013 }], self.call_gather_physical_block_devices(byidroot))
1014
779 def test__returns_block_device_without_id_path(self):1015 def test__returns_block_device_without_id_path(self):
780 """Block devices without by-id links should not have ID_PATH key"""1016 """Block devices without by-id links should not have ID_PATH key"""
781 name = factory.make_name('name')1017 name = factory.make_name('name')

Subscribers

People subscribed via source and target branches