aboutsummaryrefslogtreecommitdiffstats
path: root/vnfmgr/vnfmgr_odl/vnfmgr_odl.py
blob: 6ac72b28de8db3214fb4edea11627872d87089fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
#!/usr/bin/env python

import pdb
import os
import time
import requests
import json
import argparse

__author__ = "Brady Johnson"
__copyright__ = "Copyright(c) 2015, Ericsson, Inc."
__license__ = "Apache License version 2.0"
__version__ = "0.1"
__email__ = "brady.allen.johnson@ericsson.com"
__status__ = "beta"


PUT = 'PUT'
GET = 'GET'
POST = 'POST'


class Context(object):
    """
    Context class to hold the configuration as specified on the command line
    """

    def __init__(self):
        self.rest_path_prefix = 'sampleConfig'
        self.rest_path_sf = 'RestConf-SFs-HttpPut.json'
        self.rest_path_sf_sel = 'RestConf-SFselect-HttpPut.json'
        self.rest_path_sfc = 'RestConf-SFCs-HttpPut.json'
        self.rest_path_sff = 'RestConf-SFFs-HttpPut.json'
        self.rest_path_sfp = 'RestConf-SFPs-HttpPut.json'
        self.rest_path_acl = 'RestConf-ACLs-HttpPut.json'
        self.rest_path_rsp = 'RestConf-RSP-HttpPost.json'

        self.rest_url_sf = 'config/service-function:service-functions/'
        self.rest_url_sf_sel = ('config/service-function-scheduler-type:'
                                'service-function-scheduler-types/')
        self.rest_url_sfc = (
            'config/service-function-chain:service-function-chains/')
        self.rest_url_sff = (
            'config/service-function-forwarder:service-function-forwarders/')
        self.rest_url_sfp = (
            'config/service-function-path:service-function-paths/')
        self.rest_url_rsp = (
            'operational/rendered-service-path:rendered-service-paths/')
        self.rest_url_rsp_rpc = (
            'operations/rendered-service-path:create-rendered-path')
        self.rest_url_acl = ('config/ietf-acl:access-lists/')

        self.http_headers = {
            'Content-Type': 'application/json', 'Cache-Control': 'no-cache'}
        self.http_server = 'localhost'
        self.url_base = ''
        self.http_port = '8181'
        self.interractive = True
        self.user = 'admin'
        self.pw = 'admin'
        self.batch_sf = False
        self.batch_sf_sel = False
        self.batch_sfc = False
        self.batch_sff = False
        self.batch_sfp = False
        self.batch_acl = False
        self.batch_rsp = False
        self.batch_query = False

    def set_path_prefix_paths(self, path_prefix):
        self.rest_path_prefix = path_prefix
        self.rest_path_sf = os.path.join(
            self.rest_path_prefix, self.rest_path_sf)
        self.rest_path_sf_sel = os.path.join(
            self.rest_path_prefix, self.rest_path_sf_sel)
        self.rest_path_sfc = os.path.join(
            self.rest_path_prefix, self.rest_path_sfc)
        self.rest_path_sff = os.path.join(
            self.rest_path_prefix, self.rest_path_sff)
        self.rest_path_sfp = os.path.join(
            self.rest_path_prefix, self.rest_path_sfp)
        self.rest_path_acl = os.path.join(
            self.rest_path_prefix, self.rest_path_acl)
        self.rest_path_rsp = os.path.join(
            self.rest_path_prefix, self.rest_path_rsp)


