diff --git a/django_kubernetes_manager/models/base.py b/django_kubernetes_manager/models/base.py index 17ad8ef..ecfac0b 100644 --- a/django_kubernetes_manager/models/base.py +++ b/django_kubernetes_manager/models/base.py @@ -40,9 +40,13 @@ class KubernetesTelemetryMixin(models.Model): average_mem_usage, cpu_usage_seconds, mem_usage_seconds """ object_status = models.CharField(max_length=128, null=True, blank=True) - average_cpu_usage = models.DecimalField(null=True, blank=True, max_digits=8, decimal_places=4) + average_cpu_usage = models.DecimalField(null=True, blank=True, max_digits=8, + decimal_places=4 + ) average_mem_usage = models.IntegerField(null=True, blank=True) - cpu_usage_seconds = models.DecimalField(null=True, blank=True, max_digits=8, decimal_places=4) + cpu_usage_seconds = models.DecimalField(null=True, blank=True, max_digits=8, + decimal_places=4 + ) mem_usage_seconds = models.IntegerField(null=True, blank=True) class Meta: @@ -62,8 +66,11 @@ def read_pod_metrics(self): api_instance = self.get_client(API=client.CustomObjectsApi) pod_name = self.slug pod_namespace = self.namespace - items = api_instance.list_cluster_custom_object('metrics.k8s.io', 'v1beta1', 'pods').get("items", []) - return [pod for pod in items if pod_name in pod.get("metadata", {}).get("name") and pod_namespace in pod.get("metadata", {}).get("namespace")] + items = api_instance.list_cluster_custom_object('metrics.k8s.io', + 'v1beta1', 'pods').get("items", []) + return [pod for pod in items if pod_name in pod.get("metadata", {} + ).get("name") and pod_namespace in pod.get("metadata", {} + ).get("namespace")] def read_pod_usage(self): pod_name = self.pod_template.slug @@ -98,7 +105,9 @@ def status(self): class KubernetesBase(TitleSlugDescriptionModel): id = models.UUIDField(default=uuid4, editable=False, primary_key=True) - cluster = models.ForeignKey('TargetCluster', on_delete=models.SET_NULL, null=True) + cluster = models.ForeignKey('TargetCluster', on_delete=models.SET_NULL, + null=True + ) config = JSONField(default=dict, null=True, blank=True) deployed = models.DateTimeField(null=True, blank=True) deleted = models.DateTimeField(null=True, blank=True) @@ -111,7 +120,7 @@ def slugify_function(self, content): return self.title.replace("_", "-").replace(" ", "-").lower() def get_client(self, API=client.CoreV1Api, **kwargs): - """Gets a k8s api client based on the credential associated with this instance + """Gets a k8s api client Args: API (client.) - Kubernetes Client Type @@ -129,7 +138,9 @@ def get_client(self, API=client.CoreV1Api, **kwargs): cc = self.cluster.config with open(ntf.name, "w") as f: f.write(cc) - return API(api_client=config.new_client_from_config(config_file=ntf.name)) + return API(api_client=config.new_client_from_config( + config_file=ntf.name) + ) @@ -147,7 +158,9 @@ class KubernetesNetworkingBase(KubernetesMetadataObjBase): kind = models.CharField(max_length=16) port = models.IntegerField(default=80) namespace = models.CharField(max_length=64, default="default") - kuid = models.CharField(max_length=48, null=True, blank=True, help_text="Object's UID in the cluster") + kuid = models.CharField(max_length=48, null=True, blank=True, + help_text="Object's UID in the cluster" + ) class Meta: abstract= True @@ -210,7 +223,9 @@ def get_obj(self): class KubernetesVolumeMount(KubernetesBase): mount_path = models.CharField(max_length=255, default="/media") - sub_path = models.CharField(max_length=255, default=None, null=True, blank=True) + sub_path = models.CharField(max_length=255, default=None, null=True, + blank=True + ) def get_obj(self): return client.V1VolumeMount( @@ -225,7 +240,9 @@ class KubernetesConfigMap(KubernetesMetadataObjBase): kind = models.CharField(max_length=16, default="ConfigMap") data = JSONField(default=dict, null=True, blank=True) binary = models.BinaryField(null=True, blank=True) - override_name = models.CharField(max_length=32, null=True, blank=True, default="ConfigMap") + override_name = models.CharField(max_length=32, null=True, blank=True, + default="ConfigMap" + ) namespace = models.CharField(max_length=64, default="default") def get_obj(self): @@ -237,7 +254,9 @@ def get_obj(self): ), kind = self.kind, data = self.data if self.data else None, - binary_data = {str(self.override_name): self.binary} if self.binary else None + binary_data = { + str(self.override_name): self.binary + } if self.binary else None ) def deploy(self): @@ -264,13 +283,26 @@ def k_delete(self): class KubernetesContainer(KubernetesBase): - image_name = models.CharField(max_length=200, db_index=True, help_text="Properly qualified image name to execute this job within", default="debian") - image_tag = models.CharField(max_length=100, db_index=True, help_text="Tag name for the image to be used for this job", default="latest") - image_pull_policy = models.CharField(max_length=16, choices=PULL_POLICY, default='IfNotPresent') - command = models.TextField(help_text="Command to run when instantiating container", null=True, blank=True) - args = models.TextField(help_text="Comma separated args to run with command when instantiating container.", null=True, blank=True) + image_name = models.CharField(max_length=200, db_index=True, + help_text="Properly qualified image name to execute this job within", + default="debian" + ) + image_tag = models.CharField(max_length=100, db_index=True, + help_text="Tag name for the image to be used for this job", + default="latest" + ) + image_pull_policy = models.CharField(max_length=16, choices=PULL_POLICY, + default='IfNotPresent' + ) + command = models.TextField(help_text="Command to run when start container", + null=True, blank=True + ) + args = models.TextField(help_text="Comma separated args to run with command\ + when instantiating container.", null=True, blank=True + ) port = models.IntegerField(default=80) - volume_mount = models.ForeignKey('KubernetesVolumeMount', null=True, blank=True, on_delete=models.SET_NULL) + volume_mount = models.ForeignKey('KubernetesVolumeMount', null=True, + blank=True, on_delete=models.SET_NULL) def get_obj(self): return client.V1Container( @@ -288,10 +320,19 @@ def get_obj(self): class KubernetesPodTemplate(KubernetesMetadataObjBase): - volume = models.ForeignKey('KubernetesVolume', null=True, blank=True, on_delete=models.SET_NULL) - primary_container = models.ForeignKey('KubernetesContainer', on_delete=models.CASCADE, related_name='primary_container') - secondary_container = models.ForeignKey('KubernetesContainer', null=True, blank=True, on_delete=models.SET_NULL, related_name='secondary_container') - restart_policy = models.CharField(max_length=16, choices=RESTART_POLICY, default='Never') + volume = models.ForeignKey('KubernetesVolume', null=True, blank=True, + on_delete=models.SET_NULL + ) + primary_container = models.ForeignKey('KubernetesContainer', + on_delete=models.CASCADE, related_name='primary_container' + ) + secondary_container = models.ForeignKey('KubernetesContainer', null=True, + blank=True, on_delete=models.SET_NULL, + related_name='secondary_container' + ) + restart_policy = models.CharField(max_length=16, choices=RESTART_POLICY, + default='Never' + ) def get_obj(self): return client.V1PodTemplateSpec( @@ -307,7 +348,9 @@ def get_obj(self): containers=[ self.primary_container.get_obj(), self.secondary_container.get_obj() - ] if self.secondary_container is not None else [self.primary_container.get_obj()], + ] if self.secondary_container is not None else [ + self.primary_container.get_obj() + ], restart_policy = self.restart_policy ) ) @@ -317,7 +360,9 @@ def get_obj(self): class KubernetesDeployment(KubernetesNetworkingBase, KubernetesTelemetryMixin): selector = JSONField(default=dict) replicas = models.IntegerField(default=1) - pod_template = models.ForeignKey('KubernetesPodTemplate', on_delete=models.CASCADE) + pod_template = models.ForeignKey('KubernetesPodTemplate', + on_delete=models.CASCADE + ) def get_obj(self): return client.V1Deployment( @@ -369,7 +414,9 @@ def k_delete(self): class KubernetesJob(KubernetesNetworkingBase, KubernetesTelemetryMixin): - pod_template = models.ForeignKey('KubernetesPodTemplate', on_delete=models.CASCADE) + pod_template = models.ForeignKey('KubernetesPodTemplate', + on_delete=models.CASCADE + ) backoff_limit = models.IntegerField(default=3) def get_obj(self): @@ -459,7 +506,9 @@ def k_delete(self): class KubernetesIngress(KubernetesNetworkingBase): hostname = models.CharField(max_length=255, default="localhost") path = models.CharField(max_length=255, default="/") - target_service = models.ForeignKey('KubernetesService', on_delete=models.CASCADE) + target_service = models.ForeignKey('KubernetesService', + on_delete=models.CASCADE + ) def get_obj(self): return client.NetworkingV1beta1Ingress( diff --git a/django_kubernetes_manager/models/target_cluster.py b/django_kubernetes_manager/models/target_cluster.py index 73ffc72..30baaab 100644 --- a/django_kubernetes_manager/models/target_cluster.py +++ b/django_kubernetes_manager/models/target_cluster.py @@ -20,8 +20,12 @@ class TargetCluster(TitleSlugDescriptionModel): api_endpoint = models.URLField(help_text="Cluster Endpoint URL") telemetry_endpoint = models.URLField(help_text="Telemetry Endpoint URL") - telemetry_source = models.CharField(max_length=5, default="p", choices=TELEMETRY_SOURCE) - config = JSONField(help_text="Configuration data stored as an encrypted blob in the database", null=True) + telemetry_source = models.CharField(max_length=5, default="p", + choices=TELEMETRY_SOURCE + ) + config = JSONField(help_text="Configuration data stored as an encrypted\ + blob in the database", null=True + ) @classmethod def add(cls, kubeconfig): @@ -38,22 +42,33 @@ def add(cls, kubeconfig): config_data = yaml.load(kubeconfig, Loader=yaml.FullLoader) ret_val = [] for item in config_data.get("clusters", []): - cluster, created = TargetCluster.objects.get_or_create(title=item.get("name"), api_endpoint=item.get("cluster", {}).get("server")) + cluster, created = TargetCluster.objects.get_or_create( + title=item.get("name"), + api_endpoint=item.get("cluster", {}).get("server") + ) if created: ret_val.append(cluster) cluster.config = str(json.dumps(config_data)) cluster.save() for config_obj in split_kubeconfig(kubeconfig): cluster, created = TargetCluster.objects.get_or_create( - title=config_obj.get("clusters", [])[0].get("name"), api_endpoint=config_obj.get("clusters", [])[0].get("cluster", {}).get("server") + title=config_obj.get("clusters", [])[0].get("name"), + api_endpoint=config_obj.get("clusters", [])[0].get( + "cluster", {}).get("server") ) ret_val.append(cluster) if created: cluster.config = config_data cluster.save() - log.info("Created new cluster record for {} @ {}".format(cluster.title, cluster.api_endpoint)) + log.info("Created new cluster record for {} @ {}".format( + cluster.title, cluster.api_endpoint) + ) else: - log.warning("Cluster record for {} @ {} already existed - TargetCluster not added".format(cluster.title, cluster.api_endpoint)) + log.warning("Cluster record for {} @ {} already existed - \ + TargetCluster not added".format( + cluster.title, cluster.api_endpoint + ) + ) if ret_val: log.info("Added {} clusters".format(len(ret_val))) else: diff --git a/django_kubernetes_manager/utils.py b/django_kubernetes_manager/utils.py index fb4ec7d..d530b8e 100644 --- a/django_kubernetes_manager/utils.py +++ b/django_kubernetes_manager/utils.py @@ -10,7 +10,9 @@ import re def get_dict_hash(data): - return hashlib.md5(json.dumps({k: data[k] for k in sorted(data.keys())}).encode("utf-8")).hexdigest() + return hashlib.md5( + json.dumps({k: data[k] for k in sorted(data.keys())}).encode("utf-8") + ).hexdigest() log = logging.getLogger(__name__) @@ -30,7 +32,9 @@ def run_command(cmd, log_method=log.info): if not line and ret_val != None: break log_method(line.decode()) - log_method("Completed run_command in {} for: {}".format((datetime.utcnow() - start).total_seconds(), " ".join(cmd))) + log_method("Completed run_command in {} for: {}".format( + (datetime.utcnow() - start).total_seconds(), " ".join(cmd)) + ) return ret_val @@ -100,8 +104,15 @@ def split_kubeconfig(kubeconfig): kubeconfig = yaml.load(kubeconfig, Loader=yaml.FullLoader) ret_val = [] for context in kubeconfig.get("contexts", []): - cluster = [x for x in kubeconfig.get("clusters", []) if x.get("name") == context.get("context", {}).get("cluster", "")][0] - user = [x for x in kubeconfig.get("users", []) if x.get("name") == context.get("context", {}).get("user", "")][0] + cluster = [ + x for x in kubeconfig.get("clusters", []) if x.get( + "name" + ) == context.get("context", {}).get("cluster", "") + ][0] + user = [x for x in kubeconfig.get("users", []) if x.get( + "name" + ) == context.get("context", {}).get("user", "") + ][0] if cluster and user: ret_val.append(generate_kubeconfig(context, cluster, user)) return ret_val