-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test(robot): add test case Test Longhorn components recovery #2143
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,3 +66,19 @@ Check all Longhorn CRD removed | |
|
||
Install Longhorn | ||
install_longhorn_system | ||
|
||
Delete instance-manager of volume ${volume_id} | ||
${volume_name} = generate_name_with_suffix volume ${volume_id} | ||
${node_name} = get_volume_node ${volume_name} | ||
${pod_name} = get_instance_manager_on_node ${node_name} | ||
delete_pod ${pod_name} longhorn-system | ||
|
||
Delete instance-manager of deployment ${deployment_id} volume | ||
${deployment_name} = generate_name_with_suffix deployment ${deployment_id} | ||
${volume_name} = get_workload_volume_name ${deployment_name} | ||
${node_name} = get_volume_node ${volume_name} | ||
${pod_name} = get_instance_manager_on_node ${node_name} | ||
delete_pod ${pod_name} longhorn-system | ||
Comment on lines
+76
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor to reduce code duplication and add error handling This keyword shares similar logic with
Example refactor: +Delete instance-manager pod
+ [Arguments] ${node_name}
+ ${pod_name} = get_instance_manager_on_node ${node_name}
+ Should Not Be Equal ${pod_name} ${None} Instance manager pod not found on node ${node_name}
+ delete_pod ${pod_name} longhorn-system
+ Wait Until Keyword Succeeds 30s 5s Should Not Exist pod ${pod_name} longhorn-system
Delete instance-manager of deployment ${deployment_id} volume
${deployment_name} = generate_name_with_suffix deployment ${deployment_id}
+ ${deployment_exists} = Run Keyword And Return Status get_workload_volume_name ${deployment_name}
+ Run Keyword If not ${deployment_exists} Fail Deployment ${deployment_name} not found
${volume_name} = get_workload_volume_name ${deployment_name}
${node_name} = get_volume_node ${volume_name}
- ${pod_name} = get_instance_manager_on_node ${node_name}
- delete_pod ${pod_name} longhorn-system
+ Delete instance-manager pod ${node_name}
|
||
|
||
Wait for Longhorn components all running | ||
wait_for_namespace_pods_running longhorn-system | ||
Comment on lines
+83
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding a configurable timeout parameter The keyword looks good but consider adding a timeout parameter to handle environments where pod startup might take longer. Example enhancement: -Wait for Longhorn components all running
+Wait for Longhorn components all running
+ [Arguments] ${timeout}=300s
- wait_for_namespace_pods_running longhorn-system
+ wait_for_namespace_pods_running longhorn-system timeout=${timeout}
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
from backing_image.base import Base | ||
from backing_image.rest import Rest | ||
|
||
from backing_image.crd import CRD | ||
from strategy import LonghornOperationStrategy | ||
|
||
|
||
|
@@ -30,3 +30,19 @@ def delete(self, bi_name): | |
|
||
def cleanup_backing_images(self): | ||
return self.backing_image.cleanup_backing_images() | ||
|
||
def delete_backing_image_manager(self, name): | ||
self.backing_image = CRD() | ||
return self.backing_image.delete_backing_image_manager(name) | ||
|
||
def wait_all_backing_image_managers_running(self): | ||
self.backing_image = CRD() | ||
return self.backing_image.wait_all_backing_image_managers_running() | ||
|
||
def wait_backing_image_manager_restart(self, name, last_creation_time): | ||
self.backing_image = CRD() | ||
self.backing_image.wait_backing_image_manager_restart(name, last_creation_time) | ||
|
||
def list_backing_image_manager(self): | ||
self.backing_image = CRD() | ||
return self.backing_image.list_backing_image_manager() | ||
Comment on lines
+34
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification The shell script results provide clear evidence about the strategy pattern implementation across the codebase. Let me generate the final response: Strategy pattern implementation needs revision to match codebase standards The current implementation in
Here's the correct implementation matching the codebase standards: def __init__(self):
if self._strategy == LonghornOperationStrategy.CRD:
self.backing_image = CRD()
else:
self.backing_image = Rest() Remove the redundant CRD instantiation from:
🔗 Analysis chainStrategy pattern implementation needs revision The current implementation has several architectural concerns:
Consider refactoring to:
class BackingImage(Base):
_strategy = LonghornOperationStrategy.REST
def __init__(self):
if self._strategy == LonghornOperationStrategy.REST:
self.backing_image = Rest()
+ else:
+ self.backing_image = CRD()
def delete_backing_image_manager(self, name):
- self.backing_image = CRD()
return self.backing_image.delete_backing_image_manager(name)
def __init__(self):
self.rest_client = Rest()
self.crd_client = CRD() The def wait_backing_image_manager_restart(self, name, last_creation_time):
self.backing_image = CRD()
- self.backing_image.wait_backing_image_manager_restart(name, last_creation_time)
+ return self.backing_image.wait_backing_image_manager_restart(name, last_creation_time) Consider renaming Let's verify the strategy pattern usage across the codebase: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check if other classes follow the same pattern
rg -l "LonghornOperationStrategy" | xargs rg -A 5 "_strategy\s*="
Length of output: 5660 |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,91 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
from kubernetes import client | ||||||||||||||||||||||||||||||||||||||||||||||
from datetime import datetime | ||||||||||||||||||||||||||||||||||||||||||||||
from backing_image.base import Base | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
from utility.utility import logging | ||||||||||||||||||||||||||||||||||||||||||||||
from utility.utility import get_retry_count_and_interval | ||||||||||||||||||||||||||||||||||||||||||||||
import time | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
class CRD(Base): | ||||||||||||||||||||||||||||||||||||||||||||||
def __init__(self): | ||||||||||||||||||||||||||||||||||||||||||||||
self.obj_api = client.CustomObjectsApi() | ||||||||||||||||||||||||||||||||||||||||||||||
self.retry_count, self.retry_interval = get_retry_count_and_interval() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def create(self, bi_name, source_type, url, expected_checksum): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def get(self, bi_name): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def all_disk_file_status_are_ready(self, bi_name): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
def clean_up_backing_image_from_a_random_disk(self, bi_name): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def delete(self, bi_name): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def wait_for_backing_image_disk_cleanup(self, bi_name, disk_id): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def wait_for_backing_image_delete(self, bi_name): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def cleanup_backing_images(self): | ||||||||||||||||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def list_backing_image_manager(self): | ||||||||||||||||||||||||||||||||||||||||||||||
label_selector = 'longhorn.io/component=backing-image-manager' | ||||||||||||||||||||||||||||||||||||||||||||||
return self.obj_api.list_namespaced_custom_object( | ||||||||||||||||||||||||||||||||||||||||||||||
group="longhorn.io", | ||||||||||||||||||||||||||||||||||||||||||||||
version="v1beta2", | ||||||||||||||||||||||||||||||||||||||||||||||
namespace="longhorn-system", | ||||||||||||||||||||||||||||||||||||||||||||||
plural="backingimagemanagers", | ||||||||||||||||||||||||||||||||||||||||||||||
label_selector=label_selector) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def delete_backing_image_manager(self, name): | ||||||||||||||||||||||||||||||||||||||||||||||
logging(f"deleting backing image manager {name} ...") | ||||||||||||||||||||||||||||||||||||||||||||||
self.obj_api.delete_namespaced_custom_object( | ||||||||||||||||||||||||||||||||||||||||||||||
group="longhorn.io", | ||||||||||||||||||||||||||||||||||||||||||||||
version="v1beta2", | ||||||||||||||||||||||||||||||||||||||||||||||
namespace="longhorn-system", | ||||||||||||||||||||||||||||||||||||||||||||||
plural="backingimagemanagers", | ||||||||||||||||||||||||||||||||||||||||||||||
name=name | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def wait_all_backing_image_managers_running(self): | ||||||||||||||||||||||||||||||||||||||||||||||
for i in range(self.retry_count): | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Rename unused loop variable 'i' to '_' The loop variable Apply this diff to rename the unused variable: - for i in range(self.retry_count):
+ for _ in range(self.retry_count): 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff57-57: Loop control variable Rename unused (B007) |
||||||||||||||||||||||||||||||||||||||||||||||
all_running = True | ||||||||||||||||||||||||||||||||||||||||||||||
backing_image_managers = self.list_backing_image_manager() | ||||||||||||||||||||||||||||||||||||||||||||||
for backing_image_manager in backing_image_managers["items"]: | ||||||||||||||||||||||||||||||||||||||||||||||
current_state = backing_image_manager["status"]["currentState"] | ||||||||||||||||||||||||||||||||||||||||||||||
name = backing_image_manager["metadata"]["name"] | ||||||||||||||||||||||||||||||||||||||||||||||
logging(f"backing image manager {name} currently in {current_state} state") | ||||||||||||||||||||||||||||||||||||||||||||||
if current_state != "running": | ||||||||||||||||||||||||||||||||||||||||||||||
all_running = False | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+61
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for missing There is a potential Apply this diff to safely access dictionary keys: - current_state = backing_image_manager["status"]["currentState"]
+ current_state = backing_image_manager.get("status", {}).get("currentState", "unknown") Optionally, add a check for the if current_state == "unknown":
logging(f"Unable to determine the current state of backing image manager {name}")
all_running = False |
||||||||||||||||||||||||||||||||||||||||||||||
if all_running is True: | ||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||
time.sleep(self.retry_interval) | ||||||||||||||||||||||||||||||||||||||||||||||
assert False, f"Waiting all backing image manager in running state timeout" | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace Using Apply this diff to raise an exception and fix the string: - assert False, f"Waiting all backing image manager in running state timeout"
+ raise AssertionError("Timeout while waiting for all backing image managers to be in running state") 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff69-69: Do not Replace (B011) 69-69: f-string without any placeholders Remove extraneous (F541) |
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def wait_backing_image_manager_restart(self, name, last_creation_time): | ||||||||||||||||||||||||||||||||||||||||||||||
for i in range(self.retry_count): | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Rename unused loop variable 'i' to '_' Similar to the previous loop, the variable Apply this diff to rename the unused variable: - for i in range(self.retry_count):
+ for _ in range(self.retry_count): 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff72-72: Loop control variable Rename unused (B007) |
||||||||||||||||||||||||||||||||||||||||||||||
time.sleep(self.retry_interval) | ||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||
backing_image_manager = self.obj_api.get_namespaced_custom_object( | ||||||||||||||||||||||||||||||||||||||||||||||
group="longhorn.io", | ||||||||||||||||||||||||||||||||||||||||||||||
version="v1beta2", | ||||||||||||||||||||||||||||||||||||||||||||||
namespace="longhorn-system", | ||||||||||||||||||||||||||||||||||||||||||||||
plural="backingimagemanagers", | ||||||||||||||||||||||||||||||||||||||||||||||
name=name | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
except Exception as e: | ||||||||||||||||||||||||||||||||||||||||||||||
logging(f"Finding backing image manager {name} failed with error {e}") | ||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+75
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Handle exceptions more specifically and improve logging Catching all exceptions with a bare Apply this diff to catch specific exceptions and log the stack trace: - except Exception as e:
- logging(f"Finding backing image manager {name} failed with error {e}")
+ except client.exceptions.ApiException as e:
+ logging(f"Failed to find backing image manager {name}: {e}")
+ except Exception as e:
+ logging(f"An unexpected error occurred while finding backing image manager {name}: {e}", exc_info=True) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
creation_time = backing_image_manager["metadata"]["creationTimestamp"] | ||||||||||||||||||||||||||||||||||||||||||||||
fmt = "%Y-%m-%dT%H:%M:%SZ" | ||||||||||||||||||||||||||||||||||||||||||||||
if datetime.strptime(creation_time, fmt) > datetime.strptime(last_creation_time, fmt): | ||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
assert False, f"Wait backing image manager {name} restart failed ..." | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace Again, replace Apply this diff to correct the assertion: - assert False, f"Wait backing image manager {name} restart failed ..."
+ raise AssertionError(f"Waiting for backing image manager '{name}' to restart failed") 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff91-91: Do not Replace (B011) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,12 +1,12 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import time | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import subprocess | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import asyncio | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from kubernetes import client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from kubernetes.client.rest import ApiException | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.pod import create_pod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.pod import delete_pod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.pod import new_pod_manifest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.pod import wait_for_pod_status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.pod import get_pod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+8
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused imports. The following imports are not used in the code:
Apply this diff to remove the unused imports: -from workload.pod import wait_for_pod_status
-from workload.pod import get_pod 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff8-8: Remove unused import: (F401) 9-9: Remove unused import: (F401) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from workload.constant import IMAGE_UBUNTU | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from utility.utility import subprocess_exec_cmd | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from utility.utility import logging | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -95,6 +95,7 @@ def check_instance_manager_pdb_not_exist(instance_manager): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
exec_cmd = ["kubectl", "get", "pdb", "-n", "longhorn-system"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = subprocess_exec_cmd(exec_cmd) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assert instance_manager not in res.decode('utf-8') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def wait_namespaced_job_complete(job_label, namespace): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
retry_count, retry_interval = get_retry_count_and_interval() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
api = client.BatchV1Api() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -170,3 +171,25 @@ def delete_namespace(namespace): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
api.delete_namespace(name=namespace) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ApiException as e: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assert e.status == 404 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def wait_for_namespace_pods_running(namespace): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
retry_count, retry_interval = get_retry_count_and_interval() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for i in range(retry_count): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
time.sleep(retry_interval) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pod_list = list_namespace_pods(namespace) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
all_running = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for pod in pod_list.items: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pod_name = pod.metadata.name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pod_status = pod.status.phase | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if pod_status != "Running": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logging(f"Pod {pod_name} is in {pod_status} state, waiting...") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
all_running = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if all_running: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logging(f"All pods in namespace {namespace} are in Running state!") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assert False, f"wait all pod in namespace {namespace} running failed" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+175
to
+195
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider enhancing pod status verification for Longhorn components. Since this function is part of Longhorn components recovery testing, consider enhancing the verification to include:
Here's a suggested enhancement: def wait_for_namespace_pods_running(namespace):
retry_count, retry_interval = get_retry_count_and_interval()
for i in range(retry_count):
pod_list = list_namespace_pods(namespace)
all_running = True
for pod in pod_list.items:
pod_name = pod.metadata.name
pod_status = pod.status.phase
+ is_longhorn_component = pod.metadata.labels.get("longhorn.io/component")
- if pod_status != "Running":
+ # Check both pod phase and container readiness
+ if pod_status != "Running" or not all(
+ container.ready for container in pod.status.container_statuses
+ ):
logging(f"Pod {pod_name} is in {pod_status} state, waiting... (attempt {i + 1}/{retry_count})")
+ if is_longhorn_component:
+ logging(f"Critical Longhorn component {pod_name} not ready")
all_running = False
if all_running:
logging(f"All pods in namespace {namespace} are in Running state!")
return
time.sleep(retry_interval)
raise AssertionError(f"Timed out waiting for all pods in namespace {namespace} to reach Running state")
🧰 Tools🪛 Ruff178-178: Loop control variable Rename unused (B007) 195-195: Do not Replace (B011) Optimize the wait_for_namespace_pods_running implementation. The function logic is sound, but there are a few improvements to be made:
Apply these improvements: def wait_for_namespace_pods_running(namespace):
retry_count, retry_interval = get_retry_count_and_interval()
- for i in range(retry_count):
- time.sleep(retry_interval)
+ for i in range(retry_count):
pod_list = list_namespace_pods(namespace)
all_running = True
for pod in pod_list.items:
pod_name = pod.metadata.name
pod_status = pod.status.phase
if pod_status != "Running":
- logging(f"Pod {pod_name} is in {pod_status} state, waiting...")
+ logging(f"Pod {pod_name} is in {pod_status} state, waiting... (attempt {i + 1}/{retry_count})")
all_running = False
if all_running:
logging(f"All pods in namespace {namespace} are in Running state!")
return
+ time.sleep(retry_interval)
- assert False, f"wait all pod in namespace {namespace} running failed"
+ raise AssertionError(f"Timed out waiting for all pods in namespace {namespace} to reach Running state") 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff178-178: Loop control variable Rename unused (B007) 195-195: Do not Replace (B011) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,23 @@ def delete_backing_image(self, bi_name): | |
|
||
def cleanup_backing_images(self): | ||
self.backing_image.cleanup_backing_images() | ||
|
||
def delete_backing_image_manager(self, name): | ||
self.backing_image.delete_backing_image_manager(name) | ||
|
||
def wait_all_backing_image_managers_running(self): | ||
self.backing_image.wait_all_backing_image_managers_running() | ||
|
||
def wait_backing_image_manager_restart(self, name, last_creation_time): | ||
self.backing_image.wait_backing_image_manager_restart(name, last_creation_time) | ||
|
||
def list_backing_image_manager(self): | ||
return self.backing_image.list_backing_image_manager() | ||
Comment on lines
+24
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add docstrings and error handling to the new methods. These test automation keywords would benefit from:
Here's a suggested improvement for one of the methods as an example: def wait_backing_image_manager_restart(self, name, last_creation_time):
+ """Wait for a backing image manager to restart after deletion.
+
+ Args:
+ name (str): Name of the backing image manager
+ last_creation_time (str): Previous creation timestamp
+
+ Raises:
+ TimeoutError: If manager doesn't restart within timeout
+ ValueError: If name or timestamp is invalid
+ """
+ if not name or not last_creation_time:
+ raise ValueError("Name and last_creation_time must be provided")
self.backing_image.wait_backing_image_manager_restart(name, last_creation_time)
|
||
|
||
def delete_all_backing_image_managers_and_wait_for_recreation(self): | ||
backing_image_managers = self.backing_image.list_backing_image_manager() | ||
for backing_image in backing_image_managers["items"]: | ||
name = backing_image["metadata"]["name"] | ||
last_creation_time = backing_image["metadata"]["creationTimestamp"] | ||
self.backing_image.delete_backing_image_manager(name) | ||
self.backing_image.wait_backing_image_manager_restart(name, last_creation_time) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,3 +47,15 @@ def wait_for_sharemanagers_deleted(self, name=[]): | |
time.sleep(retry_interval) | ||
|
||
assert AssertionError, f"Failed to wait for all sharemanagers to be deleted" | ||
|
||
def delete_sharemanager(self, name): | ||
return self.sharemanager.delete(name) | ||
|
||
def delete_sharemanager_and_wait_for_recreation(self, name): | ||
sharemanager = self.sharemanager.get(name) | ||
last_creation_time = sharemanager["metadata"]["creationTimestamp"] | ||
self.sharemanager.delete(name) | ||
self.sharemanager.wait_for_restart(name, last_creation_time) | ||
Comment on lines
+54
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enhance robustness and documentation of recreation verification. The method needs documentation and additional error handling to improve reliability: def delete_sharemanager_and_wait_for_recreation(self, name):
+ """Delete a share manager and verify it gets recreated.
+
+ Args:
+ name (str): Name of the share manager
+
+ Raises:
+ ValueError: If name is empty or share manager not found
+ TimeoutError: If recreation takes too long
+ """
+ if not name:
+ raise ValueError("Share manager name cannot be empty")
+
sharemanager = self.sharemanager.get(name)
+ if not sharemanager:
+ raise ValueError(f"Share manager {name} not found")
+
last_creation_time = sharemanager["metadata"]["creationTimestamp"]
self.sharemanager.delete(name)
- self.sharemanager.wait_for_restart(name, last_creation_time)
+ try:
+ self.sharemanager.wait_for_restart(name, last_creation_time)
+ except Exception as e:
+ logging(f"Failed waiting for share manager {name} recreation: {str(e)}")
+ raise
|
||
|
||
def wait_for_share_manager_running(self, name): | ||
return self.sharemanager.wait_for_running(name) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,3 +5,19 @@ class Base(ABC): | |||||||||||||||||||||||||||||||
@abstractmethod | ||||||||||||||||||||||||||||||||
def list(self): | ||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@abstractmethod | ||||||||||||||||||||||||||||||||
def get(self, name): | ||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@abstractmethod | ||||||||||||||||||||||||||||||||
def delete(self, name): | ||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@abstractmethod | ||||||||||||||||||||||||||||||||
def wait_for_running(self, name): | ||||||||||||||||||||||||||||||||
return NotImplemented | ||||||||||||||||||||||||||||||||
Comment on lines
+17
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding timeout parameter to wait_for_running. For robustness in test scenarios, consider adding an optional timeout parameter to control how long the method should wait before giving up. @abstractmethod
- def wait_for_running(self, name):
+ def wait_for_running(self, name: str, timeout: int = 300) -> bool:
+ """Wait for a share manager to reach running state.
+
+ Args:
+ name: Name of the share manager
+ timeout: Maximum time to wait in seconds (default: 300)
+
+ Returns:
+ bool: True if running state is reached, False if timeout occurs
+ """
return NotImplemented 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@abstractmethod | ||||||||||||||||||||||||||||||||
def wait_for_restart(self, name, last_creation_time): | ||||||||||||||||||||||||||||||||
return NotImplemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding error handling and verification
While the implementation is logically correct, consider enhancing it with:
Example enhancement:
📝 Committable suggestion