V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
firejoke
V2EX  ›  Python

用 pyparted 在未分配分区创建新分区

  •  
  •   firejoke · Mar 22, 2019 · 2362 views
    This topic created in 2597 days ago, the information mentioned may be changed or developed.

    最近一个需求需要为块存储单独划出一块分区
    有可能是从空白分区,有可能是从空白磁盘
    需要实施人员能从页面选择,所以后端要能给出数据,方便前面图形化
    网上能找到的方法都是用 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

    Supplement 1  ·  Mar 28, 2019
    创建卷组可以用 lvm2py 模块,
    常用的方法有:
    查看有哪些卷组 LVM().vgscan()
    >> 返回由 VolumeGroup 实例组成的列表
    查看指定卷组用了哪些物理卷 vg_instance.pvscan()
    >> 返回由 PhysicalVolume 实例组成的列表
    创建卷组 LVM().create_vg(name, devices)
    >> 返回 vg_instance 参数内的 devices 必须是一个包含磁盘或分区路径的列表
    创建 vg LVM().get_vg(name, mode='r')
    >> 类似与 open 函数, 指定卷组名,和打开模式,默认是"读"模式
    3 replies    2019-07-15 12:33:13 +08:00
    E1n
        1
    E1n  
       Mar 22, 2019
    思路排版都不错啊
    firejoke
        2
    firejoke  
    OP
       Mar 24, 2019 via Android
    @E1n 毕竟还是踩了好多坑的~
    firejoke
        3
    firejoke  
    OP
       Jul 15, 2019
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2537 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 15:17 · PVG 23:17 · LAX 08:17 · JFK 11:17
    ♥ Do have faith in what you're doing.