Пример #1
0
    def create_missing_in_cluster(cls):
        """
        Scans the portal database for service accounts that have no representation
        in the Kubernetes cluster, and creates the latter accordingly.
        """
        try:
            # Create a list of cluster service account UIDs that already exist
            k8s_svca_uid_list = [
                k8s_svca.metadata.uid
                for k8s_svca in api.get_service_accounts()
            ]

            # Scan portal service account entries
            for portal_svca in cls.objects.all():
                if portal_svca.uid:
                    # Portal records with UID must be given in K8S, or they are stale und should be deleted
                    if portal_svca.uid not in k8s_svca_uid_list:
                        logger.warning(
                            f"Removing stale service account record '{portal_svca.namespace.name}:{portal_svca.name}'"
                        )
                        portal_svca.delete()
                else:
                    # Portal records without UID are new and should be created in K8S
                    logger.debug(
                        f"Service account record '{portal_svca.namespace.name}:{portal_svca.name}' has no UID, creating it in the cluster ..."
                    )
                    portal_svca.create_in_cluster()
            return True
        except Exception as e:
            logger.exception(
                f"Syncing new portal namespaces into the cluster failed.")
            return False
Пример #2
0
 def create_missing_in_portal(cls):
     """
     Scans the Kubernetes cluster for service accounts that have no representation
     as KubernetesServiceAccount object, and creates the latter accordingly.
     """
     try:
         k8s_svca_list = api.get_service_accounts()
         if k8s_svca_list:
             for k8s_svca in k8s_svca_list:
                 # 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_svca.metadata.name,
                         uid=k8s_svca.metadata.uid).exists():
                     logger.info(
                         f"Found new Kubernetes service account {k8s_svca.metadata.name}, creating record."
                     )
                     ns = KubernetesNamespace.get_or_sync(
                         k8s_svca.metadata.namespace)
                     new_obj = cls(name=k8s_svca.metadata.name,
                                   uid=k8s_svca.metadata.uid,
                                   namespace=ns)
                     new_obj.save()
         return True
     except Exception as e:
         logger.exception(
             f"Syncing new cluster service accounts into the portal failed."
         )
         return False
Пример #3
0
 def test_new_svc_sync(self):
     self._call_sync()
     default_ns = KubernetesNamespace.objects.get(name="default")
     new_svc = KubernetesServiceAccount(name="foobar", namespace=default_ns)
     new_svc.save()
     self._call_sync()
     svc_names = [svc.metadata.name for svc in api.get_service_accounts()]
     self.assertIn("foobar", svc_names)
Пример #4
0
def test_serviceaccount_no_permission(api_client, admin_user_with_k8s_system):
    for item in api.get_service_accounts():
        if item.metadata.namespace == 'default' and item.metadata.name == 'default':
            uid = item.metadata.uid
            response = api_client.get(
                f'/api/{settings.API_VERSION}/serviceaccounts/{uid}/')
            assert response.status_code == 404
            return
    assert False
Пример #5
0
def test_new_svc_sync(random_namespace_name):
    run_minikube_sync()
    ns = KubernetesNamespace(name=random_namespace_name)
    ns.save()
    ns.create_in_cluster()
    new_svc = KubernetesServiceAccount(name="foobar", namespace=ns)
    new_svc.save()
    run_minikube_sync()
    svc_list = api.get_service_accounts()
    for svc in svc_list:
        if svc.metadata.name == "foobar" and svc.metadata.namespace == random_namespace_name:
            return
    assert False
Пример #6
0
def _sync_svcaccounts(request):
    #################################################
    # K8S svc accounts -> portal svc accounts
    #################################################
    success_count_pull = 0
    success_count_push = 0
    ignored_missing_ns = []
    k8s_svca_uids = []

    try:
        k8s_svca_list = api.get_service_accounts()
    except Exception as e:
        error_log(request, e, None, "Sync failed, error while fetching list of service accounts: {}.")
        return

    for k8s_svca in k8s_svca_list:
        try:
            # remember for later use
            '''
            Not finding the namespace record for this namespace name means inconsistency 
            - re-sync is needed anyway, so stopping here is fine
            '''
            k8s_svca_uids.append(k8s_svca.metadata.uid)
            portal_ns = svca_utils.get_portal_ns_using_k8s_ns(k8s_svca, ignored_missing_ns)

            portal_svca, created = KubernetesServiceAccount.objects.get_or_create(
                name=k8s_svca.metadata.name, uid=k8s_svca.metadata.uid, namespace=portal_ns)

            if created:
                svca_utils.add_svca_to_kubeportal(request, k8s_svca, portal_svca)
            else:
                # No action needed
                logger.info("Found existing record for Kubernetes service account '{0}:{1}'".format(
                    k8s_svca.metadata.namespace, k8s_svca.metadata.name))
                success_count_pull += 1
        except Exception as e:
            error_log(request, e, k8s_svca.metadata.name, 'Sync from Kubernetes for service account {} failed: {}."')

    if len(ignored_missing_ns) > 0:
        names = ["{0}:{1}".format(a, b)
                 for a, b in ignored_missing_ns]
        messages.warning(
            request, "Skipping service accounts with non-existent namespaces: {0}".format(names))

    #################################################
    # portal service accounts -> K8S service accounts
    #################################################
    portal_svca_list = KubernetesServiceAccount.objects.all()
    for portal_svca in portal_svca_list:
        try:
            portal_ns = portal_svca.namespace
            if portal_svca.uid:
                # Portal service account records with UID must be given in K8S, or they are
                # stale und should be deleted
                if portal_svca.uid in k8s_svca_uids:
                    # No action needed
                    logger.info(
                        f"Found existing Kubernetes service account for record '{portal_ns.name}:{portal_svca.name}'")
                    success_count_push += 1
                else:
                    # Remove stale record from portal
                    logger.warning(
                        f"Removing stale record for Kubernetes service account '{portal_ns.name}:{portal_svca.name}'")
                    portal_svca.delete()
                    messages.info(request,
                                  f"Service account '{portal_ns.name}:{portal_svca.name}' no longer exists in portal and was removed.")
            else:
                # Portal service accounts without UID are new and should be created in K8S
                svca_utils.add_svca_to_kubernetes(request, portal_svca, portal_ns)
        except Exception as e:
            error_log(request, e, portal_svca.namespace, 'Sync to Kubernetes for service account {} failed: {}.')

    if success_count_push == success_count_pull:
        messages.success(request, "All valid service accounts are in sync.")