cluster-builder 0.3.2__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.

@@ -591,3 +591,107 @@ class Swarmchestrate:
591
591
  finally:
592
592
  if copy_dir.exists():
593
593
  shutil.rmtree(copy_dir)
594
+
595
+ def create_registry_secrets(self, cluster_config: dict):
596
+ """
597
+ Create Docker registry secrets in Kubernetes using OpenTofu.
598
+
599
+ :param cluster_config: dict with keys:
600
+ {
601
+ "master_ip": "1.2.3.4",
602
+ "ssh_user": "ubuntu",
603
+ "ssh_private_key_path": "/path/to/key.pem",
604
+ "namespace": "optional-namespace",
605
+ "secret_names": ["optional-name1", "optional-name2"]
606
+ }
607
+ """
608
+ load_dotenv()
609
+
610
+ # Read registry creds from env
611
+ registries = os.getenv("DOCKER_REGISTRIES", "").split(",")
612
+ usernames = os.getenv("DOCKER_USERNAMES", "").split(",")
613
+ passwords = os.getenv("DOCKER_PASSWORDS", "").split(",")
614
+
615
+ if not (len(registries) == len(usernames) == len(passwords)):
616
+ raise RuntimeError("Mismatch in registry, username, and password counts")
617
+
618
+ # Get cluster connection from method input
619
+ master_ip = cluster_config.get("master_ip")
620
+ ssh_user = cluster_config.get("ssh_user")
621
+ ssh_key_path = cluster_config.get("ssh_private_key_path")
622
+ namespace = cluster_config.get("namespace", "default")
623
+ secret_names = cluster_config.get("secret_names", [])
624
+
625
+ if not all([master_ip, ssh_user, ssh_key_path]):
626
+ raise ValueError("Cluster config missing required keys")
627
+
628
+ # Validate secret_names length if provided
629
+ if secret_names and len(secret_names) != len(registries):
630
+ raise RuntimeError("Length of secret_names must match number of registries")
631
+
632
+ # Create temp dir for TF
633
+ temp_dir = Path(self.output_dir) / "registry-secret"
634
+ temp_dir.mkdir(parents=True, exist_ok=True)
635
+
636
+ try:
637
+ # Copy template tf file into temp dir
638
+ tf_source_file = Path(self.template_manager.templates_dir) / "registry_secret.tf"
639
+ if not tf_source_file.exists():
640
+ logger.debug(f"registry_secret.tf not found at: {tf_source_file}")
641
+ raise RuntimeError(f"registry_secret.tf not found at: {tf_source_file}")
642
+
643
+ tf_target = temp_dir / "registry_secret.tf"
644
+ shutil.copy(tf_source_file, tf_target)
645
+ logger.debug(f"Copied registry_secret.tf to {temp_dir}")
646
+
647
+ # Setup env for tofu
648
+ env_vars = os.environ.copy()
649
+ env_vars["TF_LOG"] = os.getenv("TF_LOG", "INFO")
650
+
651
+ # tofu init
652
+ CommandExecutor.run_command(
653
+ ["tofu", "init"],
654
+ cwd=str(temp_dir),
655
+ description="Init OpenTofu",
656
+ env=env_vars,
657
+ )
658
+
659
+ # Apply registry secrets
660
+ apply_vars = [
661
+ f"-var=registries={json.dumps(registries)}",
662
+ f"-var=usernames={json.dumps(usernames)}",
663
+ f"-var=passwords={json.dumps(passwords)}",
664
+ f"-var=master_ip={master_ip}",
665
+ f"-var=ssh_user={ssh_user}",
666
+ f"-var=ssh_private_key_path={ssh_key_path}",
667
+ f"-var=namespace={namespace}"
668
+ ]
669
+ if secret_names:
670
+ apply_vars.append(f"-var=secret_names={json.dumps(secret_names)}")
671
+
672
+ CommandExecutor.run_command(
673
+ ["tofu", "apply", "-auto-approve"] + apply_vars,
674
+ cwd=str(temp_dir),
675
+ description="Apply registry secrets",
676
+ env=env_vars,
677
+ )
678
+
679
+ # Fetch Terraform/OpenTofu output
680
+ output_result = CommandExecutor.run_command(
681
+ ["tofu", "output", "-json", "docker_registry_secret_names"],
682
+ cwd=str(temp_dir),
683
+ description="Fetch registry secret names",
684
+ env=env_vars,
685
+ )
686
+
687
+ lines = [line for line in output_result.splitlines() if line.strip()]
688
+ if not lines:
689
+ raise RuntimeError("No output received from OpenTofu for secret names")
690
+ secret_names_list = json.loads(lines[-1])
691
+ logger.info(f"Created registry secrets: {secret_names_list}")
692
+
693
+ return secret_names_list
694
+
695
+ finally:
696
+ logger.debug(f"Cleaning up temp dir: {temp_dir}")
697
+ shutil.rmtree(temp_dir)
@@ -13,31 +13,25 @@ resource "null_resource" "copy_manifests" {
13
13
  host = var.master_ip
14
14
  }
