Skip to content

feat: Extra Node Selector and Tolerations - #65

Open
MessereN wants to merge 5 commits into
snakemake:mainfrom
MessereN:feature/podtolerationsandselectors
Open

feat: Extra Node Selector and Tolerations #65
MessereN wants to merge 5 commits into
snakemake:mainfrom
MessereN:feature/podtolerationsandselectors

Conversation

@MessereN

@MessereN MessereN commented Jan 5, 2026

Copy link
Copy Markdown

Added additional functionality in the plugin to account for new resource keys: node_role and node_taint.

node_role: Allows users to define in either default-resources or in rule specific resources to schedule jobs on labeled nodes.
cluster configuration: ie. node-labels=role=snakemake-exec
snakemake resource usage: ie. node_role=snakemake-exec

node_taint: Introduces a new resource key that enables users to specify custom taints on their nodes in order to craft the necessary tolerations for the pod to be scheduled on the tainted node(s). This can be initialized in either default-resources or within rule specific resources. The expected format of this resource is key=value:effect. It is essential to note that the only supported operator is "=" but perhaps in the future this can be expanded upon. Also, there are error mechanisms in place to account for proper formatting and ensuring that the effect is one of the supported NoSchedule, PreferNoSchedule, NoExecute.
cluster configuration: ie. node-taints=workload=snakemake:NoSchedule
snakemake resource usage: ie. node_taint=workload=snakemake:NoSchedule

These extra resources are useful for custom node taints and selectors on a GKE cluster so jobs can land properly on specific nodes/pools and have the associated tolerations.

Summary by CodeRabbit

  • New Features

    • Schedule workflow jobs on labeled burst‑pool nodes via configurable role assignment.
    • Add toleration handling for node taints so jobs can run on tainted nodes when configured.
    • Validate toleration configuration and show clear errors for invalid or unsupported formats.
  • Bug Fixes / Behavior

    • Simplified privileged container logic to apply consistently when enabled.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 5, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added optional node role scheduling via a node_role parameter (merged into node_selector) and introduced parsing/validation of node_taint strings to add Kubernetes Pod tolerations; invalid formats or unsupported effects raise WorkflowError. Also simplified privileged container handling: privileged context is now applied when self.privileged is true or DeploymentMethod.APPTAINER is in deployment_method.

Changes

Cohort / File(s) Summary
Node scheduling and toleration handling
snakemake_executor_plugin_kubernetes/__init__.py
Added optional node_role support by injecting role=<node_role> into node_selector and logging the change. Added node_taint parsing (expected key=value:effect), validation of format and allowed effects, conversion to V1Toleration with Equal operator, appending to pod tolerations, and logging. Invalid inputs raise WorkflowError. Retains existing GPU toleration and pod/spec construction flow.
Privileged container logic simplification
snakemake_executor_plugin_kubernetes/__init__.py
Replaced the prior complex capabilities/privileged checks with a simplified condition: privileged context applies when self.privileged is true or DeploymentMethod.APPTAINER is present in deployment_method, removing previous mixed checks and commented code.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Extra Node Selector and Tolerations' directly aligns with the main changes: adding node_role for node selectors and node_taint for tolerations in the Kubernetes executor plugin.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Fix all issues with AI Agents 🤖
In @snakemake_executor_plugin_kubernetes/__init__.py:
- Around line 220-251: Wrap the parsing of resources_dict["node_taint"] (the
toleration = str(...), key, rest = toleration.split("=", 1), value, effect =
rest.split(":", 1)) in a try/except that catches ValueError and raises a
WorkflowError with an informative message about the expected "key=value:effect"
format; keep the existing checks for empty parts and effect validity, and when
constructing the kubernetes.client.V1Toleration use consistent keyword spacing
(e.g., key=key, operator="Equal", value=value, effect=effect) and retain the
self.logger.debug call to log the added toleration.
🧹 Nitpick comments (2)
snakemake_executor_plugin_kubernetes/__init__.py (2)

