import subprocess
import yaml

from cache import ExpiringCache

class KubernetesClient(object):
    def __init__(self):
        self._cache = ExpiringCache(30)

    def _run_command(self, cmd):
        return subprocess.check_output(' '.join(['kubectl'] + cmd), shell=True)

    def _run_command_and_parse_yaml(self, cmd):
        return yaml.load(self._run_command(cmd))

    def _namespace(self, ns):
        return ['--namespace', ns] if ns != 'all' else ['--all-namespaces']

    def _load_from_cache_or_do(self, key, func):
        cached = self._cache.get(key)
        if cached is not None:
            return cached
        result = func()
        self._cache.set(key, result)
        return result
        
    def get_namespaces(self):
        return self._load_from_cache_or_do("namespaces", self._get_namespaces)

    def _get_namespaces(self):
        payload = self._run_command_and_parse_yaml('get ns -o yaml'.split())
        if payload is None or 'items' not in payload:
            return []
        return [ item['metadata']['name'] for item in payload['items']]

    def get_pods(self, ns='default'):
        return self.get_entities(ns, 'pod')
    def get_services(self, ns='default'):
        return self.get_entities(ns, 'svc')
    def get_replication_controllers(self, ns='default'):
        return self.get_entities(ns, 'rc')

    def get_entities(self, ns, entity):
        return self._load_from_cache_or_do(ns + "-" + entity, 
                lambda: self._get_entities(ns,entity))

    def _get_entities(self, ns, entity):
        payload = self._run_command_and_parse_yaml(['get', entity, '-o', 'yaml'] + self._namespace(ns))
        if payload is None or 'items' not in payload:
            return []
        return [ item['metadata']['name'] for item in payload['items']]

    def get_object_in_format(self, ns, entity_type, object, format):
        return self._run_command(['get', entity_type, object, '-o', format] + self._namespace(ns))

    def describe(self, ns, entity_type, object):
        return self._run_command(['describe', entity_type, object] + self._namespace(ns))

    def logs(self, ns, object):
        return self._run_command(['logs', object] + self._namespace(ns))


@@ -751,77 +751,292 @@
     
-return self._load_from_cache_or_do(%22namespaces%22, self._get_namespaces
+key = %22namespaces%22%0A        cb = self._get_namespaces%0A        return self._load_from_cache_or_do(key, cb)%0A%0A    def get_entities(self, ns, entity):%0A        key = %22%25s.%25s%22 %25 (ns, entity)%0A        cb = lambda: self._get_entities(ns,entity)%0A        return self._load_from_cache_or_do(key, cb
 )%0A%0A 
@@ -1046,255 +1046,665 @@
 def 
-_
 get_
-namespaces(self):%0A        payload = self._run_command_and_parse_yaml('get ns -o yaml'.split())%0A        if payload is None or 'items' not in payload:%0A            return %5B%5D%0A        return %5B item%5B'metadata'%5D%5B'name'%5D for item in payload%5B'items'%5D%5D
+object_in_format(self, ns, entity_type, object, format):%0A        key = %22%25s.%25s.%25s.%25s%22 %25 (ns, entity_type, object, format)%0A        cb = lambda: self._get_object_in_format(ns, entity_type, object, format)%0A        return self._load_from_cache_or_do(key, cb)%0A%0A    def describe(self, ns, entity_type, object):%0A        key = %22%25s.%25s.%25s.describe%22 %25 (ns, entity_type, object)%0A        cb = lambda: self._describe(ns, entity_type, object)%0A        return self._load_from_cache_or_do(key, cb)%0A%0A    def logs(self, ns, object):%0A        key = %22%25s.pod.%25s.logs%22 %25 (ns, object)%0A        cb = lambda: self._logs(ns, object)%0A        return self._load_from_cache_or_do(key, cb)
 %0A%0A  
@@ -1970,24 +1970,25 @@
  'rc')%0A%0A
+%0A
     def 
 get_enti
@@ -1983,157 +1983,255 @@
 def 
+_
 get_
-entities(self, ns, entity):%0A        return self._load_from_cache_or_do(ns + %22-%22 + entity, %0A                lambda: self._get_entities(ns,entity))
+namespaces(self):%0A        payload = self._run_command_and_parse_yaml('get ns -o yaml'.split())%0A        if payload is None or 'items' not in payload:%0A            return %5B%5D%0A        return %5B item%5B'metadata'%5D%5B'name'%5D for item in payload%5B'items'%5D%5D
 %0A%0A  
@@ -2522,32 +2522,33 @@
 ems'%5D%5D%0A%0A    def 
+_
 get_object_in_fo
@@ -2692,32 +2692,33 @@
 e(ns))%0A%0A    def 
+_
 describe(self, n
@@ -2833,32 +2833,33 @@
 e(ns))%0A%0A    def 
+_
 logs(self, ns, o

add caching to describe, logs, json and yaml files