最近一个需求需要为块存储单独划出一块分区
有可能是从空白分区,有可能是从空白磁盘
需要实施人员能从页面选择,所以后端要能给出数据,方便前面图形化
网上能找到的方法都是用 Popen 调用 shell 命令, 私以为这样不够稳妥
遂找到了 pyparted 这个库,但几乎没有文档
只找到了一个别人写的范例
https://gist.github.com/herry13/5931cac426da99820de843477e41e89e
是整个磁盘重写整个分区表,参考着尝试了一下对已有分区表添加新分区
Let's think!
>>>import parted
>>>for d in parted.getAllDevices():
... print d
...
parted.Device instance --
model: VMware, VMware Virtual S path: /dev/sda type: 1
sectorSize: 512 physicalSectorSize: 512
length: 1048576000 openCount: 0 readOnly: False
externalMode: False dirty: False bootDirty: False
host: 0 did: 0 busy: True
hardwareGeometry: (65270, 255, 63) biosGeometry: (65270, 255, 63)
PedDevice: <_ped.Device object at 0x7f80d71459e0>
parted.Device instance --
model: VMware, VMware Virtual S path: /dev/sdb type: 1
sectorSize: 512 physicalSectorSize: 512
length: 2147483648 openCount: 0 readOnly: False
externalMode: False dirty: False bootDirty: False
host: 0 did: 1 busy: False
hardwareGeometry: (133674, 255, 63) biosGeometry: (133674, 255, 63)
PedDevice: <_ped.Device object at 0x7f80d7145a70>
parted.Device instance --
model: VMware, VMware Virtual S path: /dev/sdc type: 1
sectorSize: 512 physicalSectorSize: 512
length: 2147483648 openCount: 0 readOnly: False
externalMode: False dirty: False bootDirty: False
host: 0 did: 2 busy: False
hardwareGeometry: (133674, 255, 63) biosGeometry: (133674, 255, 63)
PedDevice: <_ped.Device object at 0x7f80d7145b00>
>>> device = parted.getAllDevices()[0]
虚拟机里三个磁盘,sda 给的是 500GB,系统分区是 100G,交换分区是 2G
>>> sda = parted.newDisk(device)
>>> sda.partitions
[<parted.partition.Partition object at 0x7f80d64d7550>, <parted.partition.Partition object at 0x7f80d64d7810>]
>>> partition = sda.getFirstPartition()
>>> while partition:
... print partition.path
... print partition.getSize(unit="GB")
... print partition.type
... print partition.geometry
... if partition.type == parted.PARTITION_FREESPACE and (397 < partition.getSize(unit="GB") < 398):
... par = partition
... partition = partition.nextPartition()
...
/dev/sda-1
3.00407409668e-05
8
parted.Geometry instance --
start: 0 end: 62 length: 63
device: <parted.device.Device object at 0x7f80d3461a10> PedGeometry: <_ped.Geometry object at 0x7f80d3461b10>
/dev/sda-1
0.000946521759033
4
parted.Geometry instance --
start: 63 end: 2047 length: 1985
device: <parted.device.Device object at 0x7f80d3461d10> PedGeometry: <_ped.Geometry object at 0x7f80d3461bd0>
/dev/sda1
100.0
0
parted.Geometry instance --
start: 2048 end: 209717247 length: 209715200
device: <parted.device.Device object at 0x7f80d3461a10> PedGeometry: <_ped.Geometry object at 0x7f80d34619d0>
/dev/sda2
2.0
0
parted.Geometry instance --
start: 209717248 end: 213911551 length: 4194304
device: <parted.device.Device object at 0x7f80d3461d10> PedGeometry: <_ped.Geometry object at 0x7f80d3461c90>
/dev/sda-1
397.992609978
4
parted.Geometry instance --
start: 213911552 end: 1048562549 length: 834650998
device: <parted.device.Device object at 0x7f80d3461b10> PedGeometry: <_ped.Geometry object at 0x7f80d3461950>
/dev/sda-1
0.00641345977783
8
parted.Geometry instance --
start: 1048562550 end: 1048575999 length: 13450
device: <parted.device.Device object at 0x7f80d3461bd0> PedGeometry: <_ped.Geometry object at 0x7f80d3461c10>
type 值在 _ped 里的定义分别是
PARTITION_NORMAL = 0
PARTITION_METADATA = 8
PARTITION_HPSERVICE = 8
PARTITION_FREESPACE = 4
PARTITION_HIDDEN = 4
>>> par
<parted.partition.Partition object at 0x7f80d34619d0>
>>> par.path
'/dev/sda-1'
>>> par.getSize()
407544.4326171875
>>> par.getSize(unit="GB")
397.99260997772217
按照那个范例的思想,用紧跟在交换分区后面的扇区位置来创建一个新的分区,
再添加到磁盘里
>>> sda.partitions
[<parted.partition.Partition object at 0x7f80d64d7550>, <parted.partition.Partition object at 0x7f80d64d7810>]
>>> sda.partitions[1]
<parted.partition.Partition object at 0x7f80d64d7810>
>>> sda.partitions[1].getSize()
2048.0
>>> sda.partitions[1].getSize(unit="GB")
2.0
>>> sda.partitions[1].geometry.end
213911551L
创建并添加
>>> geometry2 = parted.Geometry(start = sda.partitions[1].geometry.end, length = parted.sizeToSectors(397, "GB", device.sectorSize), device = device)
>>> filesystem2 = parted.FileSystem(type="xfs", geometry = geometry2)
>>> par2 = parted.Partition(disk = sda, type = parted.PARTITION_NORMAL, fs = filesystem2, geometry = geometry2)
>>> sda.addPartition(par2, constraint = device.optimalAlignedConstraint)
True
>>> sda.commit()
True
看看效果
>>> sda.partitions
[<parted.partition.Partition object at 0x7f80d3461f10>, <parted.partition.Partition object at 0x7f80d3467110>, <parted.partition.Partition object at 0x7f80d3467510>]
>>> partition = sda.getFirstPartition()
>>> while partition:
... print partition.path
... print partition.getSize(unit="GB")
... print partition.type
... print partition.geometry
... partition = partition.nextPartition()
...
/dev/sda-1
3.00407409668e-05
8
parted.Geometry instance --
start: 0 end: 62 length: 63
device: <parted.device.Device object at 0x7f80d64d7710> PedGeometry: <_ped.Geometry object at 0x7f80d3461f90>
/dev/sda-1
0.000946521759033
4
parted.Geometry instance --
start: 63 end: 2047 length: 1985
device: <parted.device.Device object at 0x7f80d64d74d0> PedGeometry: <_ped.Geometry object at 0x7f80d64d7890>
/dev/sda1
100.0
0
parted.Geometry instance --
start: 2048 end: 209717247 length: 209715200
device: <parted.device.Device object at 0x7f80d64d7710> PedGeometry: <_ped.Geometry object at 0x7f80d3461f90>
/dev/sda2
2.0
0
parted.Geometry instance --
start: 209717248 end: 213911551 length: 4194304
device: <parted.device.Device object at 0x7f80d64d74d0> PedGeometry: <_ped.Geometry object at 0x7f80d64d7850>
/dev/sda-1
7.818359375
4
parted.Geometry instance --
start: 213911552 end: 230307839 length: 16396288
device: <parted.device.Device object at 0x7f80d64d7990> PedGeometry: <_ped.Geometry object at 0x7f80d3461f90>
/dev/sda3
360.834960938
0
parted.Geometry instance --
start: 230307840 end: 987033599 length: 756725760
device: <parted.device.Device object at 0x7f80d64d7890> PedGeometry: <_ped.Geometry object at 0x7f80d64d7910>
/dev/sda-1
29.3392896652
4
parted.Geometry instance --
start: 987033600 end: 1048562549 length: 61528950
device: <parted.device.Device object at 0x7f80d64d7990> PedGeometry: <_ped.Geometry object at 0x7f80d3461f90>
/dev/sda-1
0.00641345977783
8
parted.Geometry instance --
start: 1048562550 end: 1048575999 length: 13450
device: <parted.device.Device object at 0x7f80d64d7410> PedGeometry: <_ped.Geometry object at 0x7f80d64d7850>
添加成功,但多了两个未分配的分区
占了 29.3 和 7.8,换个 filesystem type 试试
让我们销毁新建的分区重新来过
>>> sda.removePartition(par2)
True
>>> sda.commit()
True
>>> sda.partitions
[<parted.partition.Partition object at 0x7f80d64d7910>, <parted.partition.Partition object at 0x7f80d64d7410>]
换过 filesystem type 依然一样
从范例的参考来源发现一点点不同
https://github.com/dcantrell/pyparted/issues/38
讨论的调整分区的大小,用到了不一样的 constraint 这里是完全按生成的扇区对齐
constraint = parted.Constraint(exactGeom=geom)
在生成扇区那里改一下, 不指定长度, 将 start 和 end 指定为最后一个空闲分区的扇区 start 和 end
添加分区那里, 照葫芦画瓢
>>> geometry2 = parted.Geometry(start = sda.getFreeSpacePartitions()[1].geometry.start, end = sda.getFreeSpacePartitions()[1].geometry.end, device = device)
>>> filesystem2 = parted.FileSystem(type="ext4", geometry = geometry2)
>>> par2 = parted.Partition(disk = sda, type = parted.PARTITION_NORMAL, fs = filesystem2, geometry = geometry2)
>>> sda.addPartition(par2, constraint = parted.Constraint(exactGeom=geometry2))
True
>>> sda.commit()
True
检查一下
>>> sda.getFreeSpacePartitions()
[<parted.partition.Partition object at 0x7f80d3467e50>]
>>> partition = sda.getFirstPartition()
>>> while partition:
... print partition.path
... print partition.getSize(unit="GB")
... print partition.type
... print partition.geometry
... partition = partition.nextPartition()
...
/dev/sda-1
3.00407409668e-05
8
parted.Geometry instance --
start: 0 end: 62 length: 63
device: <parted.device.Device object at 0x7f80d3470a90> PedGeometry: <_ped.Geometry object at 0x7f80d3467e50>
/dev/sda-1
0.000946521759033
4
parted.Geometry instance --
start: 63 end: 2047 length: 1985
device: <parted.device.Device object at 0x7f80d3470c10> PedGeometry: <_ped.Geometry object at 0x7f80d3470710>
/dev/sda1
100.0
0
parted.Geometry instance --
start: 2048 end: 209717247 length: 209715200
device: <parted.device.Device object at 0x7f80d3470a90> PedGeometry: <_ped.Geometry object at 0x7f80d3467e50>
/dev/sda2
2.0
0
parted.Geometry instance --
start: 209717248 end: 213911551 length: 4194304
device: <parted.device.Device object at 0x7f80d3470c10> PedGeometry: <_ped.Geometry object at 0x7f80d3470a50>
/dev/sda3
397.992609978
0
parted.Geometry instance --
start: 213911552 end: 1048562549 length: 834650998
device: <parted.device.Device object at 0x7f80d3470910> PedGeometry: <_ped.Geometry object at 0x7f80d3467e50>
/dev/sda-1
0.00641345977783
8
parted.Geometry instance --
start: 1048562550 end: 1048575999 length: 13450
device: <parted.device.Device object at 0x7f80d3470710> PedGeometry: <_ped.Geometry object at 0x7f80d34708d0>
很好,但在系统的磁盘管理界面里,最后 type 为 8 的这个分区居然显示为 free space?
不过才 6M 多,影响不大
这里再一次感受到 py 的方便
也重温了一遍 Linux 磁盘相关知识
end