Gabe Black | 9062322 | 2017-01-18 19:52:28 +0000 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | import requests, sys, getopt, json |
| 3 | |
| 4 | COMMANDS = [ 'show','reset', 'add','delete','deploy',"V_BUFS","NUM_BUFS", "INPUT_MODE", "TX_MODE", "QUEUE_TYPE" ] |
| 5 | trafficTypes = ['TSA_CP','TSA_UP', 'TAA_CP', 'TAA_UP'] |
| 6 | INPUT_MODES=["mmap","pfring","pfring_zc","dpdk"] |
| 7 | TX_MODES=["frp_udp","frp_tcp","viv"] |
| 8 | QUEUE_TYPES=["CLFFIFO","dpdk"] |
| 9 | RESOURCE_NAMES = [ 'V_BUFS', 'NUM_BUFS', 'INPUT_MODE', 'TX_MODE', 'QUEUE_TYPE'] |
| 10 | |
| 11 | settings = { |
| 12 | 'ipAddress':'127.0.0.1', |
| 13 | 'port':'8080', |
| 14 | 'api_version':'v1.0', |
| 15 | 'resource': 'vivs/1', |
| 16 | 'operation':'GET', |
| 17 | 'verbose': False, |
| 18 | 'data': None |
| 19 | } |
| 20 | |
| 21 | class restClient: |
| 22 | |
| 23 | def doIt( self, settings ): |
| 24 | try: |
| 25 | hdrs = { 'Accept':'application/json','content-type':'application/json' } |
| 26 | url = "http://%s:%s/%s" % ( settings['ipAddress'], settings['port'], settings['api_version'] ) |
| 27 | if settings['resource']: |
| 28 | url = "%s/%s" % (url, settings['resource']) |
| 29 | |
| 30 | if settings['operation'] == 'GET': |
| 31 | r = requests.get( url, headers = hdrs ) |
| 32 | elif settings['operation'] == 'POST': |
| 33 | data = json.loads(settings['data']) |
| 34 | r = requests.post( url, data=json.dumps(data), headers = hdrs ) |
| 35 | |
| 36 | if r.status_code == requests.codes.ok: |
| 37 | if r.headers['content-type'] == 'application/json': |
| 38 | print json.dumps( r.json(), indent=4 ) |
| 39 | else: |
| 40 | print "Received unexpected content type: %s" % r.headers['content-type'] |
| 41 | if settings['verbose']: |
| 42 | print r.text |
| 43 | |
| 44 | if settings['verbose']: |
| 45 | print "\nOperation:\n %s" % settings['operation'] |
| 46 | print "\nURL:\n %s" % r.url |
| 47 | print "\nHeaders sent:\n %s" % r.request.headers |
| 48 | print "\nResponse status code:\n %s" % r.status_code |
| 49 | |
| 50 | except requests.ConnectionError as e: |
| 51 | print e |
| 52 | raise # re-raise exception |
| 53 | except ValueError as e: |
| 54 | print "Invalid JSON: %s" % e |
| 55 | raise # re-raise exception |
| 56 | |
| 57 | |
| 58 | def stringFromList( p ): |
| 59 | """ |
| 60 | e.g. ['a', 'b', 'c' ] becomes "[a|b|c]" |
| 61 | """ |
| 62 | return str( p ).replace("'","").replace(", ","|") |
| 63 | |
| 64 | def usage(): |
| 65 | print "Usage:" |
| 66 | print " $ %s [-i ip][-p port][-a version][-v] command" % sys.argv[0] |
| 67 | print "" |
| 68 | print "optional arguments:" |
| 69 | print " -i <ip> IP address of server. (Default: 127.0.0.1)" |
| 70 | print " -p <port> Port on server. (Default: 8080)" |
| 71 | print " -a <version> API version to use. (Default: v1.0)" |
| 72 | print " -v Be verbose" |
| 73 | print "" |
| 74 | print "command" |
| 75 | print "-------" |
| 76 | print " show [<path>]" |
| 77 | print " add input <device> <type> [<type> [...]]" |
| 78 | print " add output <ip_address> <port> <type>" |
| 79 | print " delete input <device> [<type> [<type> [...]]]" |
| 80 | print " delete output <ip_address>[:<port>] [<type> [<type> [...]]]" |
| 81 | print " reset" |
| 82 | print " deploy" |
| 83 | print "" |
| 84 | print " V_BUFS <value>" |
| 85 | print " NUM_BUFS <value>" |
| 86 | print " INPUT_MODE <input-mode>" |
| 87 | print " TX_MODE <tx-mode>" |
| 88 | print " QUEUE_TYPE <queue-type>" |
| 89 | print "" |
| 90 | print "" |
| 91 | print " Where:" |
| 92 | print " <type> = %s" % stringFromList( trafficTypes ) |
| 93 | print " <input_mode> = %s" % stringFromList(INPUT_MODES ) |
| 94 | print " <tx-mode> = %s" % stringFromList( QUEUE_TYPES ) |
| 95 | print "" |
| 96 | |
| 97 | |
| 98 | def getTrafficTypes( args ): |
| 99 | traffic_types=[] |
| 100 | while len(args) > 0: |
| 101 | t = args.pop(0) |
| 102 | if t not in trafficTypes: |
| 103 | raise ValueError("Invalid traffic type '%s'" % t ) |
| 104 | traffic_types.append( t ) |
| 105 | return traffic_types |
| 106 | |
| 107 | def parseAddInputCommand( args ): |
| 108 | if len( args ) < 2: |
| 109 | raise ValueError("Usage: %s add input <device> <traffic_type> [<traffic_type> [...]]" % sys.argv[0] ) |
| 110 | |
| 111 | device = args.pop(0) |
| 112 | tt = getTrafficTypes( args ) |
| 113 | data = { "inputs":[{"device":device,"traffic_types":tt}]} |
| 114 | settings['resource']='vivs/1/add' |
| 115 | settings['operation']='POST' |
| 116 | settings['data'] = json.dumps( data ) |
| 117 | |
| 118 | def parseAddOutputCommand( args ): |
| 119 | if len( args ) != 3: |
| 120 | raise ValueError("Usage: %s add output <ip_address> <port> <traffic_type>" % sys.argv[0] ) |
| 121 | |
| 122 | ip_address = args.pop(0) |
| 123 | port = args.pop(0) |
| 124 | traffic_type = args.pop(0) |
| 125 | if traffic_type not in trafficTypes: |
| 126 | raise ValueError("Invalid traffic type '%s'" % traffic_type ) |
| 127 | |
| 128 | data = {"outputs":[{"ip_address":ip_address,"type":traffic_type,"port":port}]} |
| 129 | settings['resource']='vivs/1/add' |
| 130 | settings['operation']='POST' |
| 131 | settings['data'] = json.dumps( data ) |
| 132 | |
| 133 | def parseDeleteInputCommand( args ): |
| 134 | if len( args ) < 1: |
| 135 | raise ValueError( "Usage: %s delete input <device> [<traffic_type> [<traffic_type> [...]]]" % sys.argv[0] ) |
| 136 | |
| 137 | device = args.pop(0) |
| 138 | tt = getTrafficTypes( args ) |
| 139 | data = {"inputs":[{"device":device,"traffic_types":tt}]} |
| 140 | settings['resource']='vivs/1/delete' |
| 141 | settings['operation']='POST' |
| 142 | settings['data'] = json.dumps( data ) |
| 143 | |
| 144 | def parseDeleteOutputCommand( args ): |
| 145 | if len(args) == 0: |
| 146 | raise ValueError( "Usage: %s delete output <ip_address>[:<port>] [<traffic_type> [<traffic_type> [...]]]" % sys.argv[0] ) |
| 147 | |
| 148 | ipp = args.pop(0).split(':') |
| 149 | ip_address = ipp[0] |
| 150 | try: |
| 151 | port = ipp[1] |
| 152 | except IndexError: |
| 153 | # No port was specified |
| 154 | # All ports with spec'd traffic types will be removed for |
| 155 | # the IP given. |
| 156 | port = None |
| 157 | |
| 158 | tt = getTrafficTypes( args ) |
| 159 | data = {"outputs":[{"ip_address":ip_address,"port":port, "traffic_types":tt}]} |
| 160 | settings['resource']='vivs/1/delete' |
| 161 | settings['operation']='POST' |
| 162 | settings['data'] = json.dumps( data ) |
| 163 | |
| 164 | def parseArgs( argv ): |
| 165 | try: |
| 166 | opts,args = getopt.getopt( argv, |
| 167 | "i:p:a:vh", ["ip=","port=","api_version="]) |
| 168 | except getopt.GetoptError as e: |
| 169 | print e |
| 170 | raise # re-raise exception |
| 171 | for opt,arg in opts: |
| 172 | if opt == '-h': |
| 173 | usage() |
| 174 | sys.exit() |
| 175 | elif opt == '-v': |
| 176 | settings['verbose'] = True |
| 177 | elif opt in ("-i","--ip"): |
| 178 | settings['ipAddress'] = arg |
| 179 | elif opt in ("-p","--port"): |
| 180 | settings['port'] = arg |
| 181 | elif opt in ("-a","--api_version"): |
| 182 | settings['api_version'] = arg |
| 183 | |
| 184 | # process residual non option args |
| 185 | if len(args) == 0: |
| 186 | raise ValueError( "Expected one of: %s" % str( COMMANDS ) ) |
| 187 | |
| 188 | cmd = args.pop(0) |
| 189 | if cmd not in COMMANDS: |
| 190 | print 'Unknown command', cmd |
| 191 | sys.exit(1) |
| 192 | |
| 193 | if cmd in ['show']: |
| 194 | if len(args) != 0: |
| 195 | settings['resource'] = args.pop(0) |
| 196 | |
| 197 | elif cmd in ['reset']: |
| 198 | settings['resource']='vivs/1/reset' |
| 199 | settings['operation'] = 'POST' |
| 200 | settings['data'] = json.dumps( {} ) |
| 201 | |
| 202 | elif cmd in ['add']: |
| 203 | |
| 204 | if len(args) == 0: |
| 205 | raise ValueError("Expected 'input' or 'output'") |
| 206 | |
| 207 | direction = args.pop(0) |
| 208 | if direction not in ['input','output']: |
| 209 | raise ValueError( "expected 'input' or 'output', found '%s'" % direction ) |
| 210 | |
| 211 | if direction == 'input': |
| 212 | parseAddInputCommand( args ) |
| 213 | else: |
| 214 | parseAddOutputCommand( args ) |
| 215 | |
| 216 | elif cmd in ['delete']: |
| 217 | if len(args) == 0: |
| 218 | raise ValueError("Expected 'input' or 'output'" ) |
| 219 | |
| 220 | direction = args.pop(0) |
| 221 | if direction not in ['input','output']: |
| 222 | raise ValueError("expected 'input' or 'output', found '%s'" % direction ) |
| 223 | |
| 224 | if direction == 'input': |
| 225 | parseDeleteInputCommand( args ) |
| 226 | else: |
| 227 | parseDeleteOutputCommand( args ) |
| 228 | |
| 229 | elif cmd in ['deploy']: |
| 230 | settings['resource']='vivs/1/deploy' |
| 231 | settings['operation'] = 'POST' |
| 232 | settings['data'] = '{}' |
| 233 | |
| 234 | else: |
| 235 | |
| 236 | if cmd in RESOURCE_NAMES: |
| 237 | if len( args ) == 0 : |
| 238 | raise ValueError( 'No value supplied' ) |
| 239 | |
| 240 | val = args.pop(0) |
| 241 | # The server will complain if it does not like the value. |
| 242 | settings['resource']='vivs/1/%s' % cmd |
| 243 | settings['operation'] = 'POST' |
| 244 | settings['data'] = json.dumps( { cmd : val } ) |
| 245 | |
| 246 | |
| 247 | return settings |
| 248 | |
| 249 | |
| 250 | def RestClient(argv): |
| 251 | settings = parseArgs( argv ) |
| 252 | client = restClient() |
| 253 | client.doIt( settings ) |
| 254 | |
| 255 | |
| 256 | if __name__ == '__main__': |
| 257 | try: |
| 258 | RestClient(sys.argv[1:]) |
| 259 | except ValueError as e: |
| 260 | print e |
| 261 | sys.exit(2) |
| 262 | except getopt.GetoptError as e: |
| 263 | print e |
| 264 | sys.exit(3) |
| 265 | except requests.ConnectionError as e: |
| 266 | print e |
| 267 | sys.exit(4) |
| 268 | |