5cbc733c5392832d34b0578c0325da3e0b9758f8
[nfvbench.git] / client / client.py
1 #!/usr/bin/env python
2 # Copyright 2017 Cisco Systems, Inc.  All rights reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15 #
16
17 import requests
18 import time
19
20 from socketIO_client import SocketIO
21
22
23 class TimeOutException(Exception):
24     pass
25
26
27 class NfvbenchException(Exception):
28     pass
29
30
31 class NfvbenchClient(object):
32     """Python client class to control a nfvbench server
33
34     The nfvbench server must run in background using the --server option.
35     Since HTML pages are not required, the path to pass to --server can be
36     any directory on the host.
37     """
38     def __init__(self, nfvbench_url, use_socketio):
39         """Client class to send requests to the nfvbench server
40
41         Args:
42             nfvbench_url: the URL of the nfvbench server (e.g. 'http://127.0.0.1:7555')
43         """
44         self.url = nfvbench_url
45         self.use_socketio = use_socketio
46
47     def socketio_send(self, send_event, receive_event, config, timeout):
48         class Exec(object):
49             socketIO = None
50             socketio_result = None
51
52         def close_socketio(result):
53             Exec.socketio_result = result
54             Exec.socketIO.disconnect()
55
56         def on_response(*args):
57             close_socketio(args[0])
58
59         def on_error(*args):
60             raise NfvbenchException(args[0])
61
62         Exec.socketIO = SocketIO(self.url)
63         Exec.socketIO.on(receive_event, on_response)
64         Exec.socketIO.on('error', on_error)
65         Exec.socketIO.emit(send_event, config)
66         Exec.socketIO.wait(seconds=timeout)
67
68         if timeout and not Exec.socketio_result:
69             raise TimeOutException()
70         return Exec.socketio_result
71
72     def http_get(self, command, config):
73         url = self.url + '/' + command
74         res = requests.get(url, json=config)
75         if res.ok:
76             return res.json()
77         res.raise_for_status()
78
79     def http_post(self, command, config):
80         url = self.url + '/' + command
81         res = requests.post(url, json=config)
82         if res.ok:
83             return res.json()
84         res.raise_for_status()
85
86     def echo_config(self, config, timeout=100):
87         """Send an echo event to the nfvbench server with some dummy config and expect the
88         config to be sent back right away.
89
90         Args:
91             config: some dummy configuration - must be a valid dict
92             timeout: how long to wait in seconds or 0 to return immediately,
93                      defaults to 100 seconds
94
95         Returns:
96             The config as passed as a dict or None if timeout passed is 0
97
98         Raises:
99             NfvbenchException: the execution of the passed configuration failed,
100                                the body of the exception
101                                containes the description of the failure.
102             TimeOutException: the request timed out (and might still being executed
103                               by the server)
104         """
105         if self.use_socketio:
106             return self.socketio_send('echo', 'echo', config, timeout)
107         return self.http_get('echo', config)
108
109     def run_config(self, config, timeout=300, poll_interval=5):
110         """Request an nfvbench configuration to be executed by the nfvbench server.
111
112         This function will block the caller until the request completes or the request times out.
113         It can return immediately if timeout is set to 0.
114         Note that running a configuration may take a while depending on the amount of work
115         requested - so set the timeout value to an appropriate value.
116
117         Args:
118             config: the nfvbench configuration to execute - must be a valid dict with
119                     valid nfvbench attributes
120             timeout: how long to wait in seconds or 0 to return immediately,
121                      defaults to 300 seconds
122             poll_interval: seconds between polling (http only) - defaults to every 5 seconds
123
124         Returns:
125             The result of the nfvbench execution
126             or None if timeout passed is 0
127             The function will return as soon as the request is completed or when the
128             timeout occurs (whichever is first).
129
130         Raises:
131             NfvbenchException: the execution of the passed configuration failed, the body of
132                                the exception contains the description of the failure.
133             TimeOutException: the request timed out but will still be executed by the server.
134         """
135         if self.use_socketio:
136             return self.socketio_send('start_run', 'run_end', config, timeout)
137         res = self.http_post('start_run', config)
138         if res['status'] != 'PENDING':
139             raise NfvbenchException(res['error_message'])
140
141         # poll until request completes
142         elapsed = 0
143         while True:
144             time.sleep(poll_interval)
145             result = self.http_get('status', config)
146             if result['status'] != 'PENDING':
147                 return result
148             elapsed += poll_interval
149             if elapsed >= timeout:
150                 raise TimeOutException()