cluster-builder 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cluster-builder might be problematic. Click here for more details.

Files changed (32) hide show
  1. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/PKG-INFO +44 -26
  2. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/README.md +43 -25
  3. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/config/cluster.py +6 -3
  4. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/swarmchestrate.py +53 -47
  5. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/aws/main.tf +3 -3
  6. cluster_builder-0.3.3/cluster_builder/templates/deploy_manifest.tf +37 -0
  7. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/edge/main.tf +4 -4
  8. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/ha_user_data.sh.tpl +1 -1
  9. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/master_user_data.sh.tpl +2 -2
  10. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/openstack/main.tf +4 -4
  11. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/worker_user_data.sh.tpl +1 -1
  12. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder.egg-info/PKG-INFO +44 -26
  13. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder.egg-info/SOURCES.txt +1 -1
  14. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/pyproject.toml +1 -1
  15. cluster_builder-0.3.1/cluster_builder/templates/copy_manifest.tf +0 -36
  16. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/LICENSE +0 -0
  17. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/__init__.py +0 -0
  18. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/config/__init__.py +0 -0
  19. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/config/postgres.py +0 -0
  20. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/infrastructure/__init__.py +0 -0
  21. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/infrastructure/executor.py +0 -0
  22. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/infrastructure/templates.py +0 -0
  23. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/aws_provider.tf +0 -0
  24. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/templates/openstack_provider.tf +0 -0
  25. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/utils/__init__.py +0 -0
  26. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/utils/hcl.py +0 -0
  27. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder/utils/logging.py +0 -0
  28. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder.egg-info/dependency_links.txt +0 -0
  29. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder.egg-info/requires.txt +0 -0
  30. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/cluster_builder.egg-info/top_level.txt +0 -0
  31. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/setup.cfg +0 -0
  32. {cluster_builder-0.3.1 → cluster_builder-0.3.3}/tests/test_hcl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cluster-builder
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Swarmchestrate cluster builder
5
5
  Author-email: Gunjan <G.Kotak@westminster.ac.uk>, Jay <J.Deslauriers@westminster.ac.uk>
6
6
  License: Apache2
@@ -16,7 +16,7 @@ Dynamic: license-file
16
16
 
17
17
  # Swarmchestrate - Cluster Builder
18
18
 
19
- This repository contains the codebase for **[cluster-builder]**, which builds K3s clusters for Swarmchestrate using OpenTofu.
19
+ This repository contains the codebase for **cluster-builder**, which builds K3s clusters for Swarmchestrate using OpenTofu.
20
20
 
21
21
  Key features:
22
22
  - **Create**: Provisions infrastructure using OpenTofu and installs K3s.
@@ -33,11 +33,10 @@ Before proceeding, ensure the following prerequisites are installed:
33
33
  1. **Git**: For cloning the repository.
34
34
  2. **Python**: Version 3.9 or higher.
35
35
  3. **pip**: Python package manager.
36
- 4. **OpenTofu**: Version 1.6 or higher for infrastructure provisioning.
37
- 6. **Make**: To run the provided `Makefile`.
38
- 7. **PostgreSQL**: For storing OpenTofu state.
39
- 8. (Optional) **Docker**: To create a dev Postgres
40
- 9. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
36
+ 4. **Make**: To run the provided `Makefile`.
37
+ 5. **PostgreSQL**: For storing OpenTofu state.
38
+ 6. (Optional) **Docker**: To create a dev Postgres
39
+ 7. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
41
40
 
42
41
  ---
43
42
 
