From 16753166c6c29244d1e357f15e54e9f6ff4a66c9 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Mon, 4 Dec 2023 13:45:58 -0600 Subject: [PATCH 1/6] WIP: k8s status via ps --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 56 ++++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index c84aa34a..619095f8 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -26,6 +26,12 @@ from stack_orchestrator.deploy.deployment_context import DeploymentContext from stack_orchestrator.util import error_exit +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + + def _check_delete_exception(e: client.exceptions.ApiException): if e.status == 404: if opts.o.debug: @@ -42,7 +48,7 @@ class K8sDeployer(Deployer): networking_api: client.NetworkingV1Api k8s_namespace: str = "default" kind_cluster_name: str - cluster_info : ClusterInfo + cluster_info: ClusterInfo deployment_dir: Path deployment_context: DeploymentContext @@ -72,6 +78,7 @@ class K8sDeployer(Deployer): self.core_api = client.CoreV1Api() self.networking_api = client.NetworkingV1Api() self.apps_api = client.AppsV1Api() + self.custom_obj_api = client.CustomObjectsApi() def up(self, detach, services): @@ -205,12 +212,47 @@ class K8sDeployer(Deployer): def ps(self): self.connect_api() # Call whatever API we need to get the running container list - ret = self.core_api.list_pod_for_all_namespaces(watch=False) - if ret.items: - for i in ret.items: - print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name)) - ret = self.core_api.list_node(pretty=True, watch=False) - return [] + pods = self.core_api.list_pod_for_all_namespaces(watch=False) + + hostname = "?" + ip = "?" + tls = "?" + try: + ingress = self.networking_api.read_namespaced_ingress(namespace=self.k8s_namespace, + name=self.cluster_info.get_ingress().metadata.name) + + cert = self.custom_obj_api.get_namespaced_custom_object( + group="cert-manager.io", + version="v1", + namespace=self.k8s_namespace, + plural="certificates", + name=ingress.spec.tls[0].secret_name + ) + + hostname = ingress.spec.tls[0].hosts[0] + ip = ingress.status.load_balancer.ingress[0].ip + tls = "notBefore: %s, notAfter: %s" % (cert["status"]["notBefore"], cert["status"]["notAfter"]) + except: # noqa: E722 + pass + + print("Hostname:", hostname) + print("IP:", ip) + print("TLS:", tls) + print("") + + ret = [] + if pods.items: + for i in pods.items: + if self.cluster_info.app_name in i.metadata.name: + ret.append(AttrDict({ + "id": i.metadata.name, + "name": i.metadata.name, + "namespace": i.metadata.namespace, + "network_settings": AttrDict({ + "ports": {} + }) + })) + return ret def port(self, service, private_port): # Since we handle the port mapping, need to figure out where this comes from -- 2.45.2 From ad437b210947bf815c30a08056d7bda5bc71d1df Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Mon, 4 Dec 2023 14:21:12 -0600 Subject: [PATCH 2/6] Add k8s status output for 'deploy ps' --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 57 +++++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 619095f8..899bd121 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -212,8 +212,18 @@ class K8sDeployer(Deployer): def ps(self): self.connect_api() # Call whatever API we need to get the running container list - pods = self.core_api.list_pod_for_all_namespaces(watch=False) + all_pods = self.core_api.list_pod_for_all_namespaces(watch=False) + pods = [] + if all_pods.items: + for p in all_pods.items: + if self.cluster_info.app_name in p.metadata.name: + pods.append(p) + + if not pods: + return [] + + ret = [] hostname = "?" ip = "?" tls = "?" @@ -235,23 +245,38 @@ class K8sDeployer(Deployer): except: # noqa: E722 pass - print("Hostname:", hostname) - print("IP:", ip) - print("TLS:", tls) + print("Ingress:") + print("\tHostname:", hostname) + print("\tIP:", ip) + print("\tTLS:", tls) + print("") + print("Pod Status:") + + for i in pods: + if self.cluster_info.app_name in i.metadata.name: + if i.metadata.deletion_timestamp: + print(f"\t{i.metadata.name}: Terminating ({i.metadata.deletion_timestamp})") + else: + print(f"\t{i.metadata.name}: Running ({i.metadata.creation_timestamp})") + pod_ip = i.status.pod_ip + ports = AttrDict() + for c in i.spec.containers: + for p in c.ports: + ports[str(p.container_port)] = [AttrDict({ + "HostIp": pod_ip, + "HostPort": p.container_port + })] + + ret.append(AttrDict({ + "id": i.metadata.name, + "name": i.metadata.name, + "namespace": i.metadata.namespace, + "network_settings": AttrDict({ + "ports": ports + }) + })) print("") - ret = [] - if pods.items: - for i in pods.items: - if self.cluster_info.app_name in i.metadata.name: - ret.append(AttrDict({ - "id": i.metadata.name, - "name": i.metadata.name, - "namespace": i.metadata.namespace, - "network_settings": AttrDict({ - "ports": {} - }) - })) return ret def port(self, service, private_port): -- 2.45.2 From 7715e342622ba1224caf0bacdb88b1bb6e6dc9a9 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 5 Dec 2023 19:09:34 -0600 Subject: [PATCH 3/6] Separate status from ps --- .../deploy/compose/deploy_docker.py | 7 +++ stack_orchestrator/deploy/deploy.py | 8 ++++ stack_orchestrator/deploy/deployer.py | 4 ++ stack_orchestrator/deploy/deployment.py | 5 +- stack_orchestrator/deploy/k8s/deploy_k8s.py | 48 +++++++++++-------- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/stack_orchestrator/deploy/compose/deploy_docker.py b/stack_orchestrator/deploy/compose/deploy_docker.py index 04f24df5..d34d1e6f 100644 --- a/stack_orchestrator/deploy/compose/deploy_docker.py +++ b/stack_orchestrator/deploy/compose/deploy_docker.py @@ -40,6 +40,13 @@ class DockerDeployer(Deployer): except DockerException as e: raise DeployerException(e) + def status(self): + try: + for p in self.docker.compose.ps(): + print(f"{p.name}\t{p.state.status}") + except DockerException as e: + raise DeployerException(e) + def ps(self): try: return self.docker.compose.ps() diff --git a/stack_orchestrator/deploy/deploy.py b/stack_orchestrator/deploy/deploy.py index 424d112f..1b9e6fe1 100644 --- a/stack_orchestrator/deploy/deploy.py +++ b/stack_orchestrator/deploy/deploy.py @@ -107,6 +107,14 @@ def down_operation(ctx, delete_volumes, extra_args_list): ctx.obj.deployer.down(timeout=timeout_arg, volumes=delete_volumes) +def status_operation(ctx): + global_context = ctx.parent.parent.obj + if not global_context.dry_run: + if global_context.verbose: + print("Running compose status") + ctx.obj.deployer.status() + + def ps_operation(ctx): global_context = ctx.parent.parent.obj if not global_context.dry_run: diff --git a/stack_orchestrator/deploy/deployer.py b/stack_orchestrator/deploy/deployer.py index 984945ed..2806044b 100644 --- a/stack_orchestrator/deploy/deployer.py +++ b/stack_orchestrator/deploy/deployer.py @@ -31,6 +31,10 @@ class Deployer(ABC): def ps(self): pass + @abstractmethod + def status(self): + pass + @abstractmethod def port(self, service, private_port): pass diff --git a/stack_orchestrator/deploy/deployment.py b/stack_orchestrator/deploy/deployment.py index 8d74a62d..7b73ae6a 100644 --- a/stack_orchestrator/deploy/deployment.py +++ b/stack_orchestrator/deploy/deployment.py @@ -18,7 +18,7 @@ from pathlib import Path import sys from stack_orchestrator import constants from stack_orchestrator.deploy.images import push_images_operation -from stack_orchestrator.deploy.deploy import up_operation, down_operation, ps_operation, port_operation +from stack_orchestrator.deploy.deploy import up_operation, down_operation, ps_operation, port_operation, status_operation from stack_orchestrator.deploy.deploy import exec_operation, logs_operation, create_deploy_context from stack_orchestrator.deploy.deploy_types import DeployCommandContext from stack_orchestrator.deploy.deployment_context import DeploymentContext @@ -147,4 +147,5 @@ def logs(ctx, tail, follow, extra_args): @command.command() @click.pass_context def status(ctx): - print(f"Context: {ctx.parent.obj}") + ctx.obj = make_deploy_context(ctx) + status_operation(ctx) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 899bd121..9cc2f4e6 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -209,7 +209,7 @@ class K8sDeployer(Deployer): # Destroy the kind cluster destroy_cluster(self.kind_cluster_name) - def ps(self): + def status(self): self.connect_api() # Call whatever API we need to get the running container list all_pods = self.core_api.list_pod_for_all_namespaces(watch=False) @@ -221,9 +221,8 @@ class K8sDeployer(Deployer): pods.append(p) if not pods: - return [] + return - ret = [] hostname = "?" ip = "?" tls = "?" @@ -250,32 +249,41 @@ class K8sDeployer(Deployer): print("\tIP:", ip) print("\tTLS:", tls) print("") - print("Pod Status:") + print("Pods:") for i in pods: - if self.cluster_info.app_name in i.metadata.name: - if i.metadata.deletion_timestamp: - print(f"\t{i.metadata.name}: Terminating ({i.metadata.deletion_timestamp})") - else: - print(f"\t{i.metadata.name}: Running ({i.metadata.creation_timestamp})") - pod_ip = i.status.pod_ip + if i.metadata.deletion_timestamp: + print(f"\t{i.metadata.name}: Terminating ({i.metadata.deletion_timestamp})") + else: + print(f"\t{i.metadata.name}: Running ({i.metadata.creation_timestamp})") + print("") + + def ps(self): + self.connect_api() + pods = self.core_api.list_pod_for_all_namespaces(watch=False) + + ret = [] + + for p in pods.items: + if self.cluster_info.app_name in p.metadata.name: + pod_ip = p.status.pod_ip ports = AttrDict() - for c in i.spec.containers: - for p in c.ports: - ports[str(p.container_port)] = [AttrDict({ - "HostIp": pod_ip, - "HostPort": p.container_port - })] + for c in p.spec.containers: + if c.ports: + for prt in c.ports: + ports[str(prt.container_port)] = [AttrDict({ + "HostIp": pod_ip, + "HostPort": prt.container_port + })] ret.append(AttrDict({ - "id": i.metadata.name, - "name": i.metadata.name, - "namespace": i.metadata.namespace, + "id": p.metadata.name, + "name": p.metadata.name, + "namespace": p.metadata.namespace, "network_settings": AttrDict({ "ports": ports }) })) - print("") return ret -- 2.45.2 From 3f233fd32cac9d02eaf042107ca62ad3d39bc584 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 5 Dec 2023 19:10:58 -0600 Subject: [PATCH 4/6] remove line --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 9cc2f4e6..537e137a 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -256,7 +256,6 @@ class K8sDeployer(Deployer): print(f"\t{i.metadata.name}: Terminating ({i.metadata.deletion_timestamp})") else: print(f"\t{i.metadata.name}: Running ({i.metadata.creation_timestamp})") - print("") def ps(self): self.connect_api() -- 2.45.2 From 5a05b44e3749d2511146606ec197d44a54aecc26 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 5 Dec 2023 19:15:11 -0600 Subject: [PATCH 5/6] Tweak output --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 537e137a..8b47355e 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -276,7 +276,7 @@ class K8sDeployer(Deployer): })] ret.append(AttrDict({ - "id": p.metadata.name, + "id": f"{self.k8s_namespace}/{p.metadata.name}", "name": p.metadata.name, "namespace": p.metadata.namespace, "network_settings": AttrDict({ -- 2.45.2 From 15168bace93509edb63e746fcca1139c8b6c801f Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 5 Dec 2023 19:18:44 -0600 Subject: [PATCH 6/6] Minor reformattin --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 8b47355e..95131966 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -251,11 +251,11 @@ class K8sDeployer(Deployer): print("") print("Pods:") - for i in pods: - if i.metadata.deletion_timestamp: - print(f"\t{i.metadata.name}: Terminating ({i.metadata.deletion_timestamp})") + for p in pods: + if p.metadata.deletion_timestamp: + print(f"\t{p.metadata.namespace}/{p.metadata.name}: Terminating ({p.metadata.deletion_timestamp})") else: - print(f"\t{i.metadata.name}: Running ({i.metadata.creation_timestamp})") + print(f"\t{p.metadata.namespace}/{p.metadata.name}: Running ({p.metadata.creation_timestamp})") def ps(self): self.connect_api() @@ -276,7 +276,7 @@ class K8sDeployer(Deployer): })] ret.append(AttrDict({ - "id": f"{self.k8s_namespace}/{p.metadata.name}", + "id": f"{p.metadata.namespace}/{p.metadata.name}", "name": p.metadata.name, "namespace": p.metadata.namespace, "network_settings": AttrDict({ -- 2.45.2