Skip to content

Server and Ilo interaction#4

Merged
chikatetsu merged 19 commits intomasterfrom
feat/server_interaction
Jul 12, 2025
Merged

Server and Ilo interaction#4
chikatetsu merged 19 commits intomasterfrom
feat/server_interaction

Conversation

@chikatetsu
Copy link
Contributor

@chikatetsu chikatetsu commented Jul 12, 2025

Summary by CodeRabbit

  • New Features

    • Added modules and scripts for server power control via iLO interface, including start and stop operations with error handling and CLI support.
    • Introduced JSON serialization for VMware vSphere objects to provide detailed VM and server information and metrics.
    • Added utilities to retrieve server info and metrics by MOID with CLI and Bash wrappers.
    • Developed VM migration functionality with validation, power management, and CLI support.
    • Created unified VM start and stop modules with improved error handling and CLI.
    • Added Bash scripts for all new Python utilities to ensure environment activation and parameter validation.
  • Refactor

    • Restructured server and VM shutdown/restart logic to support migration plans and integrated iLO server power management.
    • Consolidated VM listing logic into a reusable function with structured JSON output.
    • Updated configuration file format for nested host and iLO credentials and refined VM action ordering.
    • Refactored VM metrics retrieval into a dedicated function with improved error handling.
  • Bug Fixes

    • Enhanced error handling and messaging for invalid credentials, resource not found, and unsupported power states.
  • Chores

    • Removed deprecated scripts for VM power control and migration, consolidating functionality into new modular components.
    • Corrected script usage comments and updated script references for consistency.

@chikatetsu chikatetsu requested a review from jabibamman July 12, 2025 01:06
@chikatetsu chikatetsu self-assigned this Jul 12, 2025
@chikatetsu chikatetsu added the enhancement New feature or request label Jul 12, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 12, 2025

Walkthrough

The codebase introduces new modules for VM and server control, refactors data serialization into a dedicated DTO module, and restructures the migration plan data model for greater granularity. Several legacy scripts are removed and replaced with modular functions and CLI wrappers, supporting improved error handling and a more organized command structure.

Changes

File(s) / Group Change Summary
data_retriever/dto.py New module for serializing VMware objects (VMs, hosts, metrics) into JSON strings.
data_retriever/ilo.py New module with Ilo class for iLO Redfish API control (power on/off, status) and custom exception.
data_retriever/vm_ware_connection.py Removed legacy JSON formatting functions for VMs and error messages.
list_vm.py, vm_metrics.py Refactored to use new DTO functions for data formatting; logic moved into callable functions.
migrate.py, plan-example.yml Migration plan data model restructured: hosts and actions are now nested, with explicit iLO credentials and VM action orders. Migration/shutdown logic updated accordingly.
server_info.py, server_metrics.py New modules for retrieving server info and metrics via VMware API, with CLI support and structured JSON output.
server_start.py, server_stop.py New modules for starting/stopping servers via iLO; include error handling and CLI.
vm_migration.py New module for VM migration between hosts, with validation and CLI.
vm_start.py, vm_stop.py New modules for starting/stopping VMs, with robust error handling and CLI.
server_info.sh, server_metrics.sh, server_start.sh, server_stop.sh, vm_migration.sh, vm_start.sh, vm_stop.sh New Bash scripts for running corresponding Python modules with argument parsing and virtualenv activation.
ilo.py, migrate_vm.py, turn_off.py, turn_on.py Legacy scripts for iLO control, VM migration, and VM power on/off removed.
vm_start.sh, vm_stop.sh Usage comments and script invocation corrected to match new Python modules.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI_Script
    participant Python_Module
    participant VMware_API
    participant Ilo_API

    User->>CLI_Script: Run script with parameters
    CLI_Script->>Python_Module: Parse args, call function
    Python_Module->>VMware_API: (If VM/host op) Connect, retrieve object
    Python_Module->>Ilo_API: (If server op) Connect, send power command
    VMware_API-->>Python_Module: Return data/result
    Ilo_API-->>Python_Module: Return status/result
    Python_Module->>CLI_Script: Return JSON result
    CLI_Script->>User: Print output
Loading

