Skip to content

Commit f4bdba7

Browse files
Update code and readme
Signed-off-by: michal.gubricky <[email protected]>
1 parent 859cf77 commit f4bdba7

8 files changed

+156
-109
lines changed

Diff for: Tests/kaas/plugin/README.md

+2-12
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,16 @@ To set the `GIT_ACCESS_TOKEN`, run the following command in your terminal:
6666
export GIT_ACCESS_TOKEN=<your-github-token>
6767
```
6868

69-
### Configuring clusterspec.yaml file
69+
### Configuring config file for cluster-stacks plugin
7070

71-
The `clusterspec.yaml` file is used to set parameters for creating a Kubernetes cluster with the `cluster-stacks` plugin. This file allows you to specify details related to the cluster-stack, Git integration, and cluster configurations.
72-
73-
### Mandatory Parameter
74-
75-
The only mandatory parameter in `clusterspec.yaml` is `clouds_yaml_path` field, which points to the `clouds.yaml` file for OpenStack. If other parameters are omitted, the default values will be used.
76-
77-
### Optional Parameters
78-
79-
You can include additional parameters in `clusterspec.yaml` to customize the cluster setup. These optional parameters are grouped below by their category.
71+
The config file is used to set parameters for creating a Kubernetes cluster with the `cluster-stacks` plugin. This file allows you to specify details related to the cluster-stack, Git integration, and cluster configurations. These optional parameters are grouped below by their category.
8072

8173
#### Cluster-Stack Related Parameters
8274

8375
These parameters configure specific settings for the cluster-stack:
8476

8577
```yaml
8678
cs_name: <cs_name> # Default: "scs"
87-
cs_k8s_version: <cs_k8s_version> # Default: "1.29"
8879
cs_version: <cs_version> # Default: "v1"
8980
cs_channel: <cs_channel> # Default: "stable"
9081
cs_cloudname: <cs_cloudname> # Default: "openstack"
@@ -105,7 +96,6 @@ git_repo_name: <git_repo_name> # Default: "cluster-stacks"
10596
Set these parameters to customize the configuration for your cluster.
10697
10798
```yaml
108-
cs_cluster_name: <cs_cluster_name> # Default: "cs-cluster"
10999
cs_pod_cidr: <cs_pod_cidr> # Default: "192.168.0.0/16"
110100
cs_service_cidr: <cs_service_cidr> # Default: "10.96.0.0/12"
111101
cs_external_id: <cs_external_id> # Default: A generated UUID

Diff for: Tests/kaas/plugin/cluster.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Cluster resource template
12
apiVersion: cluster.x-k8s.io/v1beta1
23
kind: Cluster
34
metadata:

Diff for: Tests/kaas/plugin/clusterstack.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Cluster-stack and OpenStack cluster-stack release resource templates
12
apiVersion: clusterstack.x-k8s.io/v1alpha1
23
kind: ClusterStack
34
metadata:

Diff for: Tests/kaas/plugin/interface.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ def create_cluster(self, cluster_name="scs-cluster", version=None, kubeconfig_fi
4646
"""
4747
raise NotImplementedError
4848

49-
def delete_cluster(self, cluster_name=None):
49+
def delete_cluster(self, cluster_name=None, kubeconfig_filepath=None):
5050
"""
5151
This method is to be called in order to unprovision a cluster
5252
:param: cluster_name:
53+
:param: kubeconfig_filepath:
5354
"""
5455
raise NotImplementedError

Diff for: Tests/kaas/plugin/plugin-cluster-stacks-config.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This is an example of the config for a cluster-stacks plugin filled with a default values
2+
3+
clouds_yaml_path: "~/.config/openstack/clouds.yaml" # Path to OpenStack clouds.yaml file
4+
cs_name: "scs" # Cluster Stack Name
5+
cs_version: "v1" # Cluster Stack Version
6+
cs_channel: "stable" # Release channel
7+
cs_cloudname: "openstack" # Cloud name from OpenStack clouds.yaml
8+
cs_namespace: "default" # Namespace for the Cluster Stack deployment
9+
10+
# Git Configuration
11+
git_provider: "github" # Git provider (e.g., GitHub, GitLab)
12+
git_org_name: "SovereignCloudStack" # Organization name on Git provider
13+
git_repo_name: "cluster-stacks" # Repository name on Git provider
14+
15+
# Cluster Information
16+
cs_pod_cidr: "192.168.0.0/16" # Pod CIDR for networking
17+
cs_service_cidr: "10.96.0.0/12" # Service CIDR for networking
18+
cs_external_id: "ebfe5546-f09f-4f42-ab54-094e457d42ec" # External ID for the Cluster Stack
19+
cs_k8s_patch_version: "6" # Kubernetes patch version to use

Diff for: Tests/kaas/plugin/plugin_cluster_stacks.py

+121-93
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import os
2+
import yaml
3+
import shutil
24
import subprocess
35
import base64
46
import time
@@ -45,20 +47,20 @@ def wait_for_capi_pods_ready(timeout=240, interval=15):
4547
# Check pod phase and all containers readiness
4648
if phase != "Running" or "false" in readiness_states:
4749
all_pods_ready = False
48-
print(f"Pod {pod_name} in {namespace} is not ready. Phase: {phase}, Ready: {readiness_states}")
50+
logger.info(f"Pod {pod_name} in {namespace} is not ready. Phase: {phase}, Ready: {readiness_states}")
4951
else:
50-
print(f"Error fetching pods in {namespace}: {result.stderr}")
52+
logger.info(f"Error fetching pods in {namespace}: {result.stderr}")
5153
all_pods_ready = False
5254

5355
except subprocess.CalledProcessError as error:
54-
print(f"Error checking pods in {namespace}: {error}")
56+
logger.error(f"Error checking pods in {namespace}: {error}")
5557
all_pods_ready = False
5658

5759
if all_pods_ready:
58-
print("All CAPI system pods are ready.")
60+
logger.info("All CAPI system pods are ready.")
5961
return True
6062

61-
print("Waiting for all CAPI pods to become ready...")
63+
logger.info("Waiting for all CAPI pods to become ready...")
6264
time.sleep(interval)
6365

6466
raise TimeoutError(f"Timed out after {timeout} seconds waiting for CAPI and CAPO system pods to become ready.")
@@ -93,31 +95,31 @@ def wait_for_cso_pods_ready(timeout=240, interval=15):
9395
# Check pod phase and all containers readiness
9496
if phase != "Running" or "false" in readiness_states:
9597
all_pods_ready = False
96-
print(f"Pod {pod_name} in {cso_namespace} is not ready. Phase: {phase}, Ready: {readiness_states}")
98+
logger.info(f"Pod {pod_name} in {cso_namespace} is not ready. Phase: {phase}, Ready: {readiness_states}")
9799
else:
98-
print(f"Error fetching pods in {cso_namespace}: {result.stderr}")
100+
logger.error(f"Error fetching pods in {cso_namespace}: {result.stderr}")
99101
all_pods_ready = False
100102

101103
except subprocess.CalledProcessError as error:
102-
print(f"Error checking pods in {cso_namespace}: {error}")
104+
logger.error(f"Error checking pods in {cso_namespace}: {error}")
103105
all_pods_ready = False
104106

105107
if all_pods_ready:
106-
print("All CSO pods in 'cso-system' namespace are ready.")
108+
logger.info("All CSO pods in 'cso-system' namespace are ready.")
107109
return True
108110

109-
print("Waiting for CSO pods in 'cso-system' namespace to become ready...")
111+
logger.info("Waiting for CSO pods in 'cso-system' namespace to become ready...")
110112
time.sleep(interval)
111113

112114
raise TimeoutError(f"Timed out after {timeout} seconds waiting for CSO pods in 'cso-system' namespace to become ready.")
113115

114116

115-
def wait_for_workload_pods_ready(namespace="kube-system", timeout=420, kubeconfig_path=None):
117+
def wait_for_workload_pods_ready(namespace="kube-system", timeout=600, kubeconfig_path=None):
116118
"""
117119
Waits for all pods in a specific namespace on a workload Kubernetes cluster to become ready.
118120
119121
:param namespace: The Kubernetes namespace where pods are located (default is "kube-system").
120-
:param timeout: The timeout in seconds to wait for pods to become ready (default is 420).
122+
:param timeout: The timeout in seconds to wait for pods to become ready (default is 600).
121123
:param kubeconfig_path: Path to the kubeconfig file for the target Kubernetes cluster.
122124
:raises RuntimeError: If pods are not ready within the specified timeout.
123125
"""
@@ -129,87 +131,111 @@ def wait_for_workload_pods_ready(namespace="kube-system", timeout=420, kubeconfi
129131

130132
# Run the command
131133
subprocess.run(wait_pods_command, shell=True, check=True)
132-
print(f"All pods in namespace '{namespace}' in the workload Kubernetes cluster are ready.")
134+
logger.info("All pods in namespace '{namespace}' in the workload Kubernetes cluster are ready.")
133135

134136
except subprocess.CalledProcessError as error:
135137
raise RuntimeError(f"Error waiting for pods in namespace '{namespace}' to become ready: {error}")
136138

137139

140+
def load_config(config_path):
141+
"""
142+
Loads the configuration from a YAML file.
143+
"""
144+
if not os.path.exists(config_path):
145+
raise FileNotFoundError(f"Configuration file {config_path} not found.")
146+
147+
with open(config_path, 'r') as file:
148+
config = yaml.safe_load(file) or {}
149+
return config
150+
151+
152+
def setup_environment_variables(self):
153+
# Cluster Stack Parameters
154+
self.clouds_yaml_path = self.config.get('clouds_yaml_path', '~/.config/openstack/clouds.yaml')
155+
self.cs_k8s_version = self.cluster_version
156+
self.cs_name = self.config.get('cs_name', 'scs')
157+
self.cs_version = self.config.get('cs_version', 'v1')
158+
self.cs_channel = self.config.get('cs_channel', 'stable')
159+
self.cs_cloudname = self.config.get('cs_cloudname', 'openstack')
160+
self.cs_secretname = self.cs_cloudname
161+
162+
# CSP-related variables and additional cluster configuration
163+
self.kubeconfig_cs_cluster_filename = f"kubeconfig-{self.cluster_name}.yaml"
164+
self.cs_class_name = f"openstack-{self.cs_name}-{str(self.cs_k8s_version).replace('.', '-')}-{self.cs_version}"
165+
self.cs_namespace = self.config.get("cs_namespace", "default")
166+
self.cs_pod_cidr = self.config.get('cs_pod_cidr', '192.168.0.0/16')
167+
self.cs_service_cidr = self.config.get('cs_service_cidr', '10.96.0.0/12')
168+
self.cs_external_id = self.config.get('cs_external_id', 'ebfe5546-f09f-4f42-ab54-094e457d42ec')
169+
self.cs_k8s_patch_version = self.config.get('cs_k8s_patch_version', '6')
170+
171+
if not self.clouds_yaml_path:
172+
raise ValueError("CLOUDS_YAML_PATH environment variable not set.")
173+
174+
required_env = {
175+
'CLUSTER_TOPOLOGY': 'true',
176+
'EXP_CLUSTER_RESOURCE_SET': 'true',
177+
'EXP_RUNTIME_SDK': 'true',
178+
'CS_NAME': self.cs_name,
179+
'CS_K8S_VERSION': self.cs_k8s_version,
180+
'CS_VERSION': self.cs_version,
181+
'CS_CHANNEL': self.cs_channel,
182+
'CS_CLOUDNAME': self.cs_cloudname,
183+
'CS_SECRETNAME': self.cs_secretname,
184+
'CS_CLASS_NAME': self.cs_class_name,
185+
'CS_NAMESPACE': self.cs_namespace,
186+
'CS_POD_CIDR': self.cs_pod_cidr,
187+
'CS_SERVICE_CIDR': self.cs_service_cidr,
188+
'CS_EXTERNAL_ID': self.cs_external_id,
189+
'CS_K8S_PATCH_VERSION': self.cs_k8s_patch_version,
190+
'CS_CLUSTER_NAME': self.cluster_name,
191+
}
192+
# Update the environment variables
193+
os.environ.update({key: str(value) for key, value in required_env.items()})
194+
195+
196+
def setup_git_env(self):
197+
# Setup Git environment variables
198+
git_provider = self.config.get('git_provider', 'github')
199+
git_org_name = self.config.get('git_org_name', 'SovereignCloudStack')
200+
git_repo_name = self.config.get('git_repo_name', 'cluster-stacks')
201+
202+
os.environ.update({
203+
'GIT_PROVIDER_B64': base64.b64encode(git_provider.encode()).decode('utf-8'),
204+
'GIT_ORG_NAME_B64': base64.b64encode(git_org_name.encode()).decode('utf-8'),
205+
'GIT_REPOSITORY_NAME_B64': base64.b64encode(git_repo_name.encode()).decode('utf-8')
206+
})
207+
208+
git_access_token = os.getenv('GIT_ACCESS_TOKEN')
209+
if git_access_token:
210+
os.environ['GIT_ACCESS_TOKEN_B64'] = base64.b64encode(git_access_token.encode()).decode('utf-8')
211+
else:
212+
raise ValueError("GIT_ACCESS_TOKEN environment variable not set.")
213+
214+
138215
class PluginClusterStacks(KubernetesClusterPlugin):
139-
def __init__(self, config=None):
140-
super().__init__(config)
141-
self.cluster_info = config if config else {}
142-
self._setup_environment_variables()
143-
self._setup_git_env()
144-
145-
def _setup_environment_variables(self):
146-
# Cluster Stack Parameters
147-
self.clouds_yaml_path = self.cluster_info.get('clouds_yaml_path')
148-
self.cs_k8s_version = self.cluster_info.get('cs_k8s_version', '1.29')
149-
self.cs_name = self.cluster_info.get('cs_name', 'scs')
150-
self.cs_version = self.cluster_info.get('cs_version', 'v1')
151-
self.cs_channel = self.cluster_info.get('cs_channel', 'stable')
152-
self.cs_cloudname = self.cluster_info.get('cs_cloudname', 'openstack')
153-
self.cs_secretname = self.cs_cloudname
154-
155-
# CSP-related variables and additional cluster configuration
156-
self.cs_cluster_name = self.cluster_info.get('cs_cluster_name', 'cs-cluster')
157-
self.kubeconfig_cs_cluster_filename = f"kubeconfig-{self.cs_cluster_name}"
158-
self.cs_class_name = f"openstack-{self.cs_name}-{str(self.cs_k8s_version).replace('.', '-')}-{self.cs_version}"
159-
self.cs_namespace = os.getenv("CS_NAMESPACE", "default")
160-
self.cs_pod_cidr = self.cluster_info.get('cs_pod_cidr', '192.168.0.0/16')
161-
self.cs_service_cidr = self.cluster_info.get('cs_service_cidr', '10.96.0.0/12')
162-
self.cs_external_id = self.cluster_info.get('cs_external_id', 'ebfe5546-f09f-4f42-ab54-094e457d42ec')
163-
self.cs_k8s_patch_version = self.cluster_info.get('cs_k8s_patch_version', '6')
164-
165-
if not self.clouds_yaml_path:
166-
raise ValueError("CLOUDS_YAML_PATH environment variable not set.")
167-
168-
required_env = {
169-
'CLUSTER_TOPOLOGY': 'true',
170-
'EXP_CLUSTER_RESOURCE_SET': 'true',
171-
'EXP_RUNTIME_SDK': 'true',
172-
'CS_NAME': self.cs_name,
173-
'CS_K8S_VERSION': self.cs_k8s_version,
174-
'CS_VERSION': self.cs_version,
175-
'CS_CHANNEL': self.cs_channel,
176-
'CS_CLOUDNAME': self.cs_cloudname,
177-
'CS_SECRETNAME': self.cs_secretname,
178-
'CS_CLASS_NAME': self.cs_class_name,
179-
'CS_NAMESPACE': self.cs_namespace,
180-
'CS_POD_CIDR': self.cs_pod_cidr,
181-
'CS_SERVICE_CIDR': self.cs_service_cidr,
182-
'CS_EXTERNAL_ID': self.cs_external_id,
183-
'CS_K8S_PATCH_VERSION': self.cs_k8s_patch_version,
184-
'CS_CLUSTER_NAME': self.cs_cluster_name,
185-
}
186-
# Update the environment variables
187-
os.environ.update({key: str(value) for key, value in required_env.items()})
188-
189-
def _setup_git_env(self):
190-
# Setup Git environment variables
191-
git_provider = self.cluster_info.get('git_provider', 'github')
192-
git_org_name = self.cluster_info.get('git_org_name', 'SovereignCloudStack')
193-
git_repo_name = self.cluster_info.get('git_repo_name', 'cluster-stacks')
194-
195-
os.environ.update({
196-
'GIT_PROVIDER_B64': base64.b64encode(git_provider.encode()).decode('utf-8'),
197-
'GIT_ORG_NAME_B64': base64.b64encode(git_org_name.encode()).decode('utf-8'),
198-
'GIT_REPOSITORY_NAME_B64': base64.b64encode(git_repo_name.encode()).decode('utf-8')
199-
})
200-
201-
git_access_token = os.getenv('GIT_ACCESS_TOKEN')
202-
if git_access_token:
203-
os.environ['GIT_ACCESS_TOKEN_B64'] = base64.b64encode(git_access_token.encode()).decode('utf-8')
204-
else:
205-
raise ValueError("GIT_ACCESS_TOKEN environment variable not set.")
216+
def __init__(self, config_file=None):
217+
self.config = load_config(config_file) if config_file else {}
218+
logger.debug(self.config)
219+
self.working_directory = os.getcwd()
220+
logger.debug(f"Working from {self.working_directory}")
221+
222+
def create_cluster(self, cluster_name="scs-cluster", version=None, kubeconfig_filepath=None):
223+
self.cluster_name = cluster_name
224+
self.cluster_version = version
225+
226+
# Setup variables
227+
setup_environment_variables(self)
228+
setup_git_env(self)
206229

207-
def _create_cluster(self):
208230
# Create the Kind cluster
209-
self.cluster = KindCluster(self.cluster_name)
231+
self.cluster = KindCluster(name=cluster_name)
210232
self.cluster.create()
211233
self.kubeconfig = str(self.cluster.kubeconfig_path.resolve())
212-
os.environ['KUBECONFIG'] = self.kubeconfig
234+
if kubeconfig_filepath:
235+
shutil.move(self.kubeconfig, kubeconfig_filepath)
236+
else:
237+
kubeconfig_filepath = str(self.kubeconfig)
238+
os.environ['KUBECONFIG'] = kubeconfig_filepath
213239

214240
# Initialize clusterctl with OpenStack as the infrastructure provider
215241
self._run_subprocess(["clusterctl", "init", "--infrastructure", "openstack"], "Error during clusterctl init")
@@ -241,34 +267,36 @@ def _create_cluster(self):
241267
self._retrieve_kubeconfig()
242268

243269
# Wait for workload system pods to be ready
270+
print(self.kubeconfig_cs_cluster_filename)
244271
wait_for_workload_pods_ready(kubeconfig_path=self.kubeconfig_cs_cluster_filename)
245272

246-
def _delete_cluster(self):
273+
def delete_cluster(self, cluster_name=None, kubeconfig_filepath=None):
274+
kubeconfig_cs_cluster_filename = f"kubeconfig-{cluster_name}.yaml"
247275
try:
248276
# Check if the cluster exists
249-
check_cluster_command = f"kubectl get cluster {self.cs_cluster_name} --kubeconfig {self.cluster_info.get('kubeconfig')}"
277+
check_cluster_command = f"kubectl get cluster {cluster_name} --kubeconfig {kubeconfig_filepath}"
250278
result = subprocess.run(check_cluster_command, shell=True, check=True, capture_output=True, text=True)
251279

252280
# Proceed with deletion only if the cluster exists
253281
if result.returncode == 0:
254-
delete_command = f"kubectl delete cluster {self.cs_cluster_name} --timeout=600s --kubeconfig {self.cluster_info.get('kubeconfig')}"
282+
delete_command = f"kubectl delete cluster {cluster_name} --timeout=600s --kubeconfig {kubeconfig_filepath}"
255283
self._run_subprocess(delete_command, "Timeout while deleting the cluster", shell=True)
256284

257285
except subprocess.CalledProcessError as error:
258286
if "NotFound" in error.stderr:
259-
logger.info(f"Cluster {self.cs_cluster_name} not found. Skipping deletion.")
287+
logger.info(f"Cluster {cluster_name} not found. Skipping deletion.")
260288
else:
261289
raise RuntimeError(f"Error checking for cluster existence: {error}")
262290

263291
# Delete kind cluster
264-
self.cluster = KindCluster(self.cluster_name)
292+
self.cluster = KindCluster(cluster_name)
265293
self.cluster.delete()
266294

267295
# Remove kubeconfigs
268-
if os.path.exists(self.kubeconfig_cs_cluster_filename):
269-
os.remove(self.kubeconfig_cs_cluster_filename)
270-
if os.path.exists(self.cluster_info.get('kubeconfig')):
271-
os.remove(self.cluster_info.get('kubeconfig'))
296+
if os.path.exists(kubeconfig_cs_cluster_filename):
297+
os.remove(kubeconfig_cs_cluster_filename)
298+
if os.path.exists(kubeconfig_filepath):
299+
os.remove(kubeconfig_filepath)
272300

273301
def _apply_yaml_with_envsubst(self, yaml_file, error_msg):
274302
try:
@@ -320,7 +348,7 @@ def _wait_kcp_ready(self, kcp_name):
320348

321349
def _retrieve_kubeconfig(self):
322350
kubeconfig_command = (
323-
f"clusterctl get kubeconfig {self.cs_cluster_name} > {self.kubeconfig_cs_cluster_filename}"
351+
f"clusterctl get kubeconfig {self.cluster_name} > {self.kubeconfig_cs_cluster_filename}"
324352
)
325353
self._run_subprocess(kubeconfig_command, "Error retrieving kubeconfig", shell=True)
326354

Diff for: Tests/kaas/plugin/plugin_kind.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ def create_cluster(self, cluster_name="scs-cluster", version=None, kubeconfig=No
4646
self.cluster.create(self.config)
4747
return str(self.cluster.kubeconfig_path.resolve())
4848

49-
def delete_cluster(self, cluster_name=None):
49+
def delete_cluster(self, cluster_name=None, kubeconfig_filepath=None):
5050
self.cluster = KindCluster(cluster_name)
5151
self.cluster.delete()
52+
53+
# Remove kubeconfig
54+
if os.path.exists(kubeconfig_filepath):
55+
os.remove(kubeconfig_filepath)

0 commit comments

Comments
 (0)