15
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
16
+ # Copy the manifest folder into /tmp
25
17
  provisioner "file" {
26
18
  source = var.manifest_folder
27
- destination = "/home/${var.ssh_user}"
19
+ destination = "/tmp/"
28
20
  }
29
21
 
30
- # Apply namespace.yaml first
22
+ # Apply namespace.yaml first if exists
31
23
  provisioner "remote-exec" {
32
24
  inline = [
33
- "sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -f /home/${var.ssh_user}/manifests/namespace.yaml"
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"
34
27
  ]
35
28
  }
36
29
 
37
30
  # Apply the rest of the manifests
38
31
  provisioner "remote-exec" {
39
32
  inline = [
40
- "sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -R -f /home/${var.ssh_user}/manifests/ --selector='!namespace.yaml'"
33
+ "folder_name=$(basename ${var.manifest_folder})",
34
+ "sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -R -f /tmp/$folder_name"
41
35
  ]
42
36
  }
43
37
  }
@@ -0,0 +1,52 @@
1
+ variable "registries" {
2
+ type = list(string)
3
+ }
4
+
5
+ variable "usernames" {
6
+ type = list(string)
7
+ }
8
+
9
+ variable "passwords" {
10
+ type = list(string)
11
+ }
12
+
13
+ variable "secret_names" {
14
+ type = list(string)
15
+ default = []
16
+ }
17
+
18
+ variable "master_ip" {}
19
+ variable "ssh_user" {}
20
+ variable "ssh_private_key_path" {}
21
+ variable "namespace" {
22
+ default = "default"
23
+ }
24
+
25
+ resource "null_resource" "docker_registry_secrets" {
26
+ count = length(var.registries)
27
+
28
+ connection {
29
+ type = "ssh"
30
+ host = var.master_ip
31
+ user = var.ssh_user
32
+ private_key = file(var.ssh_private_key_path)
33
+ }
34
+
35
+ provisioner "remote-exec" {
36
+ inline = [
37
+ <<EOT
38
+ SECRET_NAME=${length(var.secret_names) > 0 ? var.secret_names[count.index] : "regcred-${count.index}"}
39
+ sudo -E KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl create secret docker-registry $SECRET_NAME \
40
+ --docker-server="${var.registries[count.index]}" \
41
+ --docker-username="${var.usernames[count.index]}" \
42
+ --docker-password="${var.passwords[count.index]}" \
43
+ --namespace="${var.namespace}" \
44
+ --dry-run=client -o yaml | sudo kubectl apply -f -
45
+ EOT
46
+ ]
47
+ }
48
+ }
49
+
50
+ output "docker_registry_secret_names" {
51
+ value = [for i in range(length(var.registries)) : length(var.secret_names) > 0 ? var.secret_names[i] : "regcred-${i}"]
52
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cluster-builder
3
- Version: 0.3.2
3
+ Version: 0.4.0
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
@@ -1,5 +1,5 @@
1
1
  cluster_builder/__init__.py,sha256=p2Rb2BTVm-ScqCKE38436WsItY1BjVAnvx7zwmneSLs,256
2
- cluster_builder/swarmchestrate.py,sha256=LwIRR1HGD6y6XKhAxDU-T68vIPjtRIeaoaHX95wM_ZM,23139
2
+ cluster_builder/swarmchestrate.py,sha256=3cVjj1Qe2LT-N8GUL6W-jaexf6yJS6aKGaqkiUojEO8,27388
3
3
  cluster_builder/config/__init__.py,sha256=HqCua7nqa0m4RNrH-wAw-GNZ8PfmKOeYs2Ur81xGIKU,222
4
4
  cluster_builder/config/cluster.py,sha256=0CASucE_npbEmGnyR3UmF0v836tcx9HthAiotCh4sSo,5116
5
5
  cluster_builder/config/postgres.py,sha256=nQ5QxxI00GmGAbDl_9I1uEU2eBy1D2eJWGzhsBYUFMc,3354
@@ -7,10 +7,11 @@ cluster_builder/infrastructure/__init__.py,sha256=e8XY3K7Y6FJS-ODr5ufB_myV7btFvY
7
7
  cluster_builder/infrastructure/executor.py,sha256=oymr_ZP8xAOcNDAuGCp1v4F81-chR3VRotoD732l4q0,2874
8
8
  cluster_builder/infrastructure/templates.py,sha256=TAdNP-012L76dOYsd7JVIQOD4K9XNobK9QWfOoYrbeU,4084
9
9
  cluster_builder/templates/aws_provider.tf,sha256=VIRuH_-8pYtJ0Mkck38WUSszHiN3DesFOWkx75aoOIY,425
10
- cluster_builder/templates/deploy_manifest.tf,sha256=bzvcK-5iAFDMGU32YR5os6qXF1p9d7qWqlv7Kqm72Qo,1106
10
+ cluster_builder/templates/deploy_manifest.tf,sha256=kFf3Q6nuvYzFxFbVdGPjiFINN8ep4_8n0BAMx5UD5nQ,1004
11
11
  cluster_builder/templates/ha_user_data.sh.tpl,sha256=njvsBRjdKBuUaYbujJ689wI2sfpoHVpr2kkbG9sKzpw,981
12
12
  cluster_builder/templates/master_user_data.sh.tpl,sha256=g_uaehoi9Pm_vCx_vJhXCUqAt7DpcqnAi_QPm5VOgWw,1481
13
13
  cluster_builder/templates/openstack_provider.tf,sha256=wFUmkws5xSTOM1GW0Jd8JD__VAUBPNF4j1amo2SRyVM,2049
14
+ cluster_builder/templates/registry_secret.tf,sha256=_om5QIQR2lEVDJb-4B7t25uHL66bGLa7XPSBTQ16E-Y,1336
14
15
  cluster_builder/templates/worker_user_data.sh.tpl,sha256=9WP6qe6DGMHgFds_loI1N7DEuMeOI6U4SA-g3GYIIIU,1034
15
16
  cluster_builder/templates/aws/main.tf,sha256=v_mR6tdH4-E1SKI8FNqfgl-gU2POrKqRfkXCXV1DGFQ,4875
16
17
  cluster_builder/templates/edge/main.tf,sha256=8sBL_ofFfhMEH2biPRmB7X4H_SG3JgYygCOEo90yDTY,2255
@@ -18,8 +19,8 @@ cluster_builder/templates/openstack/main.tf,sha256=uMzArcNE0wbx23Y0x9B7jGIiWIgJd
18
19
  cluster_builder/utils/__init__.py,sha256=TeronqOND-SIfi0e76lwD1HfUiPO2h2ZfYhLIwZ3Aks,145
19
20
  cluster_builder/utils/hcl.py,sha256=VptRAt2Cy0AxowqMJBZ60KGe4Uptji3Y9WiYrDQsrqY,11534
20
21
  cluster_builder/utils/logging.py,sha256=rwDViuqG8PMcXJWHOdtdgbGhWMnbSZ4MwfKsXHxu2B4,1242
21
- cluster_builder-0.3.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
- cluster_builder-0.3.2.dist-info/METADATA,sha256=7M-LAWWdwURezuH4N169kDUZJPjT89ERxH6PlNJ5lOU,10937
23
- cluster_builder-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- cluster_builder-0.3.2.dist-info/top_level.txt,sha256=fTW8EW1mcWoeWprjwxSHRWpqfXYX8iN-ByEt8HPXIcs,16
25
- cluster_builder-0.3.2.dist-info/RECORD,,
22
+ cluster_builder-0.4.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
23
+ cluster_builder-0.4.0.dist-info/METADATA,sha256=O_6VEjEZY7hdC-Z_t0VV4T2vUGa5OiOXlSZ6yc-d7JU,10937
24
+ cluster_builder-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ cluster_builder-0.4.0.dist-info/top_level.txt,sha256=fTW8EW1mcWoeWprjwxSHRWpqfXYX8iN-ByEt8HPXIcs,16
26
+ cluster_builder-0.4.0.dist-info/RECORD,,