Possibly related PRs

  • Migrate VMs #3: Modifies vm_ware_connection.py by changing VM and host lookup methods and JSON serialization functions, directly related to this PR’s removal of JSON formatting functions and refactoring of VMware object serialization.
  • List VMs #1: Adds initial standalone list_vm.py script with JSON serialization functions; related due to restructuring VM listing and serialization into DTOs.
  • VM Metrics #2: Refactors JSON serialization and VMware connection handling in list_vm.py and vm_ware_connection.py, related to the main PR’s serialization and connection refactoring.

Poem

In the warren of scripts, a change hops through,
With DTOs and CLIs, the structure feels new.
VMs and servers, all neat in a row,
With Bash and Python, their metrics now show.
A rabbit’s delight—so modular and bright!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5def7f8 and 27e23a2.

📒 Files selected for processing (3)
  • data_retriever/dto.py (1 hunks)
  • server_start.py (1 hunks)
  • server_stop.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • server_stop.py
  • data_retriever/dto.py
  • server_start.py
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🔭 Outside diff range comments (2)
vm_start.sh (1)

32-36: Avoid eval – this opens an unnecessary injection surface.
Because the command string is built from user-supplied values ($MOID, $IP, …), running it through eval allows arbitrary shell expansion. Pass the arguments directly instead:

- CMD="python vm_start.py --moid \"$MOID\" --ip \"$IP\" --user \"$USER\" --password \"$PASSWORD\""
- if [[ -n "$PORT" ]]; then
-     CMD+=" --port \"$PORT\""
- fi
- eval "$CMD"
+PY=python                       # or "$(command -v python)"
+ARGS=(vm_start.py --moid "$MOID" --ip "$IP" --user "$USER" --password "$PASSWORD")
+[[ -n "$PORT" ]] && ARGS+=(--port "$PORT")
+"$PY" "${ARGS[@]}"
vm_stop.sh (1)

32-36: Same eval injection risk as in vm_start.sh.
Apply the array-based invocation pattern suggested there.

🧹 Nitpick comments (10)
vm_start.sh (1)

1-2: Add strict-mode guards for safer bash scripting.

Consider adding set -euo pipefail right after the shebang to abort on the first error, catch unset variables, and propagate pipeline failures.

vm_stop.sh (1)

1-2: Enable strict mode for robustness.

server_start.sh (1)

1-2: Add set -euo pipefail for safer execution.

server_stop.sh (1)

1-2: Consider bash strict mode.

plan-example.yml (1)

12-22: Plain-text credentials in example – highlight secret-management.

Even in sample files, including real looking passwords encourages bad practice. Recommend replacing with placeholders and documenting secret storage (e.g., Vault, environment vars).

server_metrics.py (1)

38-43: Consider language consistency in CLI descriptions.

The CLI uses French descriptions while the codebase appears to primarily use English for comments and documentation. Consider using English for consistency, or ensure the language choice aligns with project standards.

-    parser = ArgumentParser(description="Récupérer les métriques d'un serveur")
-    parser.add_argument("--moid", required=True, help="Le Managed Object ID du serveur'")
-    parser.add_argument("--ip", required=True, help="Adresse IP du serveur ESXi ou du vCenter")
-    parser.add_argument("--user", required=True, help="Nom d'utilisateur du serveur ESXi ou du vCenter")
-    parser.add_argument("--password", required=True, help="Mot de passe du serveur ESXi ou du vCenter")
-    parser.add_argument("--port", type=int, default=443, help="Port du serveur ESXi ou du vCenter")
+    parser = ArgumentParser(description="Retrieve server metrics")
+    parser.add_argument("--moid", required=True, help="The Managed Object ID of the server")
+    parser.add_argument("--ip", required=True, help="IP address of the ESXi server or vCenter")
+    parser.add_argument("--user", required=True, help="Username for the ESXi server or vCenter")
+    parser.add_argument("--password", required=True, help="Password for the ESXi server or vCenter")
+    parser.add_argument("--port", type=int, default=443, help="Port for the ESXi server or vCenter")
vm_stop.py (1)

43-48: Consider language consistency in CLI descriptions.

Same language consistency issue as in server_metrics.py - consider using English descriptions for consistency across the codebase.