def get_cmd_line(context):
    """
    Create a command-line parser, parse the command line args, and process
    them.
    Populate the Context object with the processed command-line args.
    """

    opts = argparse.ArgumentParser()

    # Batch or Interractive mode
    opts.add_argument('--interractive', '-i',
                      dest='interractive',
                      action='store_true',
                      help='Interractive mode, default')
    opts.add_argument('--batch', '-b',
                      dest='batch',
                      action='store_true',
                      help='Batch mode, overrides interractive mode')

    # Where to send the messages
    opts.add_argument('--http-server', '-s',
                      default=context.http_server,
                      dest='http_server',
                      help='HTTP server address')
    opts.add_argument('--http-port',
                      default=context.http_port,
                      dest='http_port',
                      help='HTTP server port')

    # Batch mode, which message(s) to send
    opts.add_argument('--send-sf', '-1',
                      dest='send_sf',
                      action='store_true',
                      help='Send an SF REST JSON PUT message')
    opts.add_argument('--send-sf-sel',
                      dest='send_sf_sel',
                      action='store_true',
                      help='Send an SF Selection REST JSON PUT message')
    opts.add_argument('--send-sfc', '-2',
                      dest='send_sfc',
                      action='store_true',
                      help='Send an SFC REST JSON PUT message')
    opts.add_argument('--send-sff', '-3',
                      dest='send_sff',
                      action='store_true',
                      help='Send an SFF REST JSON PUT message')
    opts.add_argument('--send-sfp', '-4',
                      dest='send_sfp',
                      action='store_true',
                      help='Send an SFP REST JSON PUT message')
    opts.add_argument('--send-acl', '-5',
                      dest='send_acl',
                      action='store_true',
                      help='Send an ACL REST JSON PUT message')
    opts.add_argument('--send-rsp', '-6',
                      dest='send_rsp',
                      action='store_true',
                      help='Send an RSP REST JSON POST RPC message')
    opts.add_argument('--send-all', '-7',
                      dest='send_all',
                      action='store_true',
                      help=('Send all (SF, SFF, SFC, SFP, RSP, ACL) '
                            'REST JSON messages'))
    opts.add_argument('--query-sfc', '-q',
                      dest='query_sfc',
                      action='store_true',
                      help='Query all SFC objects')

    # Paths to the rest JSON files
    opts.add_argument('--rest-path-prefix', '-prefix',
                      default=context.rest_path_prefix,
                      dest='rest_path_prefix',
                      help='Path prefix where the REST JSON files are located')
    opts.add_argument('--rest-path-sf-sel',
                      default=context.rest_path_sf_sel,
                      dest='rest_path_sf_sel',
                      help=('Name of the SF Selection REST JSON file, '
                            'relative to configured prefix'))
    opts.add_argument('--rest-path-sf', '-n',
                      default=context.rest_path_sf,
                      dest='rest_path_sf',
                      help=('Name of the SF REST JSON file, relative to '
                            'configured prefix'))
    opts.add_argument('--rest-path-sfc', '-c',
                      default=context.rest_path_sfc,
                      dest='rest_path_sfc',
                      help=('Name of the SFC REST JSON file, relative to '
                            'configured prefix'))
    opts.add_argument('--rest-path-sff', '-f',
                      default=context.rest_path_sff,
                      dest='rest_path_sff',
                      help=('Name of the SFF REST JSON file, relative '
                            'to configured  prefix'))
    opts.add_argument('--rest-path-sfp', '-p',
                      default=context.rest_path_sfp,
                      dest='rest_path_sfp',
                      help=('Name of the SFP REST JSON file, relative '
                            'to configured prefix'))
    opts.add_argument('--rest-path-rsp', '-r',
                      default=context.rest_path_rsp,
                      dest='rest_path_rsp',
                      help=('Name of the RSP REST JSON file, relative '
                            'to configured prefix'))
    opts.add_argument('--rest-path-acl', '-a',
                      default=context.rest_path_acl,
                      dest='rest_path_acl',
                      help=('Name of the ACL REST JSON file, relative '
                            'to configured prefix'))

    args = opts.parse_args()

    context.http_server = args.http_server
    context.http_port = args.http_port
    context.url_base = 'http://%s:%s/restconf/' % (
        context.http_server, context.http_port)

    context.rest_path_prefix = args.rest_path_prefix
    context.rest_path_sf = args.rest_path_sf
    context.rest_path_sf_sel = args.rest_path_sf_sel
    context.rest_path_sfc = args.rest_path_sfc
    context.rest_path_sff = args.rest_path_sff
    context.rest_path_sfp = args.rest_path_sfp
    context.rest_path_acl = args.rest_path_acl
    context.rest_path_rsp = args.rest_path_rsp
    context.set_path_prefix_paths(context.rest_path_prefix)

    for path in [context.rest_path_sf,
                 context.rest_path_sfc,
                 context.rest_path_sff,
                 context.rest_path_sfp]:
        print '\tUsing REST file: %s' % path

    if args.batch:
        context.interractive = False
        if args.send_all:
            context.batch_sf = True
            context.batch_sf_sel = True
            context.batch_sfc = True
            context.batch_sff = True
            context.batch_sfp = True
            context.batch_rsp = True
            # TODO deactivated for now
            # context.batch_acl      =  True
        else:
            context.batch_sf = args.send_sf
            context.batch_sf_sel = args.send_sf_sel
            context.batch_sfc = args.send_sfc
            context.batch_sff = args.send_sff
            context.batch_sfp = args.send_sfp
            context.batch_rsp = args.send_rsp
            # TODO deactivated for now
            # context.batch_acl      =  args.send_acl
            context.batch_query = args.query_sfc

    return True


