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

Proposed by Jeffrey C Jones
Status: Merged
Approved by: Andres Rodriguez
Approved revision: no longer in the source branch.
Merged at revision: 4576
Proposed branch: lp:~trapnine/maas/fix-1526542-1.10
Merge into: lp:maas/1.10
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.10
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+285062@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.

Backported from trunk.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

Voting does not meet specified criteria. Required: Approve >= 1, Disapprove == 0. Got: 1 Pending.

Revision history for this message
Andres Rodriguez (andreserl) :
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-17 19:55:54 +0000
+++ src/metadataserver/models/commissioningscript.py 2016-02-04 14:08:57 +0000
@@ -468,7 +468,8 @@
468 "ID_ATA_SATA": "SATA",468 "ID_ATA_SATA": "SATA",
469 "ID_ATA_ROTATION_RATE_RPM": "RPM"469 "ID_ATA_ROTATION_RATE_RPM": "RPM"
470 }470 }
471 del_blocks = []471 del_blocks = set()
472 seen_devices = set()
472 for block_info in blockdevs:473 for block_info in blockdevs:
473 # Some RAID devices return the name of the device seperated with "!",474 # Some RAID devices return the name of the device seperated with "!",
474 # but udevadm expects it to be a "/".475 # but udevadm expects it to be a "/".
@@ -489,7 +490,20 @@
489 if k == "ID_CDROM" and v == "1":490 if k == "ID_CDROM" and v == "1":
490 # Remove any type of CDROM from the blockdevs, as we491 # Remove any type of CDROM from the blockdevs, as we
491 # cannot use this device for installation.492 # cannot use this device for installation.
492 del_blocks.append(block_name)493 del_blocks.add(block_name)
494 break
495
496 if block_name in del_blocks:
497 continue
498
499 # Skip duplicate (serial, model) for multipath.
500 serial = block_info.get("SERIAL")
501 if serial:
502 model = block_info.get("MODEL", "").strip()
503 if (serial, model) in seen_devices:
504 del_blocks.add(block_name)
505 continue
506 seen_devices.add((serial, model))
493507
494 # Remove any devices that need to be removed.508 # Remove any devices that need to be removed.
495 blockdevs = [509 blockdevs = [
496510
=== modified file 'src/metadataserver/models/tests/test_commissioningscript.py'
--- src/metadataserver/models/tests/test_commissioningscript.py 2015-12-16 23:51:21 +0000
+++ src/metadataserver/models/tests/test_commissioningscript.py 2016-02-04 14:08:57 +0000
@@ -804,6 +804,242 @@
804 "RPM": "5400",804 "RPM": "5400",
805 }], self.call_gather_physical_block_devices(byidroot))805 }], self.call_gather_physical_block_devices(byidroot))
806806
807 def test__removes_duplicate_block_device_same_serial_and_model(self):
808 """Multipath disks get multiple IDs, but same serial/model is same
809 device and should only be enumerated once."""
810 name = factory.make_name('name')
811 model = factory.make_name('model')
812 serial = factory.make_name('serial')
813 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
814 block_size = random.choice([512, 1024, 4096])
815 check_output = self.patch(subprocess, "check_output")
816
817 name2 = factory.make_name('name')
818
819 # Create simulated /dev tree.
820 devroot = self.make_dir()
821 os.mkdir(os.path.join(devroot, 'disk'))
822 byidroot = os.path.join(devroot, 'disk', 'by_id')
823 os.mkdir(byidroot)
824
825 os.mknod(os.path.join(devroot, name))
826 os.symlink(os.path.join(devroot, name),
827 os.path.join(byidroot, 'deviceid'))
828
829 os.mknod(os.path.join(devroot, name2))
830 os.symlink(os.path.join(devroot, name2),
831 os.path.join(byidroot, 'deviceid2'))
832
833 check_output.side_effect = [
834 b"\n".join([
835 self.make_lsblk_output(name=name, model=model),
836 self.make_lsblk_output(name=name2, model=model)]),
837 self.make_udevadm_output(name, serial=serial, dev=devroot),
838 self.make_udevadm_output(name2, serial=serial, dev=devroot),
839 b'%d' % size,
840 b'%d' % block_size,
841 b'%d' % size,
842 b'%d' % block_size,
843 ]
844
845 self.assertEqual([{
846 "NAME": name,
847 "PATH": os.path.join(devroot, name),
848 "ID_PATH": os.path.join(byidroot, 'deviceid'),
849 "RO": "0",
850 "RM": "0",
851 "MODEL": model,
852 "ROTA": "1",
853 "SATA": "1",
854 "SERIAL": serial,
855 "SIZE": "%s" % size,
856 "BLOCK_SIZE": "%s" % block_size,
857 "RPM": "5400",
858 }], self.call_gather_physical_block_devices(byidroot))
859
860 def test__removes_duplicate_block_device_same_serial_blank_model(self):
861 """Multipath disks get multiple IDs, but same serial is same device."""
862 name = factory.make_name('name')
863 model = ""
864 serial = factory.make_name('serial')
865 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
866 block_size = random.choice([512, 1024, 4096])
867 check_output = self.patch(subprocess, "check_output")
868
869 name2 = factory.make_name('name')
870
871 # Create simulated /dev tree.
872 devroot = self.make_dir()
873 os.mkdir(os.path.join(devroot, 'disk'))
874 byidroot = os.path.join(devroot, 'disk', 'by_id')
875 os.mkdir(byidroot)
876
877 os.mknod(os.path.join(devroot, name))
878 os.symlink(os.path.join(devroot, name),
879 os.path.join(byidroot, 'deviceid'))
880
881 os.mknod(os.path.join(devroot, name2))
882 os.symlink(os.path.join(devroot, name2),
883 os.path.join(byidroot, 'deviceid2'))
884
885 check_output.side_effect = [
886 b"\n".join([
887 self.make_lsblk_output(name=name, model=model),
888 self.make_lsblk_output(name=name2, model=model)]),
889 self.make_udevadm_output(name, serial=serial, dev=devroot),
890 self.make_udevadm_output(name2, serial=serial, dev=devroot),
891 b'%d' % size,
892 b'%d' % block_size,
893 b'%d' % size,
894 b'%d' % block_size,
895 ]
896
897 self.assertEqual([{
898 "NAME": name,
899 "PATH": os.path.join(devroot, name),
900 "ID_PATH": os.path.join(byidroot, 'deviceid'),
901 "RO": "0",
902 "RM": "0",
903 "MODEL": model,
904 "ROTA": "1",
905 "SATA": "1",
906 "SERIAL": serial,
907 "SIZE": "%s" % size,
908 "BLOCK_SIZE": "%s" % block_size,
909 "RPM": "5400",
910 }], self.call_gather_physical_block_devices(byidroot))
911
912 def test__keeps_block_device_same_serial_different_model(self):
913 """Multipath disks get multiple IDs, but same serial is same device."""
914 name = factory.make_name('name')
915 model = factory.make_name('model')
916 serial = factory.make_name('serial')
917 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
918 block_size = random.choice([512, 1024, 4096])
919 check_output = self.patch(subprocess, "check_output")
920
921 name2 = factory.make_name('name')
922 model2 = factory.make_name('model')
923
924 # Create simulated /dev tree.
925 devroot = self.make_dir()
926 os.mkdir(os.path.join(devroot, 'disk'))
927 byidroot = os.path.join(devroot, 'disk', 'by_id')
928 os.mkdir(byidroot)
929
930 os.mknod(os.path.join(devroot, name))
931 os.symlink(os.path.join(devroot, name),
932 os.path.join(byidroot, 'deviceid'))
933
934 os.mknod(os.path.join(devroot, name2))
935 os.symlink(os.path.join(devroot, name2),
936 os.path.join(byidroot, 'deviceid2'))
937
938 check_output.side_effect = [
939 b"\n".join([
940 self.make_lsblk_output(name=name, model=model),
941 self.make_lsblk_output(name=name2, model=model2)]),
942 self.make_udevadm_output(name, serial=serial, dev=devroot),
943 self.make_udevadm_output(name2, serial=serial, dev=devroot),
944 b'%d' % size,
945 b'%d' % block_size,
946 b'%d' % size,
947 b'%d' % block_size,
948 ]
949
950 self.assertEqual([{
951 "NAME": name,
952 "PATH": os.path.join(devroot, name),
953 "ID_PATH": os.path.join(byidroot, 'deviceid'),
954 "RO": "0",
955 "RM": "0",
956 "MODEL": model,
957 "ROTA": "1",
958 "SATA": "1",
959 "SERIAL": serial,
960 "SIZE": "%s" % size,
961 "BLOCK_SIZE": "%s" % block_size,
962 "RPM": "5400",
963 }, {
964 "NAME": name2,
965 "PATH": os.path.join(devroot, name2),
966 "ID_PATH": os.path.join(byidroot, 'deviceid2'),
967 "RO": "0",
968 "RM": "0",
969 "MODEL": model2,
970 "ROTA": "1",
971 "SATA": "1",
972 "SERIAL": serial,
973 "SIZE": "%s" % size,
974 "BLOCK_SIZE": "%s" % block_size,
975 "RPM": "5400",
976 }], self.call_gather_physical_block_devices(byidroot))
977
978 def test__keeps_block_device_blank_serial_same_model(self):
979 """Multipath disks get multiple IDs, but same serial is same device."""
980 name = factory.make_name('name')
981 model = factory.make_name('model')
982 serial = ''
983 size = random.randint(3000 * 1000, 1000 * 1000 * 1000)
984 block_size = random.choice([512, 1024, 4096])
985 check_output = self.patch(subprocess, "check_output")
986
987 name2 = factory.make_name('name')
988
989 # Create simulated /dev tree.
990 devroot = self.make_dir()
991 os.mkdir(os.path.join(devroot, 'disk'))
992 byidroot = os.path.join(devroot, 'disk', 'by_id')
993 os.mkdir(byidroot)
994
995 os.mknod(os.path.join(devroot, name))
996 os.symlink(os.path.join(devroot, name),
997 os.path.join(byidroot, 'deviceid'))
998
999 os.mknod(os.path.join(devroot, name2))
1000 os.symlink(os.path.join(devroot, name2),
1001 os.path.join(byidroot, 'deviceid2'))
1002
1003 check_output.side_effect = [
1004 b"\n".join([
1005 self.make_lsblk_output(name=name, model=model),
1006 self.make_lsblk_output(name=name2, model=model)]),
1007 self.make_udevadm_output(name, serial=serial, dev=devroot),
1008 self.make_udevadm_output(name2, serial=serial, dev=devroot),
1009 b'%d' % size,
1010 b'%d' % block_size,
1011 b'%d' % size,
1012 b'%d' % block_size,
1013 ]
1014
1015 self.assertEqual([{
1016 "NAME": name,
1017 "PATH": os.path.join(devroot, name),
1018 "ID_PATH": os.path.join(byidroot, 'deviceid'),
1019 "RO": "0",
1020 "RM": "0",
1021 "MODEL": model,
1022 "ROTA": "1",
1023 "SATA": "1",
1024 "SERIAL": serial,
1025 "SIZE": "%s" % size,
1026 "BLOCK_SIZE": "%s" % block_size,
1027 "RPM": "5400",
1028 }, {
1029 "NAME": name2,
1030 "PATH": os.path.join(devroot, name2),
1031 "ID_PATH": os.path.join(byidroot, 'deviceid2'),
1032 "RO": "0",
1033 "RM": "0",
1034 "MODEL": model,
1035 "ROTA": "1",
1036 "SATA": "1",
1037 "SERIAL": serial,
1038 "SIZE": "%s" % size,
1039 "BLOCK_SIZE": "%s" % block_size,
1040 "RPM": "5400",
1041 }], self.call_gather_physical_block_devices(byidroot))
1042
807 def test__returns_block_device_without_id_path(self):1043 def test__returns_block_device_without_id_path(self):
808 """Block devices without by-id links should not have ID_PATH key"""1044 """Block devices without by-id links should not have ID_PATH key"""
809 name = factory.make_name('name')1045 name = factory.make_name('name')

Subscribers

People subscribed via source and target branches