Skip to content

Commit 35a8acf

Browse files
Add description to few functions and use only one function to wait for pods
Signed-off-by: michal.gubricky <[email protected]>
1 parent 4f58e25 commit 35a8acf

File tree

1 file changed

+55
-47
lines changed

1 file changed

+55
-47
lines changed

Tests/kaas/plugin/plugin_cluster_stacks.py

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
# Helper functions
3333
def wait_for_pods(self, namespaces, timeout=240, interval=15, kubeconfig=None):
3434
"""
35-
Waits for all pods in specified namespaces to reach the 'Running' state with all containers ready.
35+
Waits for all pods in specified namespaces to reach the condition 'Ready'.
3636
3737
:param namespaces: List of namespaces to check for pod readiness.
3838
:param timeout: Total time to wait in seconds before giving up.
3939
:param interval: Time to wait between checks in seconds.
40+
:param kubeconfig: Optional path to the kubeconfig file for the target Kubernetes cluster.
41+
:return: True if all pods are ready within the given timeout, raises TimeoutError otherwise.
4042
"""
4143
start_time = time.time()
4244

@@ -46,25 +48,16 @@ def wait_for_pods(self, namespaces, timeout=240, interval=15, kubeconfig=None):
4648
for namespace in namespaces:
4749
try:
4850
# Get pod status in the namespace
49-
command = (
50-
f"kubectl get pods -n {namespace} --kubeconfig {kubeconfig} "
51-
f"-o=jsonpath='{{range .items[*]}}{{.metadata.name}} {{.status.phase}} {{range .status.containerStatuses[*]}}{{.ready}} {{end}}{{\"\\n\"}}{{end}}'"
51+
wait_pods_command = (
52+
f"kubectl wait -n {namespace} --for=condition=Ready --timeout={timeout}s pod --all"
5253
)
53-
result = self._run_subprocess(command, f"Error fetching pods in {namespace}", shell=True, capture_output=True, text=True)
54-
55-
if result.returncode == 0:
56-
pods_status = result.stdout.strip().splitlines()
57-
for pod_status in pods_status:
58-
pod_info = pod_status.split()
59-
pod_name, phase, *readiness_states = pod_info
60-
61-
# Check pod phase and all containers readiness
62-
if phase != "Running" or "false" in readiness_states:
63-
all_pods_ready = False
64-
logger.info(f"Pod {pod_name} in {namespace} is not ready. Phase: {phase}, Ready: {readiness_states}")
65-
else:
66-
logger.error(f"Error fetching pods in {namespace}: {result.stderr}")
54+
result = self._run_subprocess(wait_pods_command, f"Error fetching pods in {namespace}", shell=True, capture_output=True, text=True, kubeconfig=kubeconfig)
55+
56+
if result.returncode != 0:
57+
logger.warning(f"Not all pods in namespace {namespace} are ready. Details: {result.stderr}")
6758
all_pods_ready = False
59+
else:
60+
logger.info(f"All pods in namespace {namespace} are ready.")
6861

6962
except subprocess.CalledProcessError as error:
7063
logger.error(f"Error checking pods in {namespace}: {error}")
@@ -80,34 +73,6 @@ def wait_for_pods(self, namespaces, timeout=240, interval=15, kubeconfig=None):
8073
raise TimeoutError(f"Timed out after {timeout} seconds waiting for pods in namespaces {namespaces} to become ready.")
8174

8275

83-
def wait_for_workload_pods_ready(namespace="kube-system", timeout=600, kubeconfig_path=None, max_retries=3, delay=30):
84-
"""
85-
Waits for all pods in a specific namespace on a workload Kubernetes cluster to become ready.
86-
87-
:param namespace: The Kubernetes namespace where pods are located (default is "kube-system").
88-
:param timeout: The timeout in seconds to wait for pods to become ready (default is 600).
89-
:param kubeconfig_path: Path to the kubeconfig file for the target Kubernetes cluster.
90-
:raises RuntimeError: If pods are not ready within the specified timeout.
91-
"""
92-
for attempt in range(max_retries):
93-
try:
94-
kubeconfig_option = f"--kubeconfig {kubeconfig_path}" if kubeconfig_path else ""
95-
wait_pods_command = (
96-
f"kubectl wait -n {namespace} --for=condition=Ready --timeout={timeout}s pod --all {kubeconfig_option}"
97-
)
98-
99-
# Run the command
100-
subprocess.run(wait_pods_command, shell=True, check=True)
101-
logger.info(f"All pods in namespace {namespace} in the workload Kubernetes cluster are ready.")
102-
return True
103-
104-
except subprocess.CalledProcessError as error:
105-
logger.warning(f"Attempt {attempt+1}/{max_retries} failed with error: {error}. Retrying in {delay} seconds...")
106-
time.sleep(delay)
107-
108-
raise RuntimeError(f"Error waiting for pods in namespace '{namespace}' to become ready.")
109-
110-
11176
def load_config(config_path):
11277
"""
11378
Loads the configuration from a YAML file.
@@ -122,6 +87,11 @@ def setup_environment_variables(self):
12287
"""
12388
Constructs and returns a dictionary of required environment variables
12489
based on the configuration.
90+
91+
:raises ValueError: If the `GIT_ACCESS_TOKEN` environment variable is not set.
92+
93+
:return: A dictionary of required environment variables with necessary values and
94+
encodings for Kubernetes and Git-related configurations.
12595
"""
12696
# Calculate values that need to be set dynamically
12797
if hasattr(self, 'cluster_version'):
@@ -210,7 +180,8 @@ def create_cluster(self, cluster_name="scs-cluster", version=None, kubeconfig_fi
210180
self._retrieve_kubeconfig(kubeconfig=self.kubeconfig_mgmnt_path)
211181

212182
# Wait for workload system pods to be ready
213-
wait_for_workload_pods_ready(kubeconfig_path=self.kubeconfig_cs_cluster)
183+
# wait_for_workload_pods_ready(kubeconfig_path=self.kubeconfig_cs_cluster)
184+
wait_for_pods(self, ["kube-system"], timeout=600, interval=15, kubeconfig=self.kubeconfig_cs_cluster)
214185

215186
def delete_cluster(self, cluster_name=None, kubeconfig_filepath=None):
216187
self.cluster_name = cluster_name
@@ -242,6 +213,13 @@ def delete_cluster(self, cluster_name=None, kubeconfig_filepath=None):
242213
os.remove(self.kubeconfig_mgmnt_path)
243214

244215
def _apply_yaml_with_envsubst(self, yaml_file, error_msg, kubeconfig=None):
216+
"""
217+
Applies a Kubernetes YAML configuration file to the cluster, substituting environment variables as needed.
218+
219+
:param yaml_file: The name of the YAML file to apply.
220+
:param kubeconfig: Optional path to a kubeconfig file, which specifies which Kubernetes cluster
221+
to apply the YAML configuration to.
222+
"""
245223
try:
246224
# Determine if the file is a local path or a URL
247225
if os.path.isfile(yaml_file):
@@ -260,6 +238,13 @@ def _apply_yaml_with_envsubst(self, yaml_file, error_msg, kubeconfig=None):
260238
raise RuntimeError(f"{error_msg}: {error}")
261239

262240
def _get_kubeadm_control_plane_name(self, kubeconfig=None):
241+
"""
242+
Retrieves the name of the KubeadmControlPlane resource for the Kubernetes cluster.
243+
244+
:param kubeconfig: Optional path to the kubeconfig file for the target Kubernetes cluster.
245+
246+
:return: The name of the KubeadmControlPlane resource as a string.
247+
"""
263248
max_retries = 6
264249
delay_between_retries = 10
265250
for _ in range(max_retries):
@@ -281,6 +266,12 @@ def _get_kubeadm_control_plane_name(self, kubeconfig=None):
281266
raise RuntimeError("Failed to get kubeadmcontrolplane name")
282267

283268
def _wait_kcp_ready(self, kcp_name, kubeconfig=None):
269+
"""
270+
Waits for the specified KubeadmControlPlane resource to become 'Available'.
271+
272+
:param kcp_name: The name of the KubeadmControlPlane resource to check for availability.
273+
:param kubeconfig: Optional path to the kubeconfig file for the target Kubernetes cluster.
274+
"""
284275
try:
285276
self._run_subprocess(
286277
f"kubectl wait kubeadmcontrolplane/{kcp_name} --for=condition=Available --timeout=600s",
@@ -292,12 +283,29 @@ def _wait_kcp_ready(self, kcp_name, kubeconfig=None):
292283
raise RuntimeError(f"Error waiting for kubeadmcontrolplane to be ready: {error}")
293284

294285
def _retrieve_kubeconfig(self, kubeconfig=None):
286+
"""
287+
Retrieves the kubeconfig for the specified cluster and saves it to a local file.
288+
289+
:param kubeconfig: Optional path to the kubeconfig file for the target Kubernetes cluster.
290+
"""
295291
kubeconfig_command = (
296292
f"sudo -E clusterctl get kubeconfig {self.cluster_name} > {self.kubeconfig_cs_cluster}"
297293
)
298294
self._run_subprocess(kubeconfig_command, "Error retrieving kubeconfig", shell=True, kubeconfig=kubeconfig)
299295

300296
def _run_subprocess(self, command, error_msg, shell=False, capture_output=False, text=False, kubeconfig=None):
297+
"""
298+
Executes a subprocess command with the specified environment variables and parameters.
299+
300+
:param command: The shell command to be executed. This can be a string or a list of arguments to pass to the subprocess.
301+
:param error_msg: A custom error message to be logged and raised if the subprocess fails.
302+
:param shell: Whether to execute the command through the shell (default: `False`).
303+
:param capture_output: Whether to capture the command's standard output and standard error (default: `False`).
304+
:param text: Whether to treat the command's output and error as text (default: `False`).
305+
:param kubeconfig: Optional path to the kubeconfig file for the target Kubernetes cluster.
306+
307+
:return: The result of the `subprocess.run` command
308+
"""
301309
try:
302310
env = setup_environment_variables(self)
303311
env['PATH'] = f'/usr/local/bin:/usr/bin:{self.working_directory}'

0 commit comments

Comments
 (0)