@@ -142,16 +141,21 @@ orchestrator = Swarmchestrate(
142
141
  To create a new k3s cluster, use the **add_node** method with the **master** role:
143
142
 
144
143
  ```python
145
- # Configuration for a new cluster
144
+ # Configuration for a new cluster using aws provider
146
145
  config = {
147
- "cloud": "aws", # Can be 'aws', 'openstack', or 'edge'
148
- "k3s_role": "master", # Role can be 'master', 'worker', or 'ha'
146
+ "cloud": "aws",
147
+ "k3s_role": "master",
149
148
  "ha": False, # Set to True for high availability (HA) deployments
150
149
  "instance_type": "t2.small", # AWS instance type
151
150
  "ssh_key_name": "g", # SSH key name for AWS or OpenStack
152
151
  "ssh_user": "ec2-user", # SSH user for the instance
153
152
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
154
153
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS (specific to region)
154
+ # Optional parameters
155
+ # If existing SG is specified, it will be used directly with no port changes
156
+ "security_group_id": "sg-0123456789abcdef0",
157
+ # No security_group_id means a new SG will be created and these ports applied as rules
158
+ # These ports will be used ONLY if creating a new SG
155
159
  "tcp_ports": [10020], # Optional list of TCP ports to open
156
160
  "udp_ports": [1003] # Optional list of UDP ports to open
157
161
  }
@@ -161,27 +165,33 @@ cluster_name = orchestrator.add_node(config)
161
165
  print(f"Created cluster: {cluster_name}")
162
166
  ```
163
167
 
168
+ Note: Fetch the outputs from the master node and use them when adding a worker node.
169
+
164
170
  ### Adding Nodes to an Existing Cluster
165
171
 
166
172
  To add worker or high-availability nodes to an existing cluster:
167
173
 
168
174
  ```python
169
- # Configuration for adding a worker node
175
+ # Configuration for adding a worker node using aws provider
170
176
  worker_config = {
171
- "cloud": "aws", # Cloud provider (can be 'aws', 'openstack', or 'edge')
177
+ "cloud": "aws",
172
178
  "k3s_role": "worker", # Role can be 'worker' or 'ha'
173
- "ha": False, # Set to True for high availability (HA) deployments
174
179
  "instance_type": "t2.small", # AWS instance type
175
180
  "ssh_key_name": "g", # SSH key name
176
181
  "ssh_user": "ec2-user", # SSH user for the instance
177
182
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
178
183
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS
179
- # Optional parameters:
180
- # "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
181
- # "cluster_name": "elastic_mcnulty", # Name of the cluster
182
- # "security_group_id": "sg-xxxxxxxxxxxxxxx", # Security group ID for AWS or OpenStack
183
- # "tcp_ports": [80, 443], # List of TCP ports to open
184
- # "udp_ports": [53] # List of UDP ports to open
184
+ # Additional parameters obtained after deploying the master node:
185
+ "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
186
+ "cluster_name": "elastic_mcnulty", # Name of the cluster
187
+ "k3s_token": "G4lm7wEaFuCCygeU", # Token of the cluster
188
+ # Optional parameters
189
+ # If existing SG is specified, it will be used directly with no port changes
190
+ "security_group_id": "sg-0123456789abcdef0",
191
+ # No security_group_id means a new SG will be created and these ports applied as rules
192
+ # These ports will be used ONLY if creating a new SG
193
+ "tcp_ports": [10020], # Optional list of TCP ports to open
194
+ "udp_ports": [1003] # Optional list of UDP ports to open
185
195
  }
186
196
 
187
197
  # Add the worker node
@@ -226,17 +236,25 @@ Note for **Edge Devices**:
226
236
  Since the edge device is already provisioned, the `destroy` method will not remove K3s directly from the edge device. You will need to manually uninstall K3s from your edge device after the cluster is destroyed.
227
237
 
228
238
  ---
239
+ ### Deploying Manifests
229
240
 
230
- ### Important Configuration Requirements
231
- #### High Availability Flag (ha):
241
+ The deploy_manifests method copies Kubernetes manifests to the target cluster node.
232
242
 
233
- - For k3s_role="worker" or k3s_role="ha", you must specify a master_ip (the IP address of the master node).
243
+ ```python
244
+ orchestrator.deploy_manifests(
245
+ manifest_folder="path/to/manifests",
246
+ master_ip="MASTER_NODE_IP",
247
+ ssh_key_path="path/to/key.pem",
248
+ ssh_user="USERNAME"
249
+ )
250
+ ```
234
251
 
235
- - For k3s_role="master", you must not specify a master_ip.
252
+ ## Important Configuration Requirements
253
+ ### High Availability Flag (ha):
236
254
 
237
255
  - The ha flag should be set to True for high availability deployment (usually when adding a ha or worker node to an existing master).
238
256
 
239
- #### SSH Credentials:
257
+ ### SSH Credentials:
240
258
 
241
259
  - For all roles (k3s_role="master", k3s_role="worker", k3s_role="ha"), you must specify both ssh_user and ssh_private_key_path except for edge.
242
260
 
@@ -244,7 +262,7 @@ Since the edge device is already provisioned, the `destroy` method will not remo
244
262
 
245
263
  - The ssh_key_name and the ssh_private_key_path are different—ensure that your SSH key is placed correctly at the provided ssh_private_key_path.
246
264
 
247
- #### Ports:
265
+ ### Ports:
248
266
  You can specify custom ports for your nodes in the tcp_ports and udp_ports fields. However, certain ports are required for Kubernetes deployment (even if not specified explicitly):
249
267
 
250
268
  **TCP Ports:**
@@ -263,7 +281,7 @@ You can specify custom ports for your nodes in the tcp_ports and udp_ports field
263
281
  - 8472: VXLAN for Flannel
264
282
  - 53: DNS
265
283
 
266
- #### OpenStack:
284
+ ### OpenStack:
267
285
  When provisioning on OpenStack, you should provide the value for 'floating_ip_pool' from which floating IPs can be allocated for the instance. If not specified, OpenTofu will not assign floating IP.
268
286
 
269
287
  ---
@@ -1,6 +1,6 @@
1
1
  # Swarmchestrate - Cluster Builder
2
2
 
3
- This repository contains the codebase for **[cluster-builder]**, which builds K3s clusters for Swarmchestrate using OpenTofu.
3
+ This repository contains the codebase for **cluster-builder**, which builds K3s clusters for Swarmchestrate using OpenTofu.
4
4
 
5
5
  Key features:
6
6
  - **Create**: Provisions infrastructure using OpenTofu and installs K3s.
@@ -17,11 +17,10 @@ Before proceeding, ensure the following prerequisites are installed:
17
17
  1. **Git**: For cloning the repository.
18
18
  2. **Python**: Version 3.9 or higher.
19
19
  3. **pip**: Python package manager.
20
- 4. **OpenTofu**: Version 1.6 or higher for infrastructure provisioning.
21
- 6. **Make**: To run the provided `Makefile`.
22
- 7. **PostgreSQL**: For storing OpenTofu state.
23
- 8. (Optional) **Docker**: To create a dev Postgres
24
- 9. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
20
+ 4. **Make**: To run the provided `Makefile`.
21
+ 5. **PostgreSQL**: For storing OpenTofu state.
22
+ 6. (Optional) **Docker**: To create a dev Postgres
23
+ 7. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
25
24
 
26
25
  ---
27
26
 
@@ -126,16 +125,21 @@ orchestrator = Swarmchestrate(
126
125
  To create a new k3s cluster, use the **add_node** method with the **master** role:
127
126
 
128
127
  ```python
129
- # Configuration for a new cluster
128
+ # Configuration for a new cluster using aws provider
130
129
  config = {
131
- "cloud": "aws", # Can be 'aws', 'openstack', or 'edge'
132
- "k3s_role": "master", # Role can be 'master', 'worker', or 'ha'
130
+ "cloud": "aws",
131
+ "k3s_role": "master",
133
132
  "ha": False, # Set to True for high availability (HA) deployments
134
133
  "instance_type": "t2.small", # AWS instance type
135
134
  "ssh_key_name": "g", # SSH key name for AWS or OpenStack
136
135
  "ssh_user": "ec2-user", # SSH user for the instance
137
136
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
138
137
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS (specific to region)
138
+ # Optional parameters
139
+ # If existing SG is specified, it will be used directly with no port changes
140
+ "security_group_id": "sg-0123456789abcdef0",
141
+ # No security_group_id means a new SG will be created and these ports applied as rules
142
+ # These ports will be used ONLY if creating a new SG
139
143
  "tcp_ports": [10020], # Optional list of TCP ports to open
140
144
  "udp_ports": [1003] # Optional list of UDP ports to open
141
145
  }
@@ -145,27 +149,33 @@ cluster_name = orchestrator.add_node(config)
145
149
  print(f"Created cluster: {cluster_name}")
146
150
  ```
147
151
 
152
+ Note: Fetch the outputs from the master node and use them when adding a worker node.
153
+
148
154
  ### Adding Nodes to an Existing Cluster
149
155
 
150
156
  To add worker or high-availability nodes to an existing cluster:
151
157
 
152
158
  ```python
153
- # Configuration for adding a worker node
159
+ # Configuration for adding a worker node using aws provider
154
160
  worker_config = {
155
- "cloud": "aws", # Cloud provider (can be 'aws', 'openstack', or 'edge')
161
+ "cloud": "aws",
156
162
  "k3s_role": "worker", # Role can be 'worker' or 'ha'
157
- "ha": False, # Set to True for high availability (HA) deployments
158
163
  "instance_type": "t2.small", # AWS instance type
159
164
  "ssh_key_name": "g", # SSH key name
160
165
  "ssh_user": "ec2-user", # SSH user for the instance
161
166
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
162
167
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS
163
- # Optional parameters:
164
- # "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
165
- # "cluster_name": "elastic_mcnulty", # Name of the cluster
166
- # "security_group_id": "sg-xxxxxxxxxxxxxxx", # Security group ID for AWS or OpenStack
167
- # "tcp_ports": [80, 443], # List of TCP ports to open
168
- # "udp_ports": [53] # List of UDP ports to open
168
+ # Additional parameters obtained after deploying the master node:
169
+ "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
170
+ "cluster_name": "elastic_mcnulty", # Name of the cluster
171
+ "k3s_token": "G4lm7wEaFuCCygeU", # Token of the cluster
172
+ # Optional parameters
173
+ # If existing SG is specified, it will be used directly with no port changes
174
+ "security_group_id": "sg-0123456789abcdef0",
175
+ # No security_group_id means a new SG will be created and these ports applied as rules
176
+ # These ports will be used ONLY if creating a new SG
177
+ "tcp_ports": [10020], # Optional list of TCP ports to open
178
+ "udp_ports": [1003] # Optional list of UDP ports to open
169
179
  }
170
180
 
171
181
  # Add the worker node
@@ -210,17 +220,25 @@ Note for **Edge Devices**:
210
220
  Since the edge device is already provisioned, the `destroy` method will not remove K3s directly from the edge device. You will need to manually uninstall K3s from your edge device after the cluster is destroyed.
211
221
 
212
222
  ---
223
+ ### Deploying Manifests
213
224
 
214
- ### Important Configuration Requirements
215
- #### High Availability Flag (ha):
225
+ The deploy_manifests method copies Kubernetes manifests to the target cluster node.
216
226
 
217
- - For k3s_role="worker" or k3s_role="ha", you must specify a master_ip (the IP address of the master node).
227
+ ```python
228
+ orchestrator.deploy_manifests(
229
+ manifest_folder="path/to/manifests",
230
+ master_ip="MASTER_NODE_IP",
231
+ ssh_key_path="path/to/key.pem",
232
+ ssh_user="USERNAME"
233
+ )
234
+ ```
218
235
 
219
- - For k3s_role="master", you must not specify a master_ip.
236
+ ## Important Configuration Requirements
237
+ ### High Availability Flag (ha):
220
238
 
221
239
  - The ha flag should be set to True for high availability deployment (usually when adding a ha or worker node to an existing master).
222
240
 
223
- #### SSH Credentials:
241
+ ### SSH Credentials:
224
242
 
225
243
  - For all roles (k3s_role="master", k3s_role="worker", k3s_role="ha"), you must specify both ssh_user and ssh_private_key_path except for edge.
226
244
 
@@ -228,7 +246,7 @@ Since the edge device is already provisioned, the `destroy` method will not remo
228
246
 
229
247
  - The ssh_key_name and the ssh_private_key_path are different—ensure that your SSH key is placed correctly at the provided ssh_private_key_path.
230
248
 
231
- #### Ports:
249
+ ### Ports:
232
250
  You can specify custom ports for your nodes in the tcp_ports and udp_ports fields. However, certain ports are required for Kubernetes deployment (even if not specified explicitly):
233
251
 
234
252
  **TCP Ports:**
@@ -247,7 +265,7 @@ You can specify custom ports for your nodes in the tcp_ports and udp_ports field
247
265
  - 8472: VXLAN for Flannel
248
266
  - 53: DNS
249
267
 
250
- #### OpenStack:
268
+ ### OpenStack:
251
269
  When provisioning on OpenStack, you should provide the value for 'floating_ip_pool' from which floating IPs can be allocated for the instance. If not specified, OpenTofu will not assign floating IP.
252
270
 
253
271
  ---
@@ -131,9 +131,12 @@ class ClusterConfig:
131
131
  logger.debug(f"Cluster directory: {cluster_dir}")
132
132
 
133
133
  # Generate a resource name
134
- random_name = self.generate_random_name()
135
- prepared_config["resource_name"] = f"{cloud}-{random_name}"
136
- logger.debug(f"Resource name: {prepared_config['resource_name']}")
134
+ if "resource_name" not in prepared_config:
135
+ random_name = self.generate_random_name()
136
+ prepared_config["resource_name"] = f"{cloud}-{random_name}"
137
+ logger.debug(f"Resource name: {prepared_config['resource_name']}")
138
+ else:
139
+ logger.debug(f" USing provded Resource name: {prepared_config['resource_name']}")
137
140
 
138
141
  # Create the cluster directory
139
142
  try:
@@ -217,7 +217,7 @@ class Swarmchestrate:
217
217
  outputs_file = os.path.join(cluster_dir, "outputs.tf")
218
218
 
219
219
  # Define common output names
220
- output_names = ["cluster_name", "master_ip", "worker_ip", "ha_ip", "k3s_token", "node_name"]
220
+ output_names = ["cluster_name", "master_ip", "worker_ip", "ha_ip", "k3s_token", "resource_name"]
221
221
 
222
222
  # Include additional outputs based on the cloud type
223
223
  if "aws" in cluster_dir:
@@ -234,9 +234,9 @@ class Swarmchestrate:
234
234
  try:
235
235
  self.deploy(cluster_dir, dryrun)
236
236
  cluster_name = prepared_config["cluster_name"]
237
- node_name = prepared_config["resource_name"]
237
+ resource_name = prepared_config["resource_name"]
238
238
  logger.info(
239
- f"✅ Successfully added '{node_name}' for cluster '{cluster_name}'"
239
+ f"✅ Successfully added '{resource_name}' for cluster '{cluster_name}'"
240
240
  )
241
241
  # Run 'tofu output -json' to get outputs
242
242
  result = subprocess.run(
@@ -256,7 +256,7 @@ class Swarmchestrate:
256
256
  "k3s_token": outputs.get("k3s_token", {}).get("value"),
257
257
  "worker_ip": outputs.get("worker_ip", {}).get("value"),
258
258
  "ha_ip": outputs.get("ha_ip", {}).get("value"),
259
- "node_name": outputs.get("node_name", {}).get("value")
259
+ "resource_name": outputs.get("resource_name", {}).get("value")
260
260
  }
261
261
  # Add cloud-specific output
262
262
  if "aws" in cluster_dir:
@@ -520,7 +520,7 @@ class Swarmchestrate:
520
520
  if connection:
521
521
  connection.close()
522
522
 
523
- def run_copy_manifests_tf(
523
+ def deploy_manifests(
524
524
  self,
525
525
  manifest_folder: str,
526
526
  master_ip: str,
@@ -528,7 +528,7 @@ class Swarmchestrate:
528
528
  ssh_user: str,
529
529
  ):
530
530
  """
531
- Copy and apply manifests to a cluster using copy_manifest.tf in a separate folder.
531
+ Copy and apply manifests to a cluster using copy_manifest.tf in a temporaryfolder.
532
532
 
533
533
  Args:
534
534
  manifest_folder: Path to local manifest folder
@@ -539,49 +539,55 @@ class Swarmchestrate:
539
539
  # Dedicated folder for copy-manifest operations
540
540
  copy_dir = Path(self.output_dir) / "copy-manifest"
541
541
  copy_dir.mkdir(parents=True, exist_ok=True)
542
- logger.info(f"Using separate copy-manifest folder: {copy_dir}")
543
542
 
544
- # Copy copy_manifest.tf from templates
545
- tf_source_file = Path(self.template_manager.templates_dir) / "copy_manifest.tf"
546
- if not tf_source_file.exists():
547
- logger.error(f"copy_manifest.tf not found at: {tf_source_file}")
548
- raise RuntimeError(f"copy_manifest.tf not found at: {tf_source_file}")
549
- shutil.copy(tf_source_file, copy_dir)
550
- logger.info(f"Copied copy_manifest.tf to {copy_dir}")
551
-
552
- # Prepare environment for OpenTofu
553
- env_vars = os.environ.copy()
554
- env_vars["TF_LOG"] = os.getenv("TF_LOG", "INFO")
555
- env_vars["TF_LOG_PATH"] = os.getenv("TF_LOG_PATH", "/tmp/opentofu.log")
543
+ logger.debug(f"Using copy-manifest folder: {copy_dir}")
556
544
 
557
545
  try:
558
- # Initialize OpenTofu in the separate folder
559
- logger.info(f"Initializing OpenTofu in {copy_dir}...")
560
- subprocess.run(["tofu", "init"], cwd=copy_dir, check=True, env=env_vars)
561
-
562
- # Apply the copy-manifest resource
563
- logger.info(f"Applying copy-manifest resource in {copy_dir}...")
564
- cmd = [
565
- "tofu",
566
- "apply",
567
- "-auto-approve",
568
- f"-var=manifest_folder={manifest_folder}",
569
- f"-var=master_ip={master_ip}",
570
- f"-var=ssh_private_key_path={ssh_key_path}",
571
- f"-var=ssh_user={ssh_user}"
572
- ]
573
- result = subprocess.run(cmd, cwd=copy_dir, check=True, capture_output=True, text=True, env=env_vars)
574
-
575
- # Log output
576
- if result.stdout:
577
- logger.info(result.stdout)
578
- if result.stderr:
579
- logger.warning(result.stderr)
580
-
581
- logger.info("✅ Copy-manifest applied successfully on master node.")
546
+ # Copy copy_manifest.tf from templates
547
+ tf_source_file = Path(self.template_manager.templates_dir) / "deploy_manifest.tf"
548
+ if not tf_source_file.exists():
549
+ logger.debug(f"deploy_manifest.tf not found at: {tf_source_file}")
550
+ raise RuntimeError(f"deploy_manifest.tf not found at: {tf_source_file}")
551
+ shutil.copy(tf_source_file, copy_dir)
552
+ logger.debug(f"Copied copy_manifest.tf to {copy_dir}")
553
+
554
+ # Prepare environment for OpenTofu
555
+ env_vars = os.environ.copy()
556
+ env_vars["TF_LOG"] = os.getenv("TF_LOG", "INFO")
557
+ env_vars["TF_LOG_PATH"] = os.getenv("TF_LOG_PATH", "/tmp/opentofu.log")
558
+
559
+ logger.info(f"------------ Applying manifest on node: {master_ip} -------------------")
560
+
561
+ # Run tofu init with spinner
562
+ CommandExecutor.run_command(
563
+ ["tofu", "init"],
564
+ cwd=str(copy_dir),
565
+ description="OpenTofu init",
566
+ env=env_vars,
567
+ )
582
568
 
583
- except subprocess.CalledProcessError as e:
584
- error_msg = f"Error applying copy-manifest on master {master_ip}: {e.stderr or e.stdout}"
585
- logger.error(error_msg)
586
- raise RuntimeError(error_msg)
569
+ # Run tofu apply with spinner
570
+ CommandExecutor.run_command(
571
+ [
572
+ "tofu",
573
+ "apply",
574
+ "-auto-approve",
575
+ f"-var=manifest_folder={manifest_folder}",
576
+ f"-var=master_ip={master_ip}",
577
+ f"-var=ssh_private_key_path={ssh_key_path}",
578
+ f"-var=ssh_user={ssh_user}"
579
+ ],
580
+ cwd=str(copy_dir),
581
+ description="OpenTofu apply",
582
+ env=env_vars,
583
+ )
584
+
585
+ logger.info("------------ Successfully applied manifests -------------------")
586
+
587
+ except RuntimeError as e:
588
+ print(f"\n---------- ERROR ----------\n{e}\n")
589
+ raise
587
590
 
591
+ finally:
592
+ if copy_dir.exists():
593
+ shutil.rmtree(copy_dir)
@@ -91,7 +91,7 @@ resource "aws_instance" "k3s_node" {
91
91
  vpc_security_group_ids = var.security_group_id != "" ? [var.security_group_id] : [aws_security_group.k3s_sg[0].id]
92
92
 
93
93
  tags = {
94
- Name = "${var.cluster_name}-${var.resource_name}"
94
+ Name = "${var.resource_name}"
95
95
  ClusterName = var.cluster_name
96
96
  Role = var.k3s_role
97
97
  }
@@ -104,7 +104,7 @@ resource "aws_instance" "k3s_node" {
104
104
  master_ip = var.master_ip,
105
105
  cluster_name = var.cluster_name,
106
106
  public_ip = self.public_ip,
107
- node_name = "${var.cluster_name}-${var.resource_name}"
107
+ resource_name = "${var.resource_name}"
108
108
  })
109
109
  destination = "/tmp/k3s_user_data.sh"
110
110
  }
@@ -151,6 +151,6 @@ output "instance_status" {
151
151
  value = aws_instance.k3s_node.id
152
152
  }
153
153
 
154
- output "node_name" {
154
+ output "resource_name" {
155
155
  value = aws_instance.k3s_node.tags["Name"]
156
156
  }
@@ -0,0 +1,37 @@
1
+ # main.tf
2
+
3
+ variable "manifest_folder" {}
4
+ variable "ssh_private_key_path" {}
5
+ variable "master_ip" {}
6
+ variable "ssh_user" {}
7
+
8
+ resource "null_resource" "copy_manifests" {
9
+ connection {
10
+ type = "ssh"
11
+ user = var.ssh_user
12
+ private_key = file(var.ssh_private_key_path)
13
+ host = var.master_ip
14
+ }
15
+
16
+ # Copy the manifest folder into /tmp
17
+ provisioner "file" {
18
+ source = var.manifest_folder
19
+ destination = "/tmp/"
20
+ }
21
+
22
+ # Apply namespace.yaml first if exists
23
+ provisioner "remote-exec" {
24
+ inline = [
25
+ "folder_name=$(basename ${var.manifest_folder})",
26
+ "if [ -f /tmp/$folder_name/namespace.yaml ]; then sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -f /tmp/$folder_name/namespace.yaml; fi"
27
+ ]
28
+ }
29
+
30
+ # Apply the rest of the manifests
31
+ provisioner "remote-exec" {
32
+ inline = [
33
+ "folder_name=$(basename ${var.manifest_folder})",
34
+ "sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -R -f /tmp/$folder_name"
35
+ ]
36
+ }
37
+ }
@@ -30,7 +30,7 @@ data "template_file" "user_data" {
30
30
  ha = var.ha
31
31
  public_ip = var.edge_device_ip
32
32
  master_ip = var.master_ip
33
- node_name = "${var.cluster_name}-${var.resource_name}"
33
+ resource_name = "${var.resource_name}"
34
34
  }
35
35
  }
36
36
 
@@ -63,7 +63,7 @@ resource "null_resource" "deploy_k3s_edge" {
63
63
  }
64
64
 
65
65
  triggers = {
66
- Name = "K3s-${var.k3s_role}-${var.cluster_name}-${var.resource_name}"
66
+ Name = "${var.resource_name}"
67
67
  cluster_name = var.cluster_name
68
68
  role = var.k3s_role
69
69
  resource_name = var.resource_name
@@ -93,6 +93,6 @@ output "k3s_token" {
93
93
  value = var.k3s_token
94
94
  }
95
95
 
96
- output "node_name" {
97
- value = "${var.cluster_name}-${var.resource_name}"
96
+ output "resource_name" {
97
+ value = "var.resource_name}"
98
98
  }
@@ -21,7 +21,7 @@ log_message "Installing K3s HA Server and joining the cluster..."
21
21
  if ! curl -sfL https://get.k3s.io | K3S_TOKEN="${k3s_token}" sh -s - server \
22
22
  --server "https://${master_ip}:6443" \
23
23
  --node-external-ip="${public_ip}" \
24
- --node-name="${node_name}" \
24
+ --node-name="${resource_name}" \
25
25
  --flannel-backend=wireguard-native \
26
26
  --flannel-external-ip; then
27
27
  log_message "ERROR: K3s server installation failed!"
@@ -25,10 +25,10 @@ else
25
25
  # Templated installation based on HA configuration
26
26
  if [[ "${ha}" == "true" ]]; then
27
27
  log_message "Installing in HA mode using cluster-init..."
28
- curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--cluster-init --node-external-ip=${public_ip} --node-name="${node_name}" --flannel-backend=wireguard-native --flannel-external-ip" K3S_TOKEN="${k3s_token}" sh -s - server
28
+ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--cluster-init --node-external-ip=${public_ip} --node-name="${resource_name}" --flannel-backend=wireguard-native --flannel-external-ip" K3S_TOKEN="${k3s_token}" sh -s - server
29
29
  else
30
30
  log_message "Installing in single-server mode..."
31
- curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--node-external-ip=${public_ip} --node-name="${node_name}" --flannel-backend=wireguard-native --flannel-external-ip" K3S_TOKEN="${k3s_token}" sh -s - server
31
+ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--node-external-ip=${public_ip} --node-name="${resource_name}" --flannel-backend=wireguard-native --flannel-external-ip" K3S_TOKEN="${k3s_token}" sh -s - server
32
32
  fi
33
33
 
34
34
  log_message "K3s installation completed successfully."
@@ -113,7 +113,7 @@ resource "openstack_networking_port_secgroup_associate_v2" "port_2" {
113
113
  resource "openstack_compute_instance_v2" "k3s_node" {
114
114
  depends_on = [openstack_networking_port_v2.port_1]
115
115
 
116
- name = "${var.cluster_name}-${var.resource_name}"
116
+ name = "${var.resource_name}"
117
117
  flavor_name = var.openstack_flavor_id
118
118
  key_pair = var.ssh_key_name
119
119
  # Only add the image_id if block device is NOT used
@@ -136,7 +136,7 @@ resource "openstack_compute_instance_v2" "k3s_node" {
136
136
  }
137
137
 
138
138
  tags = [
139
- "${var.cluster_name}-${var.resource_name}",
139
+ "${var.resource_name}",
140
140
  "ClusterName=${var.cluster_name}",
141
141
  "Role=${var.k3s_role}"
142
142
  ]
@@ -166,7 +166,7 @@ resource "null_resource" "k3s_provision" {
166
166
  master_ip = var.master_ip,
167
167
  cluster_name = var.cluster_name,
168
168
  public_ip = openstack_networking_floatingip_v2.floatip_1.address,
169
- node_name = "${var.cluster_name}-${var.resource_name}"
169
+ resource_name = "${var.resource_name}"
170
170
  })
171
171
  destination = "/tmp/k3s_user_data.sh"
172
172
  }
@@ -213,6 +213,6 @@ output "instance_power_state" {
213
213
  value = openstack_compute_instance_v2.k3s_node.power_state
214
214
  }
215
215
 
216
- output "node_name" {
216
+ output "resource_name" {
217
217
  value = openstack_compute_instance_v2.k3s_node.name
218
218
  }
@@ -23,7 +23,7 @@ else
23
23
  export K3S_TOKEN="${k3s_token}"
24
24
 
25
25
  # Install the K3s agent and join the cluster
26
- if ! curl -sfL https://get.k3s.io | sh -s - agent --node-external-ip="${public_ip}" --node-name="${node_name}"; then
26
+ if ! curl -sfL https://get.k3s.io | sh -s - agent --node-external-ip="${public_ip}" --node-name="${resource_name}"; then
27
27
  log_message "ERROR: K3s agent installation failed!"
28
28
  exit 1
29
29
  else
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cluster-builder
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Swarmchestrate cluster builder
5
5
  Author-email: Gunjan <G.Kotak@westminster.ac.uk>, Jay <J.Deslauriers@westminster.ac.uk>
6
6
  License: Apache2
@@ -16,7 +16,7 @@ Dynamic: license-file
16
16
 
17
17
  # Swarmchestrate - Cluster Builder
18
18
 
19
- This repository contains the codebase for **[cluster-builder]**, which builds K3s clusters for Swarmchestrate using OpenTofu.
19
+ This repository contains the codebase for **cluster-builder**, which builds K3s clusters for Swarmchestrate using OpenTofu.
20
20
 
21
21
  Key features:
22
22
  - **Create**: Provisions infrastructure using OpenTofu and installs K3s.
@@ -33,11 +33,10 @@ Before proceeding, ensure the following prerequisites are installed:
33
33
  1. **Git**: For cloning the repository.
34
34
  2. **Python**: Version 3.9 or higher.
35
35
  3. **pip**: Python package manager.
36
- 4. **OpenTofu**: Version 1.6 or higher for infrastructure provisioning.
37
- 6. **Make**: To run the provided `Makefile`.
38
- 7. **PostgreSQL**: For storing OpenTofu state.
39
- 8. (Optional) **Docker**: To create a dev Postgres
40
- 9. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
36
+ 4. **Make**: To run the provided `Makefile`.
37
+ 5. **PostgreSQL**: For storing OpenTofu state.
38
+ 6. (Optional) **Docker**: To create a dev Postgres
39
+ 7. For detailed instructions on **edge device requirements**, refer to the [Edge Device Requirements](docs/edge-requirements.md) document.
41
40
 
42
41
  ---
43
42
 
@@ -142,16 +141,21 @@ orchestrator = Swarmchestrate(
142
141
  To create a new k3s cluster, use the **add_node** method with the **master** role:
143
142
 
144
143
  ```python
145
- # Configuration for a new cluster
144
+ # Configuration for a new cluster using aws provider
146
145
  config = {
147
- "cloud": "aws", # Can be 'aws', 'openstack', or 'edge'
148
- "k3s_role": "master", # Role can be 'master', 'worker', or 'ha'
146
+ "cloud": "aws",
147
+ "k3s_role": "master",
149
148
  "ha": False, # Set to True for high availability (HA) deployments
150
149
  "instance_type": "t2.small", # AWS instance type
151
150
  "ssh_key_name": "g", # SSH key name for AWS or OpenStack
152
151
  "ssh_user": "ec2-user", # SSH user for the instance
153
152
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
154
153
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS (specific to region)
154
+ # Optional parameters
155
+ # If existing SG is specified, it will be used directly with no port changes
156
+ "security_group_id": "sg-0123456789abcdef0",
157
+ # No security_group_id means a new SG will be created and these ports applied as rules
158
+ # These ports will be used ONLY if creating a new SG
155
159
  "tcp_ports": [10020], # Optional list of TCP ports to open
156
160
  "udp_ports": [1003] # Optional list of UDP ports to open
157
161
  }
@@ -161,27 +165,33 @@ cluster_name = orchestrator.add_node(config)
161
165
  print(f"Created cluster: {cluster_name}")
162
166
  ```
163
167
 
168
+ Note: Fetch the outputs from the master node and use them when adding a worker node.
169
+
164
170
  ### Adding Nodes to an Existing Cluster
165
171
 
166
172
  To add worker or high-availability nodes to an existing cluster:
167
173
 
168
174
  ```python
169
- # Configuration for adding a worker node
175
+ # Configuration for adding a worker node using aws provider
170
176
  worker_config = {
171
- "cloud": "aws", # Cloud provider (can be 'aws', 'openstack', or 'edge')
177
+ "cloud": "aws",
172
178
  "k3s_role": "worker", # Role can be 'worker' or 'ha'
173
- "ha": False, # Set to True for high availability (HA) deployments
174
179
  "instance_type": "t2.small", # AWS instance type
175
180
  "ssh_key_name": "g", # SSH key name
176
181
  "ssh_user": "ec2-user", # SSH user for the instance
177
182
  "ssh_private_key_path": "/workspaces/cluster-builder/scripts/g.pem", # Path to SSH private key
178
183
  "ami": "ami-0c0493bbac867d427", # AMI ID for AWS
179
- # Optional parameters:
180
- # "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
181
- # "cluster_name": "elastic_mcnulty", # Name of the cluster
182
- # "security_group_id": "sg-xxxxxxxxxxxxxxx", # Security group ID for AWS or OpenStack
183
- # "tcp_ports": [80, 443], # List of TCP ports to open
184
- # "udp_ports": [53] # List of UDP ports to open
184
+ # Additional parameters obtained after deploying the master node:
185
+ "master_ip": "12.13.14.15", # IP address of the master node (required for worker/HA roles)
186
+ "cluster_name": "elastic_mcnulty", # Name of the cluster
187
+ "k3s_token": "G4lm7wEaFuCCygeU", # Token of the cluster
188
+ # Optional parameters
189
+ # If existing SG is specified, it will be used directly with no port changes
190
+ "security_group_id": "sg-0123456789abcdef0",
191
+ # No security_group_id means a new SG will be created and these ports applied as rules
192
+ # These ports will be used ONLY if creating a new SG
193
+ "tcp_ports": [10020], # Optional list of TCP ports to open
194
+ "udp_ports": [1003] # Optional list of UDP ports to open
185
195
  }
186
196
 
187
197
  # Add the worker node
@@ -226,17 +236,25 @@ Note for **Edge Devices**:
226
236
  Since the edge device is already provisioned, the `destroy` method will not remove K3s directly from the edge device. You will need to manually uninstall K3s from your edge device after the cluster is destroyed.
227
237
 
228
238
  ---
239
+ ### Deploying Manifests
229
240
 
230
- ### Important Configuration Requirements
231
- #### High Availability Flag (ha):
241
+ The deploy_manifests method copies Kubernetes manifests to the target cluster node.
232
242
 
233
- - For k3s_role="worker" or k3s_role="ha", you must specify a master_ip (the IP address of the master node).
243
+ ```python
244
+ orchestrator.deploy_manifests(
245
+ manifest_folder="path/to/manifests",
246
+ master_ip="MASTER_NODE_IP",
247
+ ssh_key_path="path/to/key.pem",
248
+ ssh_user="USERNAME"
249
+ )
250
+ ```
234
251
 
235
- - For k3s_role="master", you must not specify a master_ip.
252
+ ## Important Configuration Requirements
253
+ ### High Availability Flag (ha):
236
254
 
237
255
  - The ha flag should be set to True for high availability deployment (usually when adding a ha or worker node to an existing master).
238
256
 
239
- #### SSH Credentials:
257
+ ### SSH Credentials:
240
258
 
241
259
  - For all roles (k3s_role="master", k3s_role="worker", k3s_role="ha"), you must specify both ssh_user and ssh_private_key_path except for edge.
242
260
 
@@ -244,7 +262,7 @@ Since the edge device is already provisioned, the `destroy` method will not remo
244
262
 
245
263
  - The ssh_key_name and the ssh_private_key_path are different—ensure that your SSH key is placed correctly at the provided ssh_private_key_path.
246
264
 
247
- #### Ports:
265
+ ### Ports:
248
266
  You can specify custom ports for your nodes in the tcp_ports and udp_ports fields. However, certain ports are required for Kubernetes deployment (even if not specified explicitly):
249
267
 
250
268
  **TCP Ports:**
@@ -263,7 +281,7 @@ You can specify custom ports for your nodes in the tcp_ports and udp_ports field
263
281
  - 8472: VXLAN for Flannel
264
282
  - 53: DNS
265
283
 
266
- #### OpenStack:
284
+ ### OpenStack:
267
285
  When provisioning on OpenStack, you should provide the value for 'floating_ip_pool' from which floating IPs can be allocated for the instance. If not specified, OpenTofu will not assign floating IP.
268
286
 
269
287
  ---
@@ -15,7 +15,7 @@ cluster_builder/infrastructure/__init__.py
15
15
  cluster_builder/infrastructure/executor.py
16
16
  cluster_builder/infrastructure/templates.py
17
17
  cluster_builder/templates/aws_provider.tf
18
- cluster_builder/templates/copy_manifest.tf
18
+ cluster_builder/templates/deploy_manifest.tf
19
19
  cluster_builder/templates/ha_user_data.sh.tpl
20
20
  cluster_builder/templates/master_user_data.sh.tpl
21
21
  cluster_builder/templates/openstack_provider.tf
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cluster-builder"
7
- version = "0.3.1"
7
+ version = "0.3.3"
8
8
  description = "Swarmchestrate cluster builder"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -1,36 +0,0 @@
1
- # main.tf
2
-
3
- variable "manifest_folder" {}
4
- variable "ssh_private_key_path" {}
5
- variable "master_ip" {}
6
- variable "ssh_user" {}
7
-
8
- resource "null_resource" "copy_manifests" {
9
- connection {
10
- type = "ssh"
11
- user = var.ssh_user
12
- private_key = file(var.ssh_private_key_path)
13
- host = var.master_ip
14
- }
15
-
16
- # Ensure the manifests folder exists on the remote host
17
- provisioner "remote-exec" {
18
- inline = [
19
- "mkdir -p /home/${var.ssh_user}/manifests",
20
- "sudo chmod 755 /home/${var.ssh_user}/manifests"
21
- ]
22
- }
23
-
24
- # Copy the manifests
25
- provisioner "file" {
26
- source = var.manifest_folder
27
- destination = "/home/${var.ssh_user}"
28
- }
29
-
30
- # Apply manifests using K3s kubeconfig
31
- provisioner "remote-exec" {
32
- inline = [
33
- "sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -R -f /home/ubuntu/manifests/"
34
- ]
35
- }
36
- }
File without changes