@@ -52,12 +52,146 @@ class NXClient(Client):
5252 >>> capabilities = client.capabilities()
5353 >>> print(capabilities)
5454 """
55+ def delete_xpaths (self , xpaths , prefix = None ):
56+ """A convenience wrapper for set() which constructs Paths from supplied xpaths
57+ to be passed to set() as the delete parameter.
5558
56- def get (self , * args , ** kwargs ):
57- raise NotImplementedError ("Get not yet supported on NX-OS!" )
59+ Parameters
60+ ----------
61+ xpaths : iterable of str
62+ XPaths to specify to be deleted.
63+ If prefix is specified these strings are assumed to be the suffixes.
64+ prefix : str
65+ The XPath prefix to apply to all XPaths for deletion.
66+
67+ Returns
68+ -------
69+ set()
70+ """
71+ if isinstance (xpaths , string_types ):
72+ xpaths = [xpaths ]
73+ paths = []
74+ # prefix is not supported on NX yet
75+ prefix = None
76+ for xpath in xpaths :
77+ if prefix :
78+ if prefix .endswith ("/" ) and xpath .startswith ("/" ):
79+ xpath = "{prefix}{xpath}" .format (
80+ prefix = prefix [:- 1 ], xpath = xpath [1 :]
81+ )
82+ elif prefix .endswith ("/" ) or xpath .startswith ("/" ):
83+ xpath = "{prefix}{xpath}" .format (prefix = prefix , xpath = xpath )
84+ else :
85+ xpath = "{prefix}/{xpath}" .format (prefix = prefix , xpath = xpath )
86+ paths .append (self .parse_xpath_to_gnmi_path (xpath ))
87+ return self .set (deletes = paths )
88+
89+ def set_json (self , update_json_configs = None , replace_json_configs = None , ietf = False , prefix = None ):
90+ """A convenience wrapper for set() which assumes JSON payloads and constructs desired messages.
91+ All parameters are optional, but at least one must be present.
92+
93+ This method expects JSON in the same format as what you might send via the native gRPC interface
94+ with a fully modeled configuration which is then parsed to meet the gNMI implementation.
95+
96+ Parameters
97+ ----------
98+ update_json_configs : iterable of JSON configurations, optional
99+ JSON configs to apply as updates.
100+ replace_json_configs : iterable of JSON configurations, optional
101+ JSON configs to apply as replacements.
102+ ietf : bool, optional
103+ Use JSON_IETF vs JSON.
104+
105+ Returns
106+ -------
107+ set()
108+ """
109+ # JSON_IETF and prefix are not supported on NX yet
110+ ietf = False
111+ prefix = None
112+
113+ if not any ([update_json_configs , replace_json_configs ]):
114+ raise Exception ("Must supply at least one set of configurations to method!" )
115+
116+ def check_configs (name , configs ):
117+ if isinstance (configs , string_types ):
118+ logger .debug ("Handling %s as JSON string." , name )
119+ try :
120+ configs = json .loads (configs )
121+ except :
122+ raise Exception ("{name} is invalid JSON!" .format (name = name ))
123+ configs = [configs ]
124+ elif isinstance (configs , dict ):
125+ logger .debug ("Handling %s as already serialized JSON object." , name )
126+ configs = [configs ]
127+ elif not isinstance (configs , (list , set )):
128+ raise Exception (
129+ "{name} must be an iterable of configs!" .format (name = name )
130+ )
131+ return configs
58132
59- def set (self , * args , ** kwargs ):
60- raise NotImplementedError ("Set not yet supported on NX-OS!" )
133+ def create_updates (name , configs ):
134+ if not configs :
135+ return None
136+ configs = check_configs (name , configs )
137+ updates = []
138+ for config in configs :
139+ if not isinstance (config , dict ):
140+ raise Exception ("config must be a JSON object!" )
141+ if len (config .keys ()) > 1 :
142+ raise Exception ("config should only target one YANG module!" )
143+ top_element = next (iter (config .keys ()))
144+ update = proto .gnmi_pb2 .Update ()
145+ update .path .CopyFrom (self .parse_xpath_to_gnmi_path (top_element ))
146+ config = config .pop (top_element )
147+ if ietf :
148+ update .val .json_ietf_val = json .dumps (config ).encode ("utf-8" )
149+ else :
150+ update .val .json_val = json .dumps (config ).encode ("utf-8" )
151+ updates .append (update )
152+ return updates
153+
154+ updates = create_updates ("update_json_configs" , update_json_configs )
155+ replaces = create_updates ("replace_json_configs" , replace_json_configs )
156+ return self .set (prefix = prefix , updates = updates , replaces = replaces )
157+
158+ def get_xpaths (self , xpaths , data_type = "ALL" , encoding = "JSON_IETF" ):
159+ """A convenience wrapper for get() which forms proto.gnmi_pb2.Path from supplied xpaths.
160+
161+ Parameters
162+ ----------
163+ xpaths : iterable of str or str
164+ An iterable of XPath strings to request data of
165+ If simply a str, wraps as a list for convenience
166+ data_type : proto.gnmi_pb2.GetRequest.DataType, optional
167+ A direct value or key from the GetRequest.DataType enum
168+ [ALL, CONFIG, STATE, OPERATIONAL]
169+ encoding : proto.gnmi_pb2.GetRequest.Encoding, optional
170+ A direct value or key from the Encoding enum
171+ [JSON, JSON_IETF]
172+
173+ Returns
174+ -------
175+ get()
176+ """
177+ supported_encodings = ["JSON" , "JSON_IETF" ]
178+ encoding = util .validate_proto_enum (
179+ "encoding" ,
180+ encoding ,
181+ "Encoding" ,
182+ proto .gnmi_pb2 .Encoding ,
183+ supported_encodings ,
184+ )
185+ gnmi_path = None
186+ if isinstance (xpaths , (list , set )):
187+ gnmi_path = map (self .parse_xpath_to_gnmi_path , set (xpaths ))
188+ elif isinstance (xpaths , string_types ):
189+ gnmi_path = [self .parse_xpath_to_gnmi_path (xpaths )]
190+ else :
191+ raise Exception (
192+ "xpaths must be a single xpath string or iterable of xpath strings!"
193+ )
194+ return self .get (gnmi_path , data_type = data_type , encoding = encoding )
61195
62196 def subscribe_xpaths (
63197 self ,
0 commit comments