Skip to content

Commit

Permalink
Merge pull request #128 from minrk/share-apiclient
Browse files Browse the repository at this point in the history
share kubernetes client instances
  • Loading branch information
betatim committed Feb 23, 2018
2 parents f3a2637 + 3c2c517 commit f7ebb59
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 9 deletions.
29 changes: 29 additions & 0 deletions kubespawner/clients.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import weakref

import kubernetes.client

_client_cache = {}


def shared_client(ClientType, *args, **kwargs):
"""Return a single shared kubernetes client instance
A weak reference to the instance is cached,
so that concurrent calls to shared_client
will all return the same instance until
all references to the client are cleared.
"""
kwarg_key = tuple((key, kwargs[key]) for key in sorted(kwargs))
cache_key = (ClientType, args, kwarg_key)
client = None
if cache_key in _client_cache:
# resolve cached weakref
# client can still be None after this!
client = _client_cache[cache_key]()

if client is None:
Client = getattr(kubernetes.client, ClientType)
client = Client(*args, **kwargs)
# cache weakref so that clients can be garbage collected
_client_cache[cache_key] = weakref.ref(client)
return client
7 changes: 4 additions & 3 deletions kubespawner/proxy.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from concurrent.futures import ThreadPoolExecutor
import os
import string
import escapism
Expand All @@ -10,7 +11,7 @@
from kubespawner.objects import make_ingress
from kubespawner.utils import generate_hashed_slug
from kubespawner.reflector import NamespacedResourceReflector
from concurrent.futures import ThreadPoolExecutor
from .clients import shared_client
from traitlets import Unicode
from tornado import gen
from tornado.concurrent import run_on_executor
Expand Down Expand Up @@ -96,8 +97,8 @@ def __init__(self, *args, **kwargs):
self.service_reflector = ServiceReflector(parent=self, namespace=self.namespace)
self.endpoint_reflector = EndpointsReflector(parent=self, namespace=self.namespace)

self.core_api = client.CoreV1Api()
self.extension_api = client.ExtensionsV1beta1Api()
self.core_api = shared_client('CoreV1Api')
self.extension_api = shared_client('ExtensionsV1beta1Api')

@run_on_executor
def asynchronize(self, method, *args, **kwargs):
Expand Down
7 changes: 2 additions & 5 deletions kubespawner/spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@
"""
import os
import json
import time
import string
import threading
import sys
from urllib.parse import urlparse, urlunparse
import json
import multiprocessing
from concurrent.futures import ThreadPoolExecutor

Expand All @@ -26,6 +22,7 @@
from kubernetes import client
import escapism

from .clients import shared_client
from kubespawner.traitlets import Callable
from kubespawner.utils import Callable
from kubespawner.objects import make_pod, make_pvc
Expand Down Expand Up @@ -80,7 +77,7 @@ def on_reflector_failure():
on_failure=on_reflector_failure
)

self.api = client.CoreV1Api()
self.api = shared_client('CoreV1Api')

self.pod_name = self._expand_user_properties(self.pod_name_template)
self.pvc_name = self._expand_user_properties(self.pvc_name_template)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
install_requires=[
'jupyterhub>=0.8',
'pyYAML',
'kubernetes==3.*',
'kubernetes==4.*',
'escapism',
],
setup_requires=['pytest-runner'],
Expand Down

0 comments on commit f7ebb59

Please sign in to comment.