-    parser = ArgumentParser(description="Éteins une VM sur un serveur ESXi")
-    parser.add_argument("--moid", required=True, help="Le Managed Object ID de la VM")
-    parser.add_argument("--ip", required=True, help="Adresse IP du vCenter ou du serveur ESXi")
-    parser.add_argument("--user", required=True, help="Nom d'utilisateur du vCenter ou du serveur ESXi")
-    parser.add_argument("--password", required=True, help="Mot de passe du vCenter ou du serveur ESXi")
-    parser.add_argument("--port", type=int, default=443, help="Port du vCenter ou du serveur ESXi")
+    parser = ArgumentParser(description="Stop a VM on an ESXi server")
+    parser.add_argument("--moid", required=True, help="The Managed Object ID of the VM")
+    parser.add_argument("--ip", required=True, help="IP address of the vCenter or ESXi server")
+    parser.add_argument("--user", required=True, help="Username for the vCenter or ESXi server")
+    parser.add_argument("--password", required=True, help="Password for the vCenter or ESXi server")
+    parser.add_argument("--port", type=int, default=443, help="Port for the vCenter or ESXi server")
server_stop.py (1)

39-42: Language consistency issue in CLI descriptions.

Same language consistency issue as other files - consider using English for consistency.

vm_start.py (1)

43-48: Language consistency issue in CLI descriptions.

Consider using English descriptions for consistency with the broader codebase.

-    parser = ArgumentParser(description="Allume une VM sur un serveur ESXi")
-    parser.add_argument("--moid", required=True, help="Le Managed Object ID de la VM")
-    parser.add_argument("--ip", required=True, help="Adresse IP du vCenter ou du serveur ESXi")
-    parser.add_argument("--user", required=True, help="Nom d'utilisateur du vCenter ou du serveur ESXi")
-    parser.add_argument("--password", required=True, help="Mot de passe du vCenter ou du serveur ESXi")
-    parser.add_argument("--port", type=int, default=443, help="Port du vCenter ou serveur ESXi (optionnel, 443 par défaut)")
+    parser = ArgumentParser(description="Start a VM on an ESXi server")
+    parser.add_argument("--moid", required=True, help="The Managed Object ID of the VM")
+    parser.add_argument("--ip", required=True, help="IP address of the vCenter or ESXi server")
+    parser.add_argument("--user", required=True, help="Username for the vCenter or ESXi server")
+    parser.add_argument("--password", required=True, help="Password for the vCenter or ESXi server")
+    parser.add_argument("--port", type=int, default=443, help="Port for the vCenter or ESXi server (optional, default 443)")
data_retriever/dto.py (1)

5-5: Add type annotation for http_code parameter.

-def result_message(message: str, http_code) -> str:
+def result_message(message: str, http_code: int) -> str:
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4979769 and 48d90fa.

📒 Files selected for processing (25)
  • data_retriever/dto.py (1 hunks)
  • data_retriever/ilo.py (1 hunks)
  • data_retriever/vm_ware_connection.py (0 hunks)
  • ilo.py (0 hunks)
  • list_vm.py (2 hunks)
  • migrate.py (6 hunks)
  • migrate_vm.py (0 hunks)
  • plan-example.yml (1 hunks)
  • server_info.py (1 hunks)
  • server_info.sh (1 hunks)
  • server_metrics.py (1 hunks)
  • server_metrics.sh (1 hunks)
  • server_start.py (1 hunks)
  • server_start.sh (1 hunks)
  • server_stop.py (1 hunks)
  • server_stop.sh (1 hunks)
  • turn_off.py (0 hunks)
  • turn_on.py (0 hunks)
  • vm_metrics.py (2 hunks)
  • vm_migration.py (1 hunks)
  • vm_migration.sh (1 hunks)
  • vm_start.py (1 hunks)
  • vm_start.sh (2 hunks)
  • vm_stop.py (1 hunks)
  • vm_stop.sh (2 hunks)
💤 Files with no reviewable changes (5)
  • turn_off.py
  • data_retriever/vm_ware_connection.py
  • turn_on.py
  • migrate_vm.py
  • ilo.py
🧰 Additional context used
🧬 Code Graph Analysis (6)
server_info.py (2)
data_retriever/dto.py (2)
  • result_message (5-19)
  • server_info (92-123)
data_retriever/vm_ware_connection.py (4)
  • VMwareConnection (6-115)
  • connect (11-29)
  • get_host_system (93-115)
  • disconnect (31-36)
