def create_missing_in_portal(cls): """ Scans the Kubernetes cluster for namespaces that have no representation as KubernetesNamespace object, and creates the latter accordingly. """ try: k8s_ns_list = api.get_namespaces() if k8s_ns_list: for k8s_ns in k8s_ns_list: k8s_ns_name, k8s_ns_uid = k8s_ns.metadata.name, k8s_ns.metadata.uid # First calling exists(), and creating it in case, is faster than get_or_create() # but may impose an extremely small danger of race conditions. # We trade performance for reliability here. if not cls.objects.filter(name=k8s_ns_name, uid=k8s_ns_uid).exists(): logger.info( f"Found new Kubernetes namespace {k8s_ns_name}, creating record." ) new_obj = cls(name=k8s_ns_name, uid=k8s_ns_uid) if k8s_ns_name in HIDDEN_NAMESPACES: new_obj.visible = False else: new_obj.visible = True new_obj.save() return True except Exception as e: logger.exception( f"Syncing new cluster namespaces into the portal failed.") return False
def create_missing_in_cluster(cls): """ Scans the portal database for namespaces that have no representation in the Kubernetes cluster, and creates the latter accordingly. """ try: # Create a list of cluster namespace UIDs that already exist k8s_ns_uid_list = [ k8s_ns.metadata.uid for k8s_ns in api.get_namespaces() ] # Scan portal namespace entries for portal_ns in cls.objects.all(): if portal_ns.uid: # Portal namespace records with UID must be given in K8S, or they are stale und should be deleted if portal_ns.uid not in k8s_ns_uid_list: logger.warning( f"Removing stale portal record for Kubernetes namespace '{portal_ns.name}'" ) portal_ns.delete() else: # Portal namespace records without UID are new and should be created in K8S logger.debug( f"Namespace record {portal_ns.name} has no UID, creating it in Kubernetes ..." ) portal_ns.create_in_cluster( ) # ignore success, continue sync in any case return True except Exception as e: logger.exception( f"Syncing new portal namespaces into the cluster failed.") return False
def test_new_ns_sync(random_namespace_name): run_minikube_sync() new_ns = KubernetesNamespace(name=random_namespace_name) new_ns.save() run_minikube_sync() ns_names = [ns.metadata.name for ns in api.get_namespaces()] assert random_namespace_name in ns_names
def test_new_ns_broken_name_sync(self): test_cases = {"foo_bar": "foobar", "ABCDEF": "abcdef"} for old, new in test_cases.items(): new_ns = KubernetesNamespace(name=old) new_ns.save() self._call_sync() ns_names = [ns.metadata.name for ns in api.get_namespaces()] self.assertNotIn(old, ns_names) self.assertIn(new, ns_names)
def test_new_ns_broken_name_sync(): run_minikube_sync() test_cases = {"foo_bar": "foobar", "ABCDEF": "abcdef"} for old, new in test_cases.items(): new_ns = KubernetesNamespace(name=old) new_ns.save() run_minikube_sync() ns_names = [ns.metadata.name for ns in api.get_namespaces()] assert old not in ns_names assert new in ns_names api.delete_k8s_ns(new)
def _sync_namespaces(request): ################################################# # K8S namespaces -> portal namespaces ################################################# success_count_push = 0 success_count_pull = 0 try: k8s_ns_list = api.get_namespaces() except Exception as e: error_log(request, e, None, 'Sync failed, error while fetching list of namespaces: {e}') return for k8s_ns in k8s_ns_list: try: k8s_ns_name, k8s_ns_uid = k8s_ns.metadata.name, k8s_ns.metadata.uid # remember for later use k8s_ns_uids.append(k8s_ns_uid) portal_ns, created = KubernetesNamespace.objects.get_or_create(name=k8s_ns_name, uid=k8s_ns_uid) if created: ns_utils.add_namespace_to_kubeportal(k8s_ns_name, portal_ns, request) else: # No action needed logger.debug(f"Found existing record for Kubernetes namespace '{k8s_ns_name}'") success_count_pull += 1 except Exception as e: error_log(request, e, k8s_ns.metadata.name, 'Sync from Kubernetes for namespace {} failed: {}.') ################################################# # portal namespaces -> K8S namespaces ################################################# portal_ns_list = KubernetesNamespace.objects.all() for portal_ns in portal_ns_list: try: if portal_ns.uid: ns_utils.check_if_portal_ns_exists_in_k8s(request, portal_ns, k8s_ns_uids, success_count_push) else: # Portal namespaces without UID are new and should be created in K8S ns_utils.add_namespace_to_kubernetes(portal_ns, request, api) except Exception as e: error_log(request, e, portal_ns, 'Sync to Kubernetes for namespace {} failed: {}."') if success_count_push == success_count_pull: messages.success(request, "All valid namespaces are in sync.") ns_utils.check_role_bindings_of_namespaces(request)
def test_new_ns_sync(self): new_ns = KubernetesNamespace(name="foo") new_ns.save() self._call_sync() ns_names = [ns.metadata.name for ns in api.get_namespaces()] self.assertIn("foo", ns_names)