def send_rest(context, operation, rest_url, rest_file=None):
    """
    Send an HTTP REST message
    Keyword arguments:
    context -- specifies the destination IP/Port and user/pw
    operation -- specifies if the HTTP OP is one of: GET, PUT, or POST
    rest_url -- the operation URL
    rest_file -- for PUT and POST operations, specifies where the JSON
    input is found
    """

    complete_url = '%s%s' % (context.url_base, rest_url)

    if rest_file:
        if not os.path.exists(rest_file):
            print 'REST file [%s] does not exists' % rest_file
            return False

    try:
        if operation == GET:
            r = requests.get(url=complete_url,
                             headers=context.http_headers,
                             auth=(context.user, context.pw))

            print '\nHTTP GET %s\nresult: %s' % (rest_url, r.status_code)
            # if len(r.text) > 1:
            if r.status_code >= 200 and r.status_code <= 299:
                print json.dumps(json.loads(r.text),
                                 indent=4,
                                 separators=(',', ': '))

        elif operation == PUT:
            if not rest_file:
                print 'ERROR trying to PUT with empty REST file'
                return False

            r = requests.put(url=complete_url,
                             auth=(context.user, context.pw),
                             data=json.dumps(json.load(open(rest_file, 'r'))),
                             headers=context.http_headers)
            print '\nHTTP PUT %s\nresult: %s' % (rest_url, r.status_code)

        elif operation == POST:
            if not rest_file:
                print 'ERROR trying to POST with empty REST file'
                return False

            post_list = json.load(open(rest_file, 'r'))
            if len(post_list) > 1:
                # This allows for multiple RSPs to be sent from one JSON file
                for entry in post_list:
                    r = requests.post(url=complete_url,
                                      auth=(context.user, context.pw),
                                      data=json.dumps(entry),
                                      headers=context.http_headers)
                    print '\nHTTP POST %s\nresult: %s' % (rest_url,
                                                          r.status_code)
            else:
                r = requests.post(url=complete_url,
                                  auth=(context.user, context.pw),
                                  data=json.dumps(post_list),
                                  headers=context.http_headers)
                print '\nHTTP POST %s\nresult: %s' % (rest_url,
                                                      r.status_code)
        else:
            print 'ERROR: Invalid Operation: %s' % (operation)

    except requests.exceptions.ConnectionError as ce:
        print 'ERROR connecting: %s' % (ce)
        return False
    except Exception as e:
        print 'ERROR Exception: %s' % (e)
        return False
    except:
        print 'ERROR unkown exception raised'
        return False

    return True


def validate_rest(context):
    """
    For each JSON input file in context, validate the JSON syntax.
    No validation checking is made on parameter names or types.
    """

    print ''
    for path in [context.rest_path_sf,
                 context.rest_path_sfc,
                 context.rest_path_sff,
                 context.rest_path_sfp,
                 context.rest_path_rsp,
                 context.rest_path_sf_sel]:
        if os.path.exists(path):
            print 'Validating JSON file: %s' % path
            try:
                json.load(open(path, 'r'))
            except ValueError as ve:
                print '\tValidation error [%s]' % ve
                return False

    return True