server_metrics.py (2)
data_retriever/dto.py (2)
  • result_message (5-19)
  • server_metrics_info (126-148)
data_retriever/vm_ware_connection.py (4)
  • VMwareConnection (6-115)
  • connect (11-29)
  • get_host_system (93-115)
  • disconnect (31-36)
server_stop.py (2)
data_retriever/dto.py (1)
  • result_message (5-19)
data_retriever/ilo.py (4)
  • Ilo (13-82)
  • PayloadException (7-10)
  • get_server_status (21-39)
  • start_server (52-61)
vm_stop.py (2)
data_retriever/dto.py (1)
  • result_message (5-19)
data_retriever/vm_ware_connection.py (4)
  • VMwareConnection (6-115)
  • connect (11-29)
  • get_vm (64-91)
  • disconnect (31-36)
vm_metrics.py (2)
data_retriever/dto.py (2)
  • vm_metrics_info (54-89)
  • result_message (5-19)
data_retriever/vm_ware_connection.py (4)
  • VMwareConnection (6-115)
  • connect (11-29)
  • get_vm (64-91)
  • disconnect (31-36)
vm_start.py (2)
data_retriever/dto.py (1)
  • result_message (5-19)
data_retriever/vm_ware_connection.py (4)
  • VMwareConnection (6-115)
  • connect (11-29)
  • get_vm (64-91)
  • disconnect (31-36)
🔇 Additional comments (15)
list_vm.py (1)

8-31: LGTM! Well-structured refactoring with proper error handling.

The function extraction improves modularity and the implementation demonstrates good practices:

  • Clear type hints and comprehensive docstring
  • Proper exception handling for VMware-specific errors
  • Guaranteed connection cleanup in finally block
  • Consistent use of the new DTO module for JSON formatting
server_metrics.sh (1)

1-37: LGTM! Consistent CLI wrapper pattern with proper validation.

The script demonstrates good practices:

  • Comprehensive parameter parsing and validation
  • Proper virtual environment activation with error handling
  • Secure command construction with quoted variables
  • Clear usage instructions for missing parameters

This aligns well with the consistent CLI wrapper pattern used across the project.

server_info.sh (1)

1-37: LGTM! Maintains consistency with other wrapper scripts.

The implementation follows the established pattern perfectly:

  • Proper argument parsing and validation
  • Robust virtual environment activation
  • Secure command construction and execution
  • Clear error messages and usage instructions
server_info.py (2)

8-35: LGTM! Well-implemented server data retrieval with proper error handling.

The function demonstrates excellent practices:

  • Clear type hints and comprehensive docstring
  • Proper VMware connection lifecycle management
  • Specific handling for authentication failures vs general errors
  • Appropriate HTTP-like status codes in error responses
  • Guaranteed connection cleanup

The integration with the DTO module provides consistent JSON formatting across the system.


37-47: LGTM! Clean CLI interface implementation.

The command-line interface is well-structured with:

  • Clear argument descriptions in French (consistent with other scripts)
  • Required parameter validation via argparse
  • Appropriate default port value
  • Direct function call with parsed arguments
vm_migration.sh (1)

1-17: LGTM! Good CLI wrapper pattern (after fixing validation).

The script follows the established pattern well:

  • Comprehensive parameter parsing for VM migration
  • Proper virtual environment handling
  • Secure command construction
  • Clear usage instructions

Once the validation bug is fixed, this will be consistent with other wrapper scripts.

Also applies to: 23-37

server_metrics.py (1)

8-35: LGTM! Well-structured server metrics retrieval function.

The implementation follows good practices with proper connection management, specific exception handling for authentication failures, and guaranteed cleanup in the finally block. The function signature and error responses are consistent with other modules in the codebase.

vm_stop.py (1)

9-40: LGTM! Robust VM stop implementation with proper state checking.

The function correctly:

  • Validates VM existence before operation
  • Checks current power state to avoid unnecessary operations
  • Uses synchronous task execution with WaitForTask
  • Handles authentication and general exceptions appropriately
  • Ensures connection cleanup in finally block
server_stop.py (1)

19-35: Good error handling structure but verify exception handling.

The error handling covers the main exception types well. However, ensure that the status codes returned by PayloadException are appropriate for the context.

