Skip to content

Commit 1308f26

Browse files
author
Prasanna Santhanam
committed
wip #26: prevent kube-shell from failing on client-python errors
1 parent b9fce5c commit 1308f26

File tree

2 files changed

+118
-102
lines changed

2 files changed

+118
-102
lines changed

kubeshell/client.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from kubernetes import client, config
2+
from kubernetes.client.api_client import ApiException
3+
4+
5+
class KubernetesClient(object):
6+
7+
def __init__(self):
8+
try:
9+
config.load_kube_config()
10+
except Exception as e:
11+
# TODO: log errors to log file
12+
raise(e)
13+
14+
self.v1 = client.CoreV1Api()
15+
self.v1Beta1 = client.AppsV1beta1Api()
16+
self.extensionsV1Beta1 = client.ExtensionsV1beta1Api()
17+
self.autoscalingV1Api = client.AutoscalingV1Api()
18+
self.rbacAPi = client.RbacAuthorizationV1beta1Api()
19+
self.batchV1Api = client.BatchV1Api()
20+
self.batchV2Api = client.BatchV2alpha1Api()
21+
22+
23+
def get_resource(self, resource, namespace="all"):
24+
resources = []
25+
try:
26+
ret, namespaced_resource = self._call_api_client(resource)
27+
except ApiException as ae:
28+
# TODO: log warning
29+
pass
30+
if ret:
31+
for i in ret.items:
32+
if namespace == "all" or not namespaced_resource:
33+
resources.append((i.metadata.name, i.metadata.namespace))
34+
elif namespace == i.metadata.namespace:
35+
resources.append((i.metadata.name, i.metadata.namespace))
36+
return resources
37+
return None
38+
39+
def _call_api_client(self, resource):
40+
namespaced_resource = True
41+
42+
if resource == "pod":
43+
ret = self.v1.list_pod_for_all_namespaces(watch=False)
44+
elif resource == "service":
45+
ret = self.v1.list_service_for_all_namespaces(watch=False)
46+
elif resource == "deployment":
47+
ret = self.v1Beta1.list_deployment_for_all_namespaces(watch=False)
48+
elif resource == "statefulset":
49+
ret = self.v1Beta1.list_stateful_set_for_all_namespaces(watch=False)
50+
elif resource == "node":
51+
namespaced_resource = False
52+
ret = self.v1.list_node(watch=False)
53+
elif resource == "namespace":
54+
namespaced_resource = False
55+
ret = self.v1.list_namespace(watch=False)
56+
elif resource == "daemonset":
57+
ret = self.extensionsV1Beta1.list_daemon_set_for_all_namespaces(watch=False)
58+
elif resource == "networkpolicy":
59+
ret = self.extensionsV1Beta1.list_network_policy_for_all_namespaces(watch=False)
60+
elif resource == "thirdpartyresource":
61+
namespaced_resource = False
62+
ret = self.extensionsV1Beta1.list_third_party_resource(watch=False)
63+
elif resource == "replicationcontroller":
64+
ret = self.v1.list_replication_controller_for_all_namespaces(watch=False)
65+
elif resource == "replicaset":
66+
ret = self.extensionsV1Beta1.list_replica_set_for_all_namespaces(watch=False)
67+
elif resource == "ingress":
68+
ret = self.extensionsV1Beta1.list_ingress_for_all_namespaces(watch=False)
69+
elif resource == "endpoints":
70+
ret = self.v1.list_endpoints_for_all_namespaces(watch=False)
71+
elif resource == "configmap":
72+
ret = self.v1.list_config_map_for_all_namespaces(watch=False)
73+
elif resource == "event":
74+
ret = self.v1.list_event_for_all_namespaces(watch=False)
75+
elif resource == "limitrange":
76+
ret = self.v1.list_limit_range_for_all_namespaces(watch=False)
77+
elif resource == "configmap":
78+
ret = self.v1.list_config_map_for_all_namespaces(watch=False)
79+
elif resource == "persistentvolume":
80+
namespaced_resource = False
81+
ret = self.v1.list_persistent_volume(watch=False)
82+
elif resource == "secret":
83+
ret = self.v1.list_secret_for_all_namespaces(watch=False)
84+
elif resource == "resourcequota":
85+
ret = self.v1.list_resource_quota_for_all_namespaces(watch=False)
86+
elif resource == "componentstatus":
87+
namespaced_resource = False
88+
ret = self.v1.list_component_status(watch=False)
89+
elif resource == "podtemplate":
90+
ret = self.v1.list_pod_template_for_all_namespaces(watch=False)
91+
elif resource == "serviceaccount":
92+
ret = self.v1.list_service_account_for_all_namespaces(watch=False)
93+
elif resource == "horizontalpodautoscaler":
94+
ret = self.autoscalingV1Api.list_horizontal_pod_autoscaler_for_all_namespaces(watch=False)
95+
elif resource == "clusterrole":
96+
namespaced_resource = False
97+
ret = self.rbacAPi.list_cluster_role(watch=False)
98+
elif resource == "clusterrolebinding":
99+
namespaced_resource = False
100+
ret = self.rbacAPi.list_cluster_role_binding(watch=False)
101+
elif resource == "job":
102+
ret = self.batchV1Api.list_job_for_all_namespaces(watch=False)
103+
elif resource == "cronjob":
104+
ret = self.batchV2Api.list_cron_job_for_all_namespaces(watch=False)
105+
elif resource == "scheduledjob":
106+
ret = self.batchV2Api.list_scheduled_job_for_all_namespaces(watch=False)
107+
else:
108+
return None, namespaced_resource
109+
return ret, namespaced_resource

kubeshell/completer.py

Lines changed: 9 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import json
77
import os
88
import os.path
9-
from kubernetes import client, config
9+
10+
from kubeshell.client import KubernetesClient
1011

1112
class KubectlCompleter(Completer):
1213

@@ -17,6 +18,7 @@ def __init__(self):
1718
self.global_opts = []
1819
self.inline_help = True
1920
self.namespace = ""
21+
self.kube_client = KubernetesClient()
2022

2123
try:
2224
DATA_DIR = os.path.dirname(os.path.realpath(__file__))
@@ -124,7 +126,7 @@ def parse_tokens(self, cmdline):
124126
elif state == "KUBECTL_ARG":
125127
if token.startswith("--"):
126128
continue
127-
resources = self.get_resources(arg)
129+
resources = self.kube_client.get_resource(arg)
128130
if resources:
129131
for resource_name, namespace in resources:
130132
if token == resource_name:
@@ -182,7 +184,7 @@ def get_completions(self, document, complete_event, smart_completion=None):
182184
yield Completion(suggestion, -len(last_token), display=suggestion, display_meta=self.help_msg)
183185
if word_before_cursor == "":
184186
if last_token == "--namespace":
185-
namespaces = self.get_resources("namespace")
187+
namespaces = self.kube_client.get_resource("namespace")
186188
for ns in namespaces:
187189
yield Completion(ns[0])
188190
return
@@ -223,7 +225,7 @@ def get_completions(self, document, complete_event, smart_completion=None):
223225
yield Completion(arg, -len(last_token))
224226
elif word_before_cursor == "":
225227
if last_token == "--namespace":
226-
namespaces = self.get_resources("namespace")
228+
namespaces = self.kube_client.get_resource("namespace")
227229
for ns in namespaces:
228230
yield Completion(ns[0])
229231
return
@@ -239,11 +241,11 @@ def get_completions(self, document, complete_event, smart_completion=None):
239241
last_token = tokens[-1]
240242
if word_before_cursor == "":
241243
if last_token == "--namespace":
242-
namespaces = self.get_resources("namespace")
244+
namespaces = self.kube_client.get_resource("namespace")
243245
for ns in namespaces:
244246
yield Completion(ns[0])
245247
return
246-
resources = self.get_resources(arg, namespace)
248+
resources = self.kube_client.get_resource(arg, namespace)
247249
if resources:
248250
for resourceName, namespace in resources:
249251
yield Completion(resourceName, display=resourceName, display_meta=namespace)
@@ -265,105 +267,10 @@ def get_completions(self, document, complete_event, smart_completion=None):
265267
help_msg = self.kubectl_dict['kubectl']['options'][global_opt]['help']
266268
yield Completion(global_opt, -len(word_before_cursor), display=global_opt, display_meta=self.help_msg)
267269
if last_token == "--namespace":
268-
namespaces = self.get_resources("namespace")
270+
namespaces = self.kube_client.get_resource("namespace")
269271
for ns in namespaces:
270272
yield Completion(ns[0])
271273
return
272274
else:
273275
pass
274276
return
275-
276-
def get_resources(self, resource, namespace="all"):
277-
resources = []
278-
try:
279-
config.load_kube_config()
280-
except Exception as e:
281-
# TODO: log errors to log file
282-
return resources
283-
284-
v1 = client.CoreV1Api()
285-
v1Beta1 = client.AppsV1beta1Api()
286-
extensionsV1Beta1 = client.ExtensionsV1beta1Api()
287-
autoscalingV1Api = client.AutoscalingV1Api()
288-
rbacAPi = client.RbacAuthorizationV1beta1Api()
289-
batchV1Api = client.BatchV1Api()
290-
batchV2Api = client.BatchV2alpha1Api()
291-
292-
ret = None
293-
namespaced_resource = True
294-
295-
if resource == "pod":
296-
ret = v1.list_pod_for_all_namespaces(watch=False)
297-
elif resource == "service":
298-
ret = v1.list_service_for_all_namespaces(watch=False)
299-
elif resource == "deployment":
300-
ret = v1Beta1.list_deployment_for_all_namespaces(watch=False)
301-
elif resource == "statefulset":
302-
ret = v1Beta1.list_stateful_set_for_all_namespaces(watch=False)
303-
elif resource == "node":
304-
namespaced_resource = False
305-
ret = v1.list_node(watch=False)
306-
elif resource == "namespace":
307-
namespaced_resource = False
308-
ret = v1.list_namespace(watch=False)
309-
elif resource == "daemonset":
310-
ret = extensionsV1Beta1.list_daemon_set_for_all_namespaces(watch=False)
311-
elif resource == "networkpolicy":
312-
ret = extensionsV1Beta1.list_network_policy_for_all_namespaces(watch=False)
313-
elif resource == "thirdpartyresource":
314-
namespaced_resource = False
315-
ret = extensionsV1Beta1.list_third_party_resource(watch=False)
316-
elif resource == "replicationcontroller":
317-
ret = v1.list_replication_controller_for_all_namespaces(watch=False)
318-
elif resource == "replicaset":
319-
ret = extensionsV1Beta1.list_replica_set_for_all_namespaces(watch=False)
320-
elif resource == "ingress":
321-
ret = extensionsV1Beta1.list_ingress_for_all_namespaces(watch=False)
322-
elif resource == "endpoints":
323-
ret = v1.list_endpoints_for_all_namespaces(watch=False)
324-
elif resource == "configmap":
325-
ret = v1.list_config_map_for_all_namespaces(watch=False)
326-
elif resource == "event":
327-
ret = v1.list_event_for_all_namespaces(watch=False)
328-
elif resource == "limitrange":
329-
ret = v1.list_limit_range_for_all_namespaces(watch=False)
330-
elif resource == "configmap":
331-
ret = v1.list_config_map_for_all_namespaces(watch=False)
332-
elif resource == "persistentvolume":
333-
namespaced_resource = False
334-
ret = v1.list_persistent_volume(watch=False)
335-
elif resource == "secret":
336-
ret = v1.list_secret_for_all_namespaces(watch=False)
337-
elif resource == "resourcequota":
338-
ret = v1.list_resource_quota_for_all_namespaces(watch=False)
339-
elif resource == "componentstatus":
340-
namespaced_resource = False
341-
ret = v1.list_component_status(watch=False)
342-
elif resource == "podtemplate":
343-
ret = v1.list_pod_template_for_all_namespaces(watch=False)
344-
elif resource == "serviceaccount":
345-
ret = v1.list_service_account_for_all_namespaces(watch=False)
346-
elif resource == "horizontalpodautoscaler":
347-
ret = autoscalingV1Api.list_horizontal_pod_autoscaler_for_all_namespaces(watch=False)
348-
elif resource == "clusterrole":
349-
namespaced_resource = False
350-
ret = rbacAPi.list_cluster_role(watch=False)
351-
elif resource == "clusterrolebinding":
352-
namespaced_resource = False
353-
ret = rbacAPi.list_cluster_role_binding(watch=False)
354-
elif resource == "job":
355-
ret = batchV1Api.list_job_for_all_namespaces(watch=False)
356-
elif resource == "cronjob":
357-
ret = batchV2Api.list_cron_job_for_all_namespaces(watch=False)
358-
elif resource == "scheduledjob":
359-
ret = batchV2Api.list_scheduled_job_for_all_namespaces(watch=False)
360-
361-
if ret:
362-
for i in ret.items:
363-
if namespace == "all" or not namespaced_resource:
364-
resources.append((i.metadata.name, i.metadata.namespace))
365-
elif namespace == i.metadata.namespace:
366-
resources.append((i.metadata.name, i.metadata.namespace))
367-
return resources
368-
return None
369-

0 commit comments

Comments
 (0)