def batch(context):
    """
    Launch the application in batch mode and perform
    the operations as specified in the Context object.
    """

    # The order of these if's is important
    # If send-all was set, then each of these needs to be sent, in order
    if context.batch_sf_sel:
        send_rest(
            context, PUT, context.rest_url_sf_sel, context.rest_path_sf_sel)
    if context.batch_sf:
        send_rest(context, PUT, context.rest_url_sf, context.rest_path_sf)
    if context.batch_sff:
        send_rest(context, PUT, context.rest_url_sff, context.rest_path_sff)
    if context.batch_sfc:
        send_rest(context, PUT, context.rest_url_sfc, context.rest_path_sfc)
    if context.batch_sfp:
        send_rest(context, PUT, context.rest_url_sfp, context.rest_path_sfp)
    if context.batch_rsp:
        send_rest(
            context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
    if context.batch_acl:
        send_rest(context, PUT, context.rest_url_acl, context.rest_path_acl)

    if context.batch_query:
        send_rest(context, GET, context.rest_url_sf_sel)
        send_rest(context, GET, context.rest_url_sf)
        send_rest(context, GET, context.rest_url_sff)
        send_rest(context, GET, context.rest_url_sfc)
        send_rest(context, GET, context.rest_url_sfp)
        send_rest(context, GET, context.rest_url_rsp)
        # TODO deactivated for now
        # send_rest(context, GET, context.rest_url_acl)


def CLI(context):
    """
    Run a simple Command Line Interface.
    The Context object is used for sending rest messages
    """

    option = '1'
    while option != '0':
        print '\n\nChoose Option to perform:'
        print ' 0) Quit'
        print ' 1) Send SF  REST'
        print ' 2) Send SFC REST'
        print ' 3) Send SFF REST'
        print ' 4) Send SFP REST'
        print ' 5) Send RSP REST'
        print ' 6) Send ACL REST'
        print ' 7) Send all ordered: (SFsel, SF, SFF, SFC, SFP, RSP)'
        print ' 8) Query all: (SFsel, SF, SFF, SFC, SFP, RSP)'
        print(' 9) Change config file path, currently [%s]' % (
            context.rest_path_prefix))
        print '10) Validate config files JSON syntax'

        option = raw_input('=> ')

        if option == '1':
            send_rest(context, PUT, context.rest_url_sf, context.rest_path_sf)
        elif option == '2':
            send_rest(
                context, PUT, context.rest_url_sfc, context.rest_path_sfc)
        elif option == '3':
            send_rest(
                context, PUT, context.rest_url_sff, context.rest_path_sff)
        elif option == '4':
            send_rest(
                context, PUT, context.rest_url_sfp, context.rest_path_sfp)
        elif option == '5':
            send_rest(
                context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
        elif option == '6':
            send_rest(
                context, PUT, context.rest_url_acl, context.rest_path_acl)
        elif option == '7':
            pdb.set_trace()
            send_rest(
                context, PUT, context.rest_url_sf_sel,
                context.rest_path_sf_sel)
            send_rest(context, PUT, context.rest_url_sf, context.rest_path_sf)
            send_rest(
                context, PUT, context.rest_url_sff, context.rest_path_sff)
            send_rest(
                context, PUT, context.rest_url_sfc, context.rest_path_sfc)
            send_rest(
                context, PUT, context.rest_url_sfp, context.rest_path_sfp)
            time.sleep(1)
            send_rest(
                context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
            # TODO ACL deactivated for now
            # Need to wait until the SFC creates the RSP internally
            # before sending the ACL
            # print 'Sleeping 2 seconds while RSP being created'
            # time.sleep(2);
            # send_rest(context, PUT, context.rest_url_acl,
            # context.rest_path_acl)
        elif option == '8':
            send_rest(context, GET, context.rest_url_sf_sel)
            send_rest(context, GET, context.rest_url_sf)
            send_rest(context, GET, context.rest_url_sff)
            send_rest(context, GET, context.rest_url_sfc)
            send_rest(context, GET, context.rest_url_sfp)
            send_rest(context, GET, context.rest_url_rsp)
            send_rest(context, GET, context.rest_url_acl)
        elif option == '9':
            path_prefix = raw_input('Enter path => ')
            if not os.path.exists(path_prefix):
                print 'ERROR: path does not exist: [%s]' % (path_prefix)
            else:
                context.set_path_prefix_paths(path_prefix)
        elif option == '10':
            validate_rest(context)
        elif option != '0':
            print 'ERROR: Invalid option %s' % (option)


def main():
    """
    Main entry point into the VnfMgrSim application.
    Command line arguments are expected.
    Example invocations:
    To display application command-line help:
        vnfmgr_odl.py --help
    To start the application in interractive mode:
        vnfmgr_odl.py -prefix <input json dir>
    To start the application in batch mode and send an SF JSON REST message:
        vnfmgr_odl.py -b -prefix <input json dir> --send-sf
    """

    context = Context()
    if not get_cmd_line(context):
        return 1

    if context.interractive:
        CLI(context)
    else:
        batch(context)

    return 0

if __name__ == '__main__':
    main()