206-209: Consider documenting or making the node selector label key configurable.

The implementation hardcodes "role" as the node selector key. While this may work for specific cluster setups, Kubernetes doesn't enforce a standard "role" label. Consider:

  • Documenting that users must label their nodes with role=<value> for this feature to work
  • Alternatively, making the label key configurable (e.g., node_role_label setting) to support different cluster labeling schemes
Example of configurable approach

If configurability is desired, you could allow users to specify the full label in the resource:

# Example: node_selector_label="custom-pool=snakemake-exec"
if "node_selector_label" in resources_dict:
    label_spec = str(resources_dict["node_selector_label"])
    if "=" in label_spec:
        key, value = label_spec.split("=", 1)
        node_selector[key] = value
    else:
        node_selector[label_spec] = "true"

However, the current implementation is acceptable if the role label is standard in your environment.


229-238: Optional: Consider the static analysis hint about exception messages.

The static analysis tool suggests avoiding long messages outside the exception class (TRY003). However, for this use case, the contextual error messages are appropriate and clear. You may safely ignore this hint, or if you prefer to address it, you could define custom exception subclasses.

This is a low-priority style suggestion and doesn't affect functionality. Based on coding guidelines for this project.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5f720e and cd465d5.

📒 Files selected for processing (1)
  • snakemake_executor_plugin_kubernetes/__init__.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • snakemake_executor_plugin_kubernetes/__init__.py
🪛 Ruff (0.14.10)
snakemake_executor_plugin_kubernetes/__init__.py

230-233: Avoid specifying long messages outside the exception class

(TRY003)


235-238: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (1)
snakemake_executor_plugin_kubernetes/__init__.py (1)

220-251: Integration with existing GPU tolerations is correct.

The node_taint toleration handling integrates well with the existing GPU toleration logic (lines 252-298). Both properly initialize pod_spec.tolerations if needed and can coexist, allowing pods to tolerate both custom taints and GPU-specific taints.

Comment thread snakemake_executor_plugin_kubernetes/__init__.py
@MessereN MessereN changed the title Feature: Extra Node Selector and Tolerations feat: Extra Node Selector and Tolerations Jan 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
snakemake_executor_plugin_kubernetes/__init__.py (1)

220-258: LGTM! Error handling and validation are solid.

The implementation correctly handles the node_taint resource with proper error handling for parsing failures and comprehensive validation. The try/except block at lines 227-234 addresses the parsing concern from the previous review.

Optionally, you can improve the exception chaining by using raise ... from None to indicate that the ValueError is intentionally being replaced:

🔎 Optional improvement for exception chaining
         try:
             key, rest = toleration.split("=", 1)
             value, effect = rest.split(":", 1)
         except ValueError:
-            raise WorkflowError(
+            raise WorkflowError(
                 f"Invalid node_taint format: '{toleration}'. "
                 "Expected format: key=value:effect"
-            )
+            ) from None

This makes it clearer that the ValueError is expected and being intentionally replaced with a more user-friendly WorkflowError.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd465d5 and 0f2a7b1.

📒 Files selected for processing (1)
  • snakemake_executor_plugin_kubernetes/__init__.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • snakemake_executor_plugin_kubernetes/__init__.py
🪛 Ruff (0.14.10)
snakemake_executor_plugin_kubernetes/__init__.py

231-234: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


231-234: Avoid specifying long messages outside the exception class

(TRY003)


237-240: Avoid specifying long messages outside the exception class

(TRY003)


242-245: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (1)
snakemake_executor_plugin_kubernetes/__init__.py (1)

206-209: No changes needed — the hardcoded "role" label key is intentional.

The code comment explicitly documents that this feature is for scheduling on GKE burst-pool nodes using the role label key (e.g., role=snakemake-exec). The hardcoding is not a flexibility issue but rather the correct implementation for this specific use case. The role label is the standard convention for GKE burst pools, and the design is properly documented in the code.