vm_metrics.py (3)

4-5: LGTM! Good refactoring to use centralized DTO functions.

The import changes align well with the broader refactoring to centralize JSON serialization logic in the DTO module.


8-34: Excellent function extraction following consistent patterns.

The vm_metrics function follows the same pattern as other modules in this PR:

  • Clear parameter validation
  • Proper connection management
  • Specific exception handling for authentication
  • Guaranteed cleanup in finally block
  • Consistent error message formatting

This refactoring improves code reusability and maintainability.


47-47: Clean integration of the new function.

The main block is now properly simplified to just call the extracted function, making the code more testable and modular.

vm_start.py (1)

9-39: LGTM! Well-implemented VM start function with proper state management.

The implementation correctly:

  • Validates VM existence and current power state
  • Avoids unnecessary operations when VM is already running
  • Uses synchronous task execution for reliable operation
  • Handles exceptions appropriately with specific error codes
  • Ensures proper resource cleanup

The code follows the same reliable patterns as vm_stop.py.

server_start.py (1)

9-36: Well-structured server control implementation!

The function has excellent error handling with specific exception types and consistent JSON response formatting. The logic flow is clear and handles edge cases appropriately.

data_retriever/ilo.py (1)

80-82: Remove redundant status code check.

The status code check is redundant since raise_for_status() already raises an exception for non-2xx status codes, making this check unreachable for error responses.

Remove the redundant check:

         resp.raise_for_status()
-        if resp.status_code not in [200, 202, 204]:
-            raise PayloadException(resp.text, resp.status_code)

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
migrate.py (1)

203-207: Fix undefined variables and incorrect method usage.

This is the same issue flagged in previous reviews - the code still uses undefined args variables and incorrectly expects a boolean return from ilo.stop_server().

-            ilo = Ilo(args.ip, args.user, args.password)
-            if ilo.stop_server():
-                print(f"Server '{server.host.name}' ({server.host.moid}) is fully migrated")
-            else:
-                print(f"Couldn't stop server '{server.host.name}' ({server.host.moid})")
+            ilo = Ilo(server.host.ilo.ip, server.host.ilo.user, server.host.ilo.password)
+            try:
+                ilo.stop_server()
+                print(f"Server '{server.host.name}' ({server.host.moid}) is fully migrated")
+            except Exception as e:
+                print(f"Couldn't stop server '{server.host.name}' ({server.host.moid}): {e}")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48d90fa and 5def7f8.

📒 Files selected for processing (8)
  • data_retriever/dto.py (1 hunks)
  • data_retriever/ilo.py (1 hunks)
  • migrate.py (6 hunks)
  • server_start.sh (1 hunks)
  • server_stop.py (1 hunks)
  • server_stop.sh (1 hunks)
  • vm_migration.py (1 hunks)
  • vm_migration.sh (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • server_start.sh
  • data_retriever/dto.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • server_stop.sh
  • server_stop.py
  • vm_migration.sh
  • vm_migration.py
  • data_retriever/ilo.py
🧰 Additional context used
🪛 Ruff (0.11.9)
migrate.py

168-168: Local variable dist_ilo is assigned to but never used

Remove assignment to unused variable dist_ilo

(F841)

🔇 Additional comments (4)
migrate.py (4)

14-39: LGTM! Well-structured data model refactoring.

The introduction of granular dataclasses (Shutdown, Restart, IloYaml, Host, Server) provides better organization and type safety compared to the previous flatter structure. The nested relationships are logical and will improve maintainability.


80-108: LGTM! Robust YAML parsing with proper error handling.

The updated parsing logic correctly handles the new nested structure and includes appropriate error handling for missing keys. The conditional handling of optional destination servers is well implemented.


123-126: LGTM! Logical change to VM startup order.

Using the reversed shutdown order for VM startup is more intuitive than using a separate restart order, as it ensures VMs are started in the reverse order they were shut down.


159-159: LGTM! Power state enum issue has been resolved.

The code now correctly uses vim.HostSystem.PowerState.poweredOff instead of the incorrect vim.VirtualMachinePowerState.poweredOff that was flagged in previous reviews.

@chikatetsu chikatetsu merged commit eabfea5 into master Jul 12, 2025
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Jul 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants