Skip to content

Commit 86b3252

Browse files
committed
Add watch to dynamic client (#221)
* First stab at watch implementation * add docs * remove extraneous newline * Fixes #203 fix query parameter checking to prevent filtering out valid falsey values * Add docstring for watch (cherry picked from commit 2bf10ca)
1 parent 58a8b9d commit 86b3252

File tree

2 files changed

+59
-10
lines changed

2 files changed

+59
-10
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,16 @@ v1_services.replace(body=body, namespace='test')
312312

313313
The `replace` implementation is the same for `*List` kinds, except that each definition in the list will be replaced separately.
314314

315+
#### `watch(namespace=None, name=None, label_selector=None, field_selector=None, resource_version=None, timeout=None)`
316+
317+
```python
318+
v1_services = dyn_client.resources.get(api_version='v1', kind='Service')
319+
320+
# Prints the resource that triggered each event related to Services in the 'test' namespace
321+
for event in v1_services.watch(namespace='test'):
322+
print(event['object'])
323+
```
324+
315325
### DEPRECATED Generated client usage
316326

317327
To work with a K8s object, use the K8s client, and to work with an OpenShift specific object, use the OpenShift client. For example, the following uses the K8s client to create a new Service object:

openshift/dynamic/client.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import yaml
1010
from pprint import pformat
1111

12-
from kubernetes import config
12+
from kubernetes import config, watch
1313
from kubernetes.client.api_client import ApiClient
1414
from kubernetes.client.rest import ApiException
1515

@@ -209,6 +209,45 @@ def patch(self, resource, body=None, name=None, namespace=None, **kwargs):
209209

210210
return self.request('patch', path, body=body, content_type=content_type, **kwargs)
211211

212+
def watch(self, resource, namespace=None, name=None, label_selector=None, field_selector=None, resource_version=None, timeout=None):
213+
"""
214+
Stream events for a resource from the Kubernetes API
215+
216+
:param resource: The API resource object that will be used to query the API
217+
:param namespace: The namespace to query
218+
:param name: The name of the resource instance to query
219+
:param label_selector: The label selector with which to filter results
220+
:param label_selector: The field selector with which to filter results
221+
:param resource_version: The version with which to filter results. Only events with
222+
a resource_version greater than this value will be returned
223+
:param timeout: The amount of time in seconds to wait before terminating the stream
224+
225+
:return: Event object with these keys:
226+
'type': The type of event such as "ADDED", "DELETED", etc.
227+
'raw_object': a dict representing the watched object.
228+
'object': A ResourceInstance wrapping raw_object.
229+
230+
Example:
231+
client = DynamicClient(k8s_client)
232+
v1_pods = client.resources.get(api_version='v1', kind='Pod')
233+
234+
for e in v1_pods.watch(resource_version=0, namespace=default, timeout=5):
235+
print(e['type'])
236+
print(e['object'].metadata)
237+
"""
238+
watcher = watch.Watch()
239+
for event in watcher.stream(
240+
resource.get,
241+
namespace=namespace,
242+
name=name,
243+
field_selector=field_selector,
244+
label_selector=label_selector,
245+
resource_version=resource_version,
246+
serialize=False,
247+
timeout_seconds=timeout
248+
):
249+
event['object'] = ResourceInstance(resource, event['object'])
250+
yield event
212251

213252
def request(self, method, path, body=None, **params):
214253

@@ -217,23 +256,23 @@ def request(self, method, path, body=None, **params):
217256

218257
path_params = params.get('path_params', {})
219258
query_params = params.get('query_params', [])
220-
if params.get('pretty'):
259+
if params.get('pretty') is not None:
221260
query_params.append(('pretty', params['pretty']))
222-
if params.get('_continue'):
261+
if params.get('_continue') is not None:
223262
query_params.append(('continue', params['_continue']))
224-
if params.get('include_uninitialized'):
263+
if params.get('include_uninitialized') is not None:
225264
query_params.append(('includeUninitialized', params['include_uninitialized']))
226-
if params.get('field_selector'):
265+
if params.get('field_selector') is not None:
227266
query_params.append(('fieldSelector', params['field_selector']))
228-
if params.get('label_selector'):
267+
if params.get('label_selector') is not None:
229268
query_params.append(('labelSelector', params['label_selector']))
230-
if params.get('limit'):
269+
if params.get('limit') is not None:
231270
query_params.append(('limit', params['limit']))
232-
if params.get('resource_version'):
271+
if params.get('resource_version') is not None:
233272
query_params.append(('resourceVersion', params['resource_version']))
234-
if params.get('timeout_seconds'):
273+
if params.get('timeout_seconds') is not None:
235274
query_params.append(('timeoutSeconds', params['timeout_seconds']))
236-
if params.get('watch'):
275+
if params.get('watch') is not None:
237276
query_params.append(('watch', params['watch']))
238277

239278
header_params = params.get('header_params', {})

0 commit comments

Comments
 (0)