3 # Copyright (c) 2018 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 """Python API provider.
26 sys.path.append('/tmp/openvpp-testing')
28 from resources.libraries.python.PapiErrors import *
32 # Sphinx creates auto-generated documentation by importing the python source
33 # files and collecting the docstrings from them. The NO_VPP_PAPI flag allows
34 # the vpp_papi_provider.py file to be importable without having to build
35 # the whole vpp api if the user only wishes to generate the test documentation.
38 no_vpp_papi = os.getenv("NO_VPP_PAPI")
39 if no_vpp_papi == "1":
45 # TODO: run os.walk once per whole suite and store the path in environmental
48 for root, dirs, files in os.walk('/usr/lib'):
50 if name == 'vpp_papi.py':
51 modules_path = os.path.split(root)[0]
54 sys.path.append(modules_path)
55 from vpp_papi import VPP
57 raise PapiInitError('vpp_papi module not found')
60 CLIENT_NAME = 'csit_papi'
64 """Construct a VPP instance from VPP JSON API files.
66 :param vpp_json_dir: Directory containing all the JSON API files. If VPP is
67 installed in the system it will be in /usr/share/vpp/api/.
68 :type vpp_json_dir: str
69 :returns: VPP instance.
71 :raises PapiJsonFileError: If no api.json file found.
72 :raises PapiInitError: If PAPI initialization failed.
77 except Exception as err:
78 raise PapiInitError('PAPI init failed:\n{exc}'.format(exc=repr(err)))
81 def papi_connect(vpp_client, name='vpp_api'):
82 """Attach to VPP client.
84 :param vpp_client: VPP instance to connect to.
85 :param name: VPP client name.
86 :type vpp_client: VPP object
88 :returns: Return code of VPP.connect() method.
91 return vpp_client.connect(name)
94 def papi_disconnect(vpp_client):
95 """Detach from VPP client.
97 :param vpp_client: VPP instance to detach from.
98 :type vpp_client: VPP object
100 vpp_client.disconnect()
103 def papi_run(vpp_client, api_name, api_args):
106 :param vpp_client: VPP instance.
107 :param api_name: VPP API name.
108 :param api_args: Input arguments of the API.
109 :type vpp_client: VPP object
112 :returns: VPP API reply.
113 :rtype: Vpp_serializer reply object
115 papi_fn = getattr(vpp_client.api, api_name)
116 return papi_fn(**api_args)
119 def convert_reply(api_r):
120 """Process API reply / a part of API reply for smooth converting to
123 # Apply binascii.hexlify() method for string values.
124 :param api_r: API reply.
125 :type api_r: Vpp_serializer reply object (named tuple)
126 :returns: Processed API reply / a part of API reply.
129 unwanted_fields = ['count', 'index']
132 reply_key = repr(api_r).split('(')[0]
134 for item in dir(api_r):
135 if not item.startswith('_') and item not in unwanted_fields:
136 # attr_value = getattr(api_r, item)
137 # value = binascii.hexlify(attr_value) \
138 # if isinstance(attr_value, str) else attr_value
139 value = getattr(api_r, item)
140 reply_value[item] = value
141 reply_dict[reply_key] = reply_value
145 def process_reply(api_reply):
146 """Process API reply for smooth converting to JSON string.
148 :param api_reply: API reply.
149 :type api_reply: Vpp_serializer reply object (named tuple) or list of
150 vpp_serializer reply objects
151 :returns: Processed API reply.
155 if isinstance(api_reply, list):
156 converted_reply = list()
158 converted_reply.append(convert_reply(r))
160 converted_reply = convert_reply(api_reply)
161 return converted_reply
165 """Main function for the Python API provider.
167 :raises PapiCommandInputError: If invalid attribute name or invalid value is
169 :raises PapiCommandError: If PAPI command(s) execution failed.
172 parser = argparse.ArgumentParser()
173 parser.add_argument("-j", "--json_data",
176 help="JSON string (list) containing API name(s) and "
177 "its/their input argument(s).")
178 parser.add_argument("-d", "--json_dir",
180 default='/usr/share/vpp/api/',
181 help="Directory containing all vpp json api files.")
182 args = parser.parse_args()
183 json_string = args.json_data
188 json_data = json.loads(json_string)
189 papi_connect(vpp, CLIENT_NAME)
190 for data in json_data:
191 api_name = data['api_name']
192 api_args_unicode = data['api_args']
193 api_reply = dict(api_name=api_name)
195 for a_k, a_v in api_args_unicode.iteritems():
196 value = binascii.unhexlify(a_v) if isinstance(a_v, unicode) else a_v
197 api_args[str(a_k)] = value
199 rep = papi_run(vpp, api_name, api_args)
200 api_reply['api_reply'] = process_reply(rep)
201 reply.append(api_reply)
202 except (AttributeError, ValueError) as err:
204 raise PapiCommandInputError(
205 'PAPI command {api}({args}) input error:\n{exc}'.format(
206 api=api_name, args=api_args), exc=repr(err))
207 except Exception as err:
209 raise PapiCommandError(
210 'PAPI command {api}({args}) error:\n{exc}'.format(
211 api=api_name, args=api_args), exc=repr(err))
214 return json.dumps(reply)
217 if __name__ == '__main__':
218 sys.stdout.write(main())