Radek Krejci | d23f0df | 2017-08-31 16:34:49 +0200 | [diff] [blame] | 1 | """ |
| 2 | Manipulation with the YANG schemas. |
| 3 | File: schemas.py |
| 4 | Author: Radek Krejci <rkrejci@cesnet.cz> |
| 5 | """ |
| 6 | |
| 7 | from liberouterapi import auth, config |
| 8 | from flask import request |
| 9 | import libyang as ly |
| 10 | import json |
| 11 | import os, errno, time |
| 12 | |
| 13 | from .error import NetopeerException |
| 14 | |
| 15 | __INVENTORY = config.modules['netopeer']['usersdata_path'] |
| 16 | __SCHEMAS_EMPTY = '{"schemas":{"timestamp":0,"schema":[]}}' |
| 17 | |
| 18 | def __schema_parse(path): |
| 19 | try: |
| 20 | ctx = ly.Context() |
| 21 | except Exception as e: |
| 22 | raise NetopeerException(str(e)) |
| 23 | |
| 24 | return(ctx.parse_path(path, ly.LYS_IN_YANG, 0)) |
| 25 | |
| 26 | |
| 27 | def __schemas_init(): |
| 28 | schemas = json.loads(__SCHEMAS_EMPTY) |
| 29 | try: |
| 30 | ctx = ly.Context() |
| 31 | except Exception as e: |
| 32 | raise NetopeerException(str(e)) |
| 33 | |
| 34 | # initialize the list with libyang's internal modules |
| 35 | modules = ctx.get_module_iter() |
| 36 | for module in modules: |
| 37 | schemas['schemas']['schema'].append({'name':module.name(),'revision':module.rev().date()}) |
| 38 | return schemas |
| 39 | |
| 40 | |
| 41 | def __schemas_update(path): |
| 42 | schemainv_path = os.path.join(path, '/schemas.json') |
| 43 | try: |
| 44 | with open(schemainv_path, 'r') as schemas_file: |
| 45 | schemas = json.load(schemas_file) |
| 46 | except OSError as e: |
| 47 | if e.errno == errno.ENOENT: |
| 48 | schemas = __schemas_init() |
| 49 | else: |
| 50 | raise NetopeerException('Unable to use user\'s schemas inventory ' + schemainv_path + ' (' + str(e) + ').') |
| 51 | except ValueError: |
| 52 | schemas = __schemas_init() |
| 53 | |
| 54 | # get the previous timestamp |
| 55 | timestamp = schemas['schemas']['timestamp'] |
| 56 | |
| 57 | # check the current content of the storage |
| 58 | for file in os.listdir(path): |
| 59 | if file[-4] != 'yang': |
| 60 | continue |
| 61 | |
| 62 | schemapath = os.path.join(path, file); |
| 63 | print(schemapath) |
| 64 | if os.path.getmtime(schemapath) > timestamp: |
| 65 | # update the list |
| 66 | try: |
| 67 | module = __schema_parse(schemapath) |
| 68 | schemas['schemas']['schema'].append({'name':module.name(),'revision':module.rev().date()}) |
| 69 | except Exception: |
| 70 | pass |
| 71 | |
| 72 | # update the timestamp |
| 73 | schemas['schemas']['timestamp'] = time.time() |
| 74 | |
| 75 | #store the list |
| 76 | try: |
| 77 | with open(schemainv_path, 'w') as schema_file: |
| 78 | json.dump(schemas, schema_file) |
| 79 | except Exception: |
| 80 | pass |
| 81 | |
| 82 | # return the up-to-date list |
| 83 | return schemas['schemas']['schema'] |
| 84 | |
| 85 | def __schemas_check(path): |
| 86 | try: |
| 87 | os.makedirs(path, mode=0o750) |
| 88 | except OSError as e: |
| 89 | if e.errno == errno.EEXIST and os.path.isdir(path): |
| 90 | pass |
| 91 | elif e.errno == errno.EEXIST: |
| 92 | raise NetopeerException('User\'s schemas inventory (' + path + ') already exists and it\'s not a directory.') |
| 93 | else: |
| 94 | raise NetopeerException('Unable to use schemas inventory path ' + path +' (' + str(e) + ').') |
| 95 | |
| 96 | |
| 97 | @auth.required() |
| 98 | def schemas_list(): |
| 99 | session = auth.lookup(request.headers.get('Authorization', None)) |
| 100 | user = session['user'] |
| 101 | path = os.path.join(__INVENTORY, user.username) |
| 102 | |
| 103 | __schemas_check(path) |
| 104 | schemas = __schemas_update(path) |
| 105 | |
| 106 | return(json.dumps(schemas)) |
| 107 | |
| 108 | @auth.required() |
| 109 | def schemas_add(): |
| 110 | if 'schema' not in request.files: |
| 111 | raise NetopeerException('Missing schema file in upload request.') |
| 112 | |
| 113 | session = auth.lookup(request.headers.get('Authorization', None)) |
| 114 | user = session['user'] |
| 115 | file = request.files['schema'] |
| 116 | |
| 117 | # store the file |
| 118 | path = os.path.join(__INVENTORY, user.username, file.filename) |
| 119 | file.save(path) |
| 120 | |
| 121 | # parse file |
| 122 | try: |
| 123 | module = __schema_parse(path) |
| 124 | except Exception: |
| 125 | os.remove(path) |
| 126 | return(json.dumps({'success': False})) |
| 127 | |
| 128 | return(json.dumps({'success': True})) |