Skip to content

Conversation

@vojtechtrefny
Copy link
Collaborator

@vojtechtrefny vojtechtrefny commented Aug 19, 2025

Full partitioning support and one related fix found during testing in safe mode.

Summary by Sourcery

Enable full multi-partition support by introducing a part_type option, enhancing partition lookup and ordering, validating partition constraints, and bolstering tests and documentation.

New Features:

  • Add part_type parameter to specify primary, extended, or logical partitions
  • Support creating, resizing, and removing multiple partitions per disk

Bug Fixes:

  • Fix device lookup to use devicetree.resolve_device before scanning disks
  • Adjust safe mode check to correctly detect existing disk formatting

Enhancements:

  • Implement partition ordering via weight for idempotent multi-partition creation
  • Handle zero-size volumes as full-disk partitions for backward compatibility
  • Validate extended/logical partition constraints on MSDOS disklabels

Documentation:

  • Document the new part_type parameter and its behavior in the README

Tests:

  • Add integration tests covering multiple partition operations on GPT and MSDOS/MBR, idempotence, resizing, encryption, and error scenarios

@sourcery-ai
Copy link

sourcery-ai bot commented Aug 19, 2025

Reviewer's Guide

Implements full multi‐partition support by introducing a part_type parameter, enriching BlivetPartitionVolume with partition type mapping and lookup logic, refining device resolution and safe_mode checks, adjusting imports for parted integration, and updating documentation with comprehensive GPT/MSDOS tests.

ER diagram for new part_type attribute in partition volumes

erDiagram
    VOLUME {
        string name
        string part_type
        string fs_type
        string size
        string encryption
        string mount_point
    }
    DISK {
        string name
        string label_type
    }
    VOLUME ||--|{ DISK : "on"
    VOLUME ||--|{ PARTITION : "contains"
    PARTITION {
        int number
        string part_type
        string fs_type
    }
Loading

Class diagram for updated BlivetPartitionVolume partition logic

classDiagram
    class BlivetPartitionVolume {
        +_update_from_device(param_name)
        +_get_part_by_partnum(partnum)
        +_get_device_id()
        +_get_part_weight()
        +_create()
        -_type_check()
        -_manage_cache()
    }
    BlivetPartitionVolume --|> BlivetVolume
    BlivetPartitionVolume : +part_type
    BlivetPartitionVolume : +fs_type
    BlivetPartitionVolume : +name
    BlivetPartitionVolume : +_blivet_pool
    BlivetPartitionVolume : +_device
    BlivetPartitionVolume : +_volume
    BlivetPartitionVolume : +_get_format()
    BlivetPartitionVolume : +_get_size()
    BlivetPartitionVolume : +_blivet
    BlivetPartitionVolume : +_get_part_weight()
    BlivetPartitionVolume : +_get_part_by_partnum()
    BlivetPartitionVolume : +_update_from_device()
    BlivetPartitionVolume : +_create()
    BlivetPartitionVolume : +_get_device_id()
    BlivetPartitionVolume : +_manage_cache()
Loading

File-Level Changes

Change Details Files
Add and document part_type parameter support
  • Define part_type as a new argument in module spec
  • Include part_type in run_module args
  • Update README with part_type description and behavior
library/blivet.py
README.md
Enrich BlivetPartitionVolume to handle multiple partitions
  • Implement _update_from_device to set part_type and unformatted fs for extended
  • Add _get_part_by_partnum and enhanced _get_device_id to resolve partitions by name or number
  • Introduce _get_part_weight for deterministic creation order
  • Extend _create to honor part_type mapping, size=0 fallback, GPT/MSDOS and encryption/mount constraints
library/blivet.py
Integrate parted into partitioning imports
  • Import re and add parted alongside do_partitioning for both blivet3 and blivet
  • Adjust import statements to include parted.PARTITION_* constants
library/blivet.py
Refine pool lookup and safe_mode format checks
  • Streamline _look_up_device to prefer resolved device over scanning disks
  • Tighten safe_mode logic to compare device.format.name against default format name
library/blivet.py
Add comprehensive tests for GPT and MSDOS scenarios
  • Create Ansible playbooks covering multi‐partition creation, resizing, idempotence, removal, encryption and failure cases
tests/tests_create_multiple_partitions_gpt.yml
tests/tests_create_multiple_partitions_dos.yml

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov
Copy link

codecov bot commented Aug 19, 2025

Codecov Report

❌ Patch coverage is 0% with 72 lines in your changes missing coverage. Please review.
✅ Project coverage is 10.37%. Comparing base (59fd1c6) to head (82f1c31).
⚠️ Report is 79 commits behind head on main.

Files with missing lines Patch % Lines
library/blivet.py 0.00% 72 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (59fd1c6) and HEAD (82f1c31). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (59fd1c6) HEAD (82f1c31)
sanity 1 0
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #552      +/-   ##
==========================================
- Coverage   16.54%   10.37%   -6.18%     
==========================================
  Files           2        8       +6     
  Lines         284     2015    +1731     
  Branches       79        0      -79     
==========================================
+ Hits           47      209     +162     
- Misses        237     1806    +1569     
Flag Coverage Δ
sanity ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vojtechtrefny vojtechtrefny force-pushed the main_partitioning branch 6 times, most recently from e1bb792 to c9bf341 Compare August 19, 2025 12:58
@vojtechtrefny
Copy link
Collaborator Author

[citest]

@vojtechtrefny vojtechtrefny force-pushed the main_partitioning branch 2 times, most recently from 2674c29 to fd4db30 Compare August 20, 2025 09:42
@vojtechtrefny vojtechtrefny marked this pull request as ready for review August 20, 2025 11:34
@vojtechtrefny
Copy link
Collaborator Author

[citest]

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `library/blivet.py:1000` </location>
<code_context>

-    def _resize(self):
-        pass
+    def _get_part_by_partnum(self, partnum):
+        return next((p for p in self._blivet_pool._disks[0].children if (p.parted_partition and p.parted_partition.number == partnum)),
+                    None)
+
+    def _get_device_id(self):
</code_context>

<issue_to_address>
The _get_part_by_partnum method assumes the first disk is always present and partitioned.

Add a guard clause to handle cases where _blivet_pool._disks is empty or the first disk lacks partitions to prevent exceptions.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
    def _get_part_by_partnum(self, partnum):
        return next((p for p in self._blivet_pool._disks[0].children if (p.parted_partition and p.parted_partition.number == partnum)),
                    None)
=======
    def _get_part_by_partnum(self, partnum):
        # Guard clause: ensure disks exist and first disk has children
        if not self._blivet_pool._disks:
            return None
        first_disk = self._blivet_pool._disks[0]
        if not hasattr(first_disk, "children") or not first_disk.children:
            return None
        return next(
            (p for p in first_disk.children if (p.parted_partition and p.parted_partition.number == partnum)),
            None
        )
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `library/blivet.py:1006` </location>
<code_context>
+
+    def _get_device_id(self):
+        name = self._volume['name']
+        if self._blivet_pool._disks[0].partitioned:
+            if name in (p.name for p in self._blivet_pool._disks[0].children):
+                # partition is specified by its name, e.g. "sda1"
+                return name
+            elif name and name.isdigit():
+                # partition is specified by its partition number, e.g. "1"
+                part = self._get_part_by_partnum(int(name))
+                if part:
+                    return os.path.basename(part.path)
+            elif name and name[-1].isdigit():
+                # this might be something like "test1", not really supported but we used it previously
</code_context>

<issue_to_address>
Direct access to _blivet_pool._disks[0] may be unsafe if the disk list is empty.

Please add a check to ensure _blivet_pool._disks is not empty before accessing its first element to prevent IndexError.
</issue_to_address>

### Comment 3
<location> `README.md:383` </location>
<code_context>
+  Supported values include `primary`, `extended` and `logical`.
+  If not specified, first three partitions on the disk will be created as primary and fourth
+  one will be created as logical inside a newly created extended partition.
+  `part_type` is ignored on GPT partition table.
+
 ### `storage_safe_mode`
</code_context>

<issue_to_address>
Consider pluralizing 'partition table' to 'partition tables'.

Change to: '`part_type` is ignored on GPT partition tables.'
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
  `part_type` is ignored on GPT partition table.
=======
  `part_type` is ignored on GPT partition tables.
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +1000 to +1002
def _get_part_by_partnum(self, partnum):
return next((p for p in self._blivet_pool._disks[0].children if (p.parted_partition and p.parted_partition.number == partnum)),
None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The _get_part_by_partnum method assumes the first disk is always present and partitioned.

Add a guard clause to handle cases where _blivet_pool._disks is empty or the first disk lacks partitions to prevent exceptions.

Suggested change
def _get_part_by_partnum(self, partnum):
return next((p for p in self._blivet_pool._disks[0].children if (p.parted_partition and p.parted_partition.number == partnum)),
None)
def _get_part_by_partnum(self, partnum):
# Guard clause: ensure disks exist and first disk has children
if not self._blivet_pool._disks:
return None
first_disk = self._blivet_pool._disks[0]
if not hasattr(first_disk, "children") or not first_disk.children:
return None
return next(
(p for p in first_disk.children if (p.parted_partition and p.parted_partition.number == partnum)),
None
)

Supported values include `primary`, `extended` and `logical`.
If not specified, first three partitions on the disk will be created as primary and fourth
one will be created as logical inside a newly created extended partition.
`part_type` is ignored on GPT partition table.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Consider pluralizing 'partition table' to 'partition tables'.

Change to: 'part_type is ignored on GPT partition tables.'

Suggested change
`part_type` is ignored on GPT partition table.
`part_type` is ignored on GPT partition tables.

This adds support for specifying size when creating a partition
volume and adding multiple partition volumes in one partition
pool.

Fixes: linux-system-roles#437
@richm
Copy link
Contributor

richm commented Aug 20, 2025

[citest]

@richm
Copy link
Contributor

richm commented Aug 29, 2025

[citest_bad]

Copy link
Contributor

@richm richm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@richm richm merged commit c95c03a into linux-system-roles:main Sep 3, 2025
43 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants