Skip to content

Commit 294a48f

Browse files
committed
Added make develop, checkpoint commit for the rest
1 parent d9bd9fe commit 294a48f

File tree

4 files changed

+168
-128
lines changed

4 files changed

+168
-128
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ help:
9090
develop:
9191
@echo "--------------------------------------------------------------------"
9292
@echo "Setting up development environment"
93-
@python setup.py develop --no-deps -q
93+
@python setup.py develop -q
9494
@echo ""
9595
@echo "Done."
9696
@echo ""
@@ -99,7 +99,7 @@ develop:
9999
undevelop:
100100
@echo "--------------------------------------------------------------------"
101101
@echo "Removing development environment"
102-
@python setup.py develop --no-deps -q --uninstall
102+
@python setup.py develop -q --uninstall
103103
@echo ""
104104
@echo "Done."
105105
@echo ""

src/cisco_gnmi/client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,6 @@ def parse_xpath_to_gnmi_path(self, xpath, origin=None):
341341
def xpath_iterator(self, xpath):
342342
for token in xpath[1:].split('/'):
343343
#elem = proto.gnmi_pb2.PathElem()
344-
xpath_so_far += '/' + token
345344
if '[' in token:
346345
keys = OrderedDict()
347346
subtoken = token.replace('[', ',').replace(']', '').split(',')

src/cisco_gnmi/nx.py

Lines changed: 96 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,76 @@ class NXClient(Client):
5555
>>> print(capabilities)
5656
"""
5757

58+
def xpath_to_path_elem(self, request):
59+
paths = []
60+
message = {
61+
'update': [],
62+
'replace': [],
63+
'delete': [],
64+
'get': [],
65+
}
66+
if 'nodes' not in request:
67+
# TODO: raw rpc?
68+
return paths
69+
else:
70+
namespace_modules = {}
71+
for prefix, nspace in request.get('namespace', {}).items():
72+
module = ''
73+
if '/Cisco-IOS-' in nspace:
74+
module = nspace[nspace.rfind('/') + 1:]
75+
elif '/cisco-nx' in nspace: # NXOS lowercases namespace
76+
module = 'Cisco-NX-OS-device'
77+
elif '/openconfig.net' in nspace:
78+
module = 'openconfig-'
79+
module += nspace[nspace.rfind('/') + 1:]
80+
elif 'urn:ietf:params:xml:ns:yang:' in nspace:
81+
module = nspace.replace(
82+
'urn:ietf:params:xml:ns:yang:', '')
83+
if module:
84+
namespace_modules[prefix] = module
85+
for node in request.get('nodes', []):
86+
if 'xpath' not in node:
87+
log.error('Xpath is not in message')
88+
else:
89+
xpath = node['xpath']
90+
value = node.get('value', '')
91+
edit_op = node.get('edit-op', '')
92+
93+
for pfx, ns in namespace_modules.items():
94+
xpath = xpath.replace(pfx + ':', '')
95+
value = value.replace(pfx + ':', '')
96+
if edit_op:
97+
if edit_op in ['create', 'merge', 'replace']:
98+
xpath_lst = xpath.split('/')
99+
name = xpath_lst.pop()
100+
xpath = '/'.join(xpath_lst)
101+
if edit_op == 'replace':
102+
if not message['replace']:
103+
message['replace'] = [{
104+
xpath: {name: value}
105+
}]
106+
else:
107+
message['replace'].append(
108+
{xpath: {name: value}}
109+
)
110+
else:
111+
if not message['update']:
112+
message['update'] = [{
113+
xpath: {name: value}
114+
}]
115+
else:
116+
message['update'].append(
117+
{xpath: {name: value}}
118+
)
119+
elif edit_op in ['delete', 'remove']:
120+
if message['delete']:
121+
message['delete'].add(xpath)
122+
else:
123+
message['delete'] = set(xpath)
124+
else:
125+
message['get'].append(xpath)
126+
return namespace_modules, message
127+
58128
def delete_xpaths(self, xpaths, prefix=None):
59129
"""A convenience wrapper for set() which constructs Paths from supplied xpaths
60130
to be passed to set() as the delete parameter.
@@ -87,6 +157,31 @@ def delete_xpaths(self, xpaths, prefix=None):
87157
paths.append(self.parse_xpath_to_gnmi_path(xpath))
88158
return self.set(deletes=paths)
89159

160+
def segment_configs(self, request, configs=[]):
161+
seg_config = []
162+
for config in configs:
163+
top_element = next(iter(config.keys()))
164+
name, val = (next(iter(config[top_element].items())))
165+
value = {'name': name, 'value': val}
166+
seg_config.append(
167+
(
168+
top_element,
169+
[seg for seg in self.xpath_iterator(top_element)],
170+
value
171+
)
172+
)
173+
import pdb; pdb.set_trace()
174+
# seg_config = self.resolve_segments(seg_config)
175+
# Build the Path
176+
path = proto.gnmi_pb2.Path()
177+
for config in seg_config:
178+
xpath, segments, value = config
179+
for seg in segments:
180+
path_elem = proto.gnmi_pb2.PathElem()
181+
path_elem.name = seg['elem']['name']
182+
183+
return seg_config
184+
90185
def set_json(self, update_json_configs=None, replace_json_configs=None, ietf=True):
91186
"""A convenience wrapper for set() which assumes JSON payloads and constructs desired messages.
92187
All parameters are optional, but at least one must be present.
@@ -127,36 +222,12 @@ def check_configs(configs):
127222
)
128223
return configs
129224

130-
def segment_configs(configs=[]):
131-
seg_config = []
132-
for config in configs:
133-
top_element = next(iter(config.keys()))
134-
name, val = (next(iter(config[top_element].items())))
135-
value = {'name': name, 'value': val}
136-
seg_config.append(
137-
(
138-
top_element,
139-
[seg for seg in self.xpath_iterator(top_element)],
140-
value
141-
)
142-
)
143-
import pdb; pdb.set_trace()
144-
seg_config = self.resolve_segments(seg_config)
145-
# Build the Path
146-
path = proto.gnmi_pb2.Path()
147-
for config in seg_config:
148-
xpath, segments, value = config
149-
for seg in segments:
150-
path_elem = proto.gnmi_pb2.PathElem()
151-
path_elem.name = seg['elem']['name']
152-
return seg_config
153-
154225
def create_updates(configs):
155226
if not configs:
156227
return None
157228
configs = check_configs(configs)
158229
import pdb; pdb.set_trace()
159-
#segment_configs(configs)
230+
#self.segment_configs(configs)
160231
updates = []
161232
for config in configs:
162233
if not isinstance(config, dict):
@@ -252,106 +323,6 @@ def get_xpaths(self, xpaths, data_type="ALL", encoding="JSON"):
252323
)
253324
return self.get(gnmi_path, data_type=data_type, encoding=encoding)
254325

255-
def subscribe_xpaths(
256-
self,
257-
xpath_subscriptions,
258-
encoding="JSON_IETF",
259-
sample_interval=Client._NS_IN_S * 10,
260-
heartbeat_interval=None,
261-
):
262-
"""A convenience wrapper of subscribe() which aids in building of SubscriptionRequest
263-
with request as subscribe SubscriptionList. This method accepts an iterable of simply xpath strings,
264-
dictionaries with Subscription attributes for more granularity, or already built Subscription
265-
objects and builds the SubscriptionList. Fields not supplied will be defaulted with the default arguments
266-
to the method.
267-
268-
Generates a single SubscribeRequest.
269-
270-
Parameters
271-
----------
272-
xpath_subscriptions : str or iterable of str, dict, Subscription
273-
An iterable which is parsed to form the Subscriptions in the SubscriptionList to be passed
274-
to SubscriptionRequest. Strings are parsed as XPaths and defaulted with the default arguments,
275-
dictionaries are treated as dicts of args to pass to the Subscribe init, and Subscription is
276-
treated as simply a pre-made Subscription.
277-
encoding : proto.gnmi_pb2.Encoding, optional
278-
A member of the proto.gnmi_pb2.Encoding enum specifying desired encoding of returned data
279-
[JSON, JSON_IETF]
280-
sample_interval : int, optional
281-
Default nanoseconds for sample to occur.
282-
Defaults to 10 seconds.
283-
heartbeat_interval : int, optional
284-
Specifies the maximum allowable silent period in nanoseconds when
285-
suppress_redundant is in use. The target should send a value at least once
286-
in the period specified.
287-
288-
Returns
289-
-------
290-
subscribe()
291-
"""
292-
supported_request_modes = ["STREAM"]
293-
request_mode = "STREAM"
294-
supported_sub_modes = ["SAMPLE"]
295-
sub_mode = "SAMPLE"
296-
supported_encodings = ["JSON", "JSON_IETF"]
297-
subscription_list = proto.gnmi_pb2.SubscriptionList()
298-
subscription_list.mode = util.validate_proto_enum(
299-
"mode",
300-
request_mode,
301-
"SubscriptionList.Mode",
302-
proto.gnmi_pb2.SubscriptionList.Mode,
303-
supported_request_modes,
304-
)
305-
subscription_list.encoding = util.validate_proto_enum(
306-
"encoding",
307-
encoding,
308-
"Encoding",
309-
proto.gnmi_pb2.Encoding,
310-
supported_encodings,
311-
)
312-
if isinstance(xpath_subscriptions, string_types):
313-
xpath_subscriptions = [xpath_subscriptions]
314-
subscriptions = []
315-
for xpath_subscription in xpath_subscriptions:
316-
subscription = None
317-
if isinstance(xpath_subscription, string_types):
318-
subscription = proto.gnmi_pb2.Subscription()
319-
subscription.path.CopyFrom(
320-
self.parse_xpath_to_gnmi_path(xpath_subscription)
321-
)
322-
subscription.mode = util.validate_proto_enum(
323-
"sub_mode",
324-
sub_mode,
325-
"SubscriptionMode",
326-
proto.gnmi_pb2.SubscriptionMode,
327-
supported_sub_modes,
328-
)
329-
subscription.sample_interval = sample_interval
330-
elif isinstance(xpath_subscription, dict):
331-
path = self.parse_xpath_to_gnmi_path(xpath_subscription["path"])
332-
arg_dict = {
333-
"path": path,
334-
"mode": sub_mode,
335-
"sample_interval": sample_interval,
336-
}
337-
arg_dict.update(xpath_subscription)
338-
if "mode" in arg_dict:
339-
arg_dict["mode"] = util.validate_proto_enum(
340-
"sub_mode",
341-
arg_dict["mode"],
342-
"SubscriptionMode",
343-
proto.gnmi_pb2.SubscriptionMode,
344-
supported_sub_modes,
345-
)
346-
subscription = proto.gnmi_pb2.Subscription(**arg_dict)
347-
elif isinstance(xpath_subscription, proto.gnmi_pb2.Subscription):
348-
subscription = xpath_subscription
349-
else:
350-
raise Exception("xpath in list must be xpath or dict/Path!")
351-
subscriptions.append(subscription)
352-
subscription_list.subscription.extend(subscriptions)
353-
return self.subscribe([subscription_list])
354-
355326
def subscribe_xpaths(
356327
self,
357328
xpath_subscriptions,

src/cisco_gnmi/xe.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,76 @@ class XEClient(Client):
7676
>>> delete_response = client.delete_xpaths('/Cisco-IOS-XE-native:native/hostname')
7777
"""
7878

79+
def xpath_to_path_elem(self, request):
80+
paths = []
81+
message = {
82+
'update': [],
83+
'replace': [],
84+
'delete': [],
85+
'get': [],
86+
}
87+
if 'nodes' not in request:
88+
# TODO: raw rpc?
89+
return paths
90+
else:
91+
namespace_modules = {}
92+
for prefix, nspace in request.get('namespace', {}).items():
93+
module = ''
94+
if '/Cisco-IOS-' in nspace:
95+
module = nspace[nspace.rfind('/') + 1:]
96+
elif '/cisco-nx' in nspace: # NXOS lowercases namespace
97+
module = 'Cisco-NX-OS-device'
98+
elif '/openconfig.net' in nspace:
99+
module = 'openconfig-'
100+
module += nspace[nspace.rfind('/') + 1:]
101+
elif 'urn:ietf:params:xml:ns:yang:' in nspace:
102+
module = nspace.replace(
103+
'urn:ietf:params:xml:ns:yang:', '')
104+
if module:
105+
namespace_modules[prefix] = module
106+
for node in request.get('nodes', []):
107+
if 'xpath' not in node:
108+
log.error('Xpath is not in message')
109+
else:
110+
xpath = node['xpath']
111+
value = node.get('value', '')
112+
edit_op = node.get('edit-op', '')
113+
114+
for pfx, ns in namespace_modules.items():
115+
xpath = xpath.replace(pfx + ':', ns + ':')
116+
value = value.replace(pfx + ':', ns + ':')
117+
if edit_op:
118+
if edit_op in ['create', 'merge', 'replace']:
119+
xpath_lst = xpath.split('/')
120+
name = xpath_lst.pop()
121+
xpath = '/'.join(xpath_lst)
122+
if edit_op == 'replace':
123+
if not message['replace']:
124+
message['replace'] = [{
125+
xpath: {name: value}
126+
}]
127+
else:
128+
message['replace'].append(
129+
{xpath: {name: value}}
130+
)
131+
else:
132+
if not message['update']:
133+
message['update'] = [{
134+
xpath: {name: value}
135+
}]
136+
else:
137+
message['update'].append(
138+
{xpath: {name: value}}
139+
)
140+
elif edit_op in ['delete', 'remove']:
141+
if message['delete']:
142+
message['delete'].add(xpath)
143+
else:
144+
message['delete'] = set(xpath)
145+
else:
146+
message['get'].append(xpath)
147+
return namespace_modules, message
148+
79149
def delete_xpaths(self, xpaths, prefix=None):
80150
"""A convenience wrapper for set() which constructs Paths from supplied xpaths
81151
to be passed to set() as the delete parameter.

0 commit comments

Comments
 (0)