Likely an incorrect or invalid review comment.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@snakemake_executor_plugin_kubernetes/__init__.py`:
- Around line 254-257: The log message in the logger.debug call incorrectly
hardcodes the prefix "workload=" while emitting the value from
resources_dict['node_taint']; update the message to use a generic or accurate
label (e.g., "taint=" or "node_taint=") and/or interpolate the actual key name
instead of "workload" so the output matches the value; modify the call to
logger.debug(...) that references resources_dict['node_taint'] to something like
"Added taint toleration: taint={resources_dict['node_taint']}" (or
"node_taint={...}") to remove the misleading "workload=" prefix.
🧹 Nitpick comments (2)
snakemake_executor_plugin_kubernetes/__init__.py (2)

230-234: Chain the exception for better debugging.

When re-raising in an except block, use from err to preserve the original traceback, which aids debugging.

♻️ Proposed fix
-            except ValueError:
+            except ValueError as err:
                 raise WorkflowError(
                     f"Invalid node_taint format: '{toleration}'. "
                     "Expected format: key=value:effect"
-                )
+                ) from err

306-312: Duplicate privileged container handling.

The security context is set at lines 306-312, and then again at lines 400-405 when self.privileged is True. This creates redundant code - when self.privileged=True, the context is assigned twice.

Consider consolidating this logic. The block at lines 400-405 could be removed entirely, or the condition at line 306 could be simplified to only handle the APPTAINER case (since the self.privileged case is handled later with logging).

♻️ Option 1: Remove the redundant block at lines 400-405

Add logging to the first block and remove the second:

 # capabilities
 if self.privileged or (
     DeploymentMethod.APPTAINER
     in self.workflow.deployment_settings.deployment_method
 ):
     container.security_context = kubernetes.client.V1SecurityContext(
         privileged=True
     )
+    self.logger.debug("Container set to run in privileged mode.")

Then delete lines 400-405.

♻️ Option 2: Keep blocks separate but avoid duplicate assignment
 # capabilities
-if self.privileged or (
-    DeploymentMethod.APPTAINER
+if (
+    DeploymentMethod.APPTAINER
     in self.workflow.deployment_settings.deployment_method
 ):
     container.security_context = kubernetes.client.V1SecurityContext(
         privileged=True
     )
+    self.logger.debug("Container set to run in privileged mode (APPTAINER).")

This keeps the APPTAINER-specific handling separate from the explicit privileged flag handling at lines 400-405.

Also applies to: 400-405

Comment on lines +254 to +257
self.logger.debug(
"Added workload taint toleration: "
f"workload={resources_dict['node_taint']}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Misleading log message prefix.

The log hardcodes "workload=" but the toleration key can be any value, not just "workload". If node_taint="foo=bar:NoSchedule", this logs "workload=foo=bar:NoSchedule" which is confusing.

🐛 Proposed fix
             self.logger.debug(
-                "Added workload taint toleration: "
-                f"workload={resources_dict['node_taint']}"
+                f"Added taint toleration: {resources_dict['node_taint']}"
             )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.logger.debug(
"Added workload taint toleration: "
f"workload={resources_dict['node_taint']}"
)
self.logger.debug(
f"Added taint toleration: {resources_dict['node_taint']}"
)
🤖 Prompt for AI Agents
In `@snakemake_executor_plugin_kubernetes/__init__.py` around lines 254 - 257, The
log message in the logger.debug call incorrectly hardcodes the prefix
"workload=" while emitting the value from resources_dict['node_taint']; update
the message to use a generic or accurate label (e.g., "taint=" or "node_taint=")
and/or interpolate the actual key name instead of "workload" so the output
matches the value; modify the call to logger.debug(...) that references
resources_dict['node_taint'] to something like "Added taint toleration:
taint={resources_dict['node_taint']}" (or "node_taint={...}") to remove the
misleading "workload=" prefix.

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.

1 participant