def devices_add(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) device = request.get_json() if not device or not device['id']: raise NetopeerException('Invalid device remove request.') devices = __devices_inv_load(path) for dev in devices['device']: if dev['id'] == device['id']: return (json.dumps({'success': False})) device_json = {'id':device['id'], 'name':device['name'], 'hostname':device['hostname'], 'port':device['port'], 'autoconnect':device['autoconnect'], 'username':device['username']} if 'password' in device and device['password']: device_json['password'] = device['password'] devices['device'].append(device_json) #store the list __devices_inv_save(path, devices) return(json.dumps({'success': True}))
def session_get(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] req = request.args.to_dict() if not 'key' in req: return(json.dumps({'success': False, 'error-msg': 'Missing session key.'})) if not 'recursive' in req: return(json.dumps({'success': False, 'error-msg': 'Missing recursive flag.'})) if not user.username in sessions: sessions[user.username] = {} key = req['key'] if not key in sessions[user.username]: return(json.dumps({'success': False, 'error-msg': 'Invalid session key.'})) try: sessions[user.username][key]['data'] = sessions[user.username][key]['session'].rpcGet() except ConnectionError as e: reply = {'success': False, 'error': [{'msg': str(e)}]} del sessions[user.username][key] return(json.dumps(reply)) except nc.ReplyError as e: reply = {'success': False, 'error': []} for err in e.args[0]: reply['error'].append(json.loads(str(err))) return(json.dumps(reply)) if not 'path' in req: return(dataInfoRoots(sessions[user.username][key]['data'], True if req['recursive'] == 'true' else False)) else: return(dataInfoSubtree(sessions[user.username][key]['data'], req['path'], True if req['recursive'] == 'true' else False))
def schemas_rm(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) key = request.get_json() if not key: raise NetopeerException('Invalid schema remove request.') schemas = __schemas_inv_load(path) try: schemas['schemas'].pop(key) except KeyError: # schema not in inventory return (json.dumps({'success': False})) # update the inventory database __schemas_inv_save(path, schemas) # remove the schema file try: os.remove(os.path.join(path, key)) except Exception as e: print(e) # TODO: resolve dependencies ? return (json.dumps({'success': True}))
def session_destroy_all(): global sessions session = auth.lookup(request.headers.get('lgui-Authorization', None)) username = str(session['user'].username) if username in sessions: del sessions[username] return json.dumps({'success': True, 'code': 200})
def devices_rm(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) rm_id = request.get_json()['id'] if not rm_id: raise NetopeerException('Invalid device remove request.') devices = __devices_inv_load(path) for i in range(len(devices['device'])): device = devices['device'][i] if device['id'] == rm_id: devices['device'].pop(i) device = None break if device: # device not in inventory return (json.dumps({'success': False})) # update the inventory database __devices_inv_save(path, devices) return(json.dumps({'success': True}))
def session_get_capabilities(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] req = request.args.to_dict() if not 'key' in req: return (json.dumps({ 'success': False, 'error-msg': 'Missing session key.' })) if not user.username in sessions: sessions[user.username] = {} key = req['key'] if not key in sessions[user.username]: return (json.dumps({ 'success': False, 'error-msg': 'Invalid session key.' })) cpblts = [] for c in sessions[user.username][key]['session'].capabilities: cpblts.append(c) return (json.dumps({'success': True, 'capabilities': cpblts}))
def schema_get(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] req = request.args.to_dict() path = os.path.join(INVENTORY, user.username) if not 'key' in req: return (json.dumps({ 'success': False, 'error-msg': 'Missing schema key.' })) key = req['key'] schemas = __schemas_inv_load(path) if key in schemas['schemas']: try: with open(os.path.join(path, key), 'r') as schema_file: data = schema_file.read() return (json.dumps({'success': True, 'data': data})) except: pass return (json.dumps({ 'success': False, 'error-msg': 'Schema ' + key + ' not found.' }))
def schemas_list(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) inventory_check(path) schemas = __schemas_update(path) return (json.dumps(schemas, sort_keys=True))
def devices_list(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) inventory_check(path) devices = __devices_inv_load(path) for dev in devices['device']: del dev['password'] return (json.dumps(devices['device']))
def delete_filter(): data = request.json name = data['name'] session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'].username try: filters_coll.delete_one({'name': name, 'user': user}) return json.dumps({"success": True, "errCode": 200}) except Exception: return json.dumps({"success": False, "errCode": 500})
def session_rpc_get(): """ code 500: wrong argument code 404: session invalid -> try reconnecting code 410: connection gone -> remove session, try reconnecting code 418: Error in processing netconf request (nothing to do with a teapot) """ global sessions session = auth.lookup(request.headers.get('lgui-Authorization', None)) username = str(session['user'].username) req = request.args.to_dict() if 'key' not in req: return json.dumps({ 'success': False, 'code': 500, 'message': 'Missing session key.' }) if 'recursive' not in req: return json.dumps({ 'success': False, 'code': 500, 'message': 'Missing recursive flag.' }) if username not in sessions: sessions[username] = {} key = req['key'] if key not in sessions[username]: return json.dumps({ 'success': False, 'code': 404, 'message': 'Invalid session key.' }) try: sessions[username][key]['data'] = sessions[username][key][ 'session'].rpcGet() except ConnectionError as e: del sessions[username][key] return json.dumps({'success': False, 'code': 410, 'message': str(e)}) except nc.ReplyError as e: err_list = [] for err in e.args[0]: err_list.append(str(err)) return json.dumps({'success': False, 'code': 418, 'message': str(e)}) if 'path' not in req: return data_info_roots(sessions[username][key]['data'], True if req['recursive'] == 'true' else False) else: return data_info_subtree(sessions[username][key]['data'], req['path'], True if req['recursive'] == 'true' else False)
def schema_info(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] req = request.args.to_dict() if not 'key' in req: return(json.dumps({'success': False, 'error-msg': 'Missing session key.'})) if not 'path' in req: return(json.dumps({'success': False, 'error-msg': 'Missing path to validate value.'})) key = req['key'] if not key in sessions[user.username]: return(json.dumps({'success': False, 'error-msg': 'Invalid session key.'})) if req['path'] == '/': node = None else: search = sessions[user.username][key]['session'].context.find_path(req['path']) if search.number() != 1: return(json.dumps({'success': False, 'error-msg': 'Invalid data path.'})) node = search.schema()[0] result = []; if 'relative' in req: if req['relative'] == 'children': if node: instantiables = node.child_instantiables(0) else: # top level instantiables = sessions[user.username][key]['session'].context.data_instantiables(0) elif req['relative'] == 'siblings': if node.parent(): instantiables = node.parent().child_instantiables(0) else: # top level instantiables = sessions[user.username][key]['session'].context.data_instantiables(0) else: return(json.dumps({'success': False, 'error-msg': 'Invalid relative parameter.'})) for child in instantiables: if child.flags() & yang.LYS_CONFIG_R: # ignore status nodes continue if child.nodetype() & (yang.LYS_RPC | yang.LYS_NOTIF | yang.LYS_ACTION): # ignore RPCs, Notifications and Actions continue result.append(schemaInfoNode(child)) else: result.append(schemaInfoNode(node)) return(json.dumps({'success': True, 'data': result}))
def edit_user(user_id): """ TODO: differentiate between PUT and PATCH -> PATCH partial update """ user = User.from_dict(request.get_json()) user.id = user_id session_id = request.headers.get('lgui-Authorization', None) session = auth.lookup(session_id) if session["user"].role != Role.admin: # We must check if the user is editing themselves if user_id != session["user"].id: raise UserException( "Insufficient privileges. Non-admin users can edit only themselves", status_code=401) # Create basic query for user updating query = dict() # If the user updates their profile check for all fields to be updated if user.first_name and user.first_name != "": query["first_name"] = user.first_name if user.last_name and user.last_name != "": query["last_name"] = user.last_name if user.email and user.email != "": query["email"] = user.email if user.role != None and user.role >= 0: query["role"] = user.role if user.settings and user.settings != {}: query['settings'] = user.settings # In case of password change, verify that it is really him (revalidate their password) if user.password and user.password != "": query["password"] = auth.create_hash(user.password) if len(query.keys()) == 0: raise UserException("Nothing to update", status_code=400) # Update the user and return updated document res = db.update("users", "id", user.id, query) # Remove password hash from the response del res['password'] return (json.dumps(res))
def connect(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) data = request.get_json() if 'id' in data: # stored device device = devices_get(data['id'], user.username) elif 'device' in data: # one-time connect, the device is specified in request device = data['device'] else: raise NetopeerException('Invalid connection request.') if not device: raise NetopeerException('Unknown device to connect to request.') nc.setSearchpath(path) nc.setSchemaCallback(getschema, session) if 'password' in device: ssh = nc.SSH(device['username'], password = device['password']) else: ssh = nc.SSH(device['username']) ssh.setAuthPasswordClb(auth_password, session['session_id']) ssh.setAuthInteractiveClb(auth_interactive, session['session_id']) ssh.setAuthHostkeyCheckClb(hostkey_check, {'session': session, 'device' : device}) try: ncs = nc.Session(device['hostname'], device['port'], ssh) except Exception as e: nc.setSchemaCallback(None) return(json.dumps({'success': False, 'error-msg': str(e)})) nc.setSchemaCallback(None) if not user.username in sessions: sessions[user.username] = {} # use key (as hostname:port:session-id) to store the created NETCONF session key = ncs.host + ":" + str(ncs.port) + ":" + ncs.id sessions[user.username][key] = {} sessions[user.username][key]['session'] = ncs # update inventory's list of schemas schemas_update(session) return(json.dumps({'success': True, 'session-key': key}))
def session_destroy(key): global sessions session = auth.lookup(request.headers.get('lgui-Authorization', None)) username = str(session['user'].username) if not username in sessions: sessions[username] = {} if key in sessions[username]: del sessions[username][key] return json.dumps({'success': True, 'code': 200}) else: return json.dumps({ 'success': False, 'code': 404, 'message': 'Session not found' })
def load_filter(): data = request.json name = data['name'] session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'].username record = filters_coll.find_one({ 'name': name, 'user': user }, { '_id': 0, 'user': 0 }) print('load', record) return json.dumps(record)
def session_alive(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] req = request.args.to_dict() if not 'key' in req: return(json.dumps({'success': False, 'error-msg': 'Missing session key.'})) if not user.username in sessions: sessions[user.username] = {} key = req['key'] if not key in sessions[user.username]: return(json.dumps({'success': False, 'error-msg': 'Invalid session key.'})) return(json.dumps({'success': True}))
def connect_device(): global sessions session = auth.lookup(request.headers.get('lgui-Authorization', None)) username = str(session['user'].username) data = request.get_json() nc.setSchemaCallback(get_schema, session) site_root = os.path.realpath(os.path.dirname(__file__)) path = os.path.join(site_root, 'userfiles', username) if not os.path.exists(path): os.makedirs(path) nc.setSearchpath(path) if 'password' in data and data['password'] != '': ssh = nc.SSH(data['username'], password=data['password']) else: ssh = nc.SSH(data['username']) ssh.setAuthPasswordClb(auth_password, session['session_id']) ssh.setAuthInteractiveClb(func=auth_interactive, priv={ 'id': session['session_id'], 'device': data }) ssh.setAuthHostkeyCheckClb(hostkey_check, { 'session': session, 'device': data }) try: ncs = nc.Session(data['hostname'], int(data['port']), ssh) except Exception as e: nc.setSchemaCallback(None) return json.dumps({'success': False, 'code': 500, 'message': str(e)}) nc.setSchemaCallback(None) if username not in sessions: sessions[username] = {} # use key (as hostname:port:session-id) to store the created NETCONF session key = ncs.host + ":" + str(ncs.port) + ":" + ncs.id sessions[username][key] = {} sessions[username][key]['session'] = ncs # update inventory's list of schemas # schemas_update(session) return json.dumps({'success': True, 'session-key': key})
def schemas_list(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) schemas = schemas_update(session) result = [] for key in schemas: if 'revision' in schemas[key]: result.append({ 'key': key, 'name': schemas[key]['name'], 'revision': schemas[key]['revision'] }) else: result.append({'key': key, 'name': schemas[key]['name']}) return (json.dumps(result, sort_keys=True))
def sio_login(session_id): if not request.sid in sockets: raise SessionException("Socket already connected.") if sockets[request.sid]['auth']: return if not session_id: raise SessionException("Session ID information not found.") try: session = auth.lookup(session_id) except SessionException: raise SessionException("Session not found") sockets[request.sid]['sid'] = session_id sockets[request.sid]['auth'] = True log.info("SocketIO authorized for session %s (%s)." % (session_id, request.sid))
def get_filter_names(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'].username records = list( filters_coll.aggregate([{ '$group': { '_id': user, 'names': { '$push': '$name' } } }, { '$project': { '_id': 0, 'names': 1 } }])) return json.dumps(records)
def schemas_add(): if 'schema' not in request.files: raise NetopeerException('Missing schema file in upload request.') session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] file = request.files['schema'] # store the file path = os.path.join(INVENTORY, user.username, file.filename) file.save(path) # parse file try: if file.filename[-5:] == '.yang': format = yang.LYS_IN_YANG elif file.filename[-4:] == '.yin': format = yang.LYS_IN_YIN else: format = yang.LYS_IN_UNKNOWN module = __schema_parse(path, format, session) # normalize file name to allow removing without remembering schema path if module.rev_size(): name_norm = module.name() + '@' + module.rev().date() + '.yang' else: name_norm = module.name() + '.yang' if file.filename != name_norm: with open(os.path.join(INVENTORY, user.username, name_norm), 'w') as schema_file: schema_file.write(module.print_mem(yang.LYS_OUT_YANG, 0)) try: os.remove(path) except: pass except Exception: try: os.remove(path) except: pass return (json.dumps({'success': False})) return (json.dumps({'success': True}))
def save_filter(): data = request.json name = data['name'] received_filter = data['filter'] session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'].username filter_doc = {"name": name, "user": user, "filter": received_filter} try: if not received_filter: filters_coll.delete_one({'name': name, 'user': user}) return json.dumps({"success": True, "errCode": 200}) filters_coll.update_one({'name': name}, {'$set': filter_doc}, upsert=True) return json.dumps({"success": True, "errCode": 200}) except Exception: return json.dumps({"success": False, "errCode": 500})
def sessions_get_open(): """ Get all open sessions belonging to the user :return: Array of session keys and devices belonging to sessions. Device names will not be loaded. """ global sessions session = auth.lookup(request.headers.get('lgui-Authorization', None)) username = str(session['user'].username) if username in sessions: result = [] for key in sessions[username].keys(): ncs = sessions[username][key]['session'] device = get_device_from_session_data(ncs.host, ncs.port, username, ncs.user, netconf_coll) if device is not None: result.append({'key': key, 'device': device}) return json.dumps(result) else: return json.dumps([])
def schema_values(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] req = request.args.to_dict() if not 'key' in req: return (json.dumps({ 'success': False, 'error-msg': 'Missing session key.' })) if not 'path' in req: return (json.dumps({ 'success': False, 'error-msg': 'Missing path to validate value.' })) key = req['key'] if not key in sessions[user.username]: return (json.dumps({ 'success': False, 'error-msg': 'Invalid session key.' })) search = sessions[user.username][key]['session'].context.find_path( req['path']) if search.number() != 1: return (json.dumps({ 'success': False, 'error-msg': 'Invalid data path.' })) schema = search.schema()[0] if schema.nodetype( ) != yang.LYS_LEAF and schema.nodetype != yang.LYS_LEAFLIST: result = None else: result = typeValues(schema.subtype().type(), []) return (json.dumps({'success': True, 'data': result}))
def connect(): session = auth.lookup(request.headers.get('Authorization', None)) user = session['user'] path = os.path.join(INVENTORY, user.username) data = request.get_json() if 'id' in data: # stored device device = devices_get(data['id'], user.username) elif 'device' in data: # one-time connect, the device is specified in request device = data['device'] else: raise NetopeerException('Invalid connection request.') if not device: raise NetopeerException('Unknown device to connect to request.') nc.setSearchpath(path) ssh = nc.SSH(device['username'], password=device['password']) ssh.setAuthHostkeyCheckClb(hostkey_check) try: session = nc.Session(device['hostname'], device['port'], ssh) except Exception as e: return (json.dumps({'success': False, 'error-msg': str(e)})) if not user.username in sessions: sessions[user.username] = {} # use key (as hostname:port:session-id) to store the created NETCONF session key = session.host + ":" + str(session.port) + ":" + session.id sessions[user.username][key] = {} sessions[user.username][key]['session'] = session return (json.dumps({'success': True, 'session-key': key}))
def session_commit(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] req = request.get_json(keep_order=True) if 'key' not in req: return json.dumps({ 'success': False, 'code': 500, 'message': 'Missing session key.' }) if 'modifications' not in req: return json.dumps({ 'success': False, 'code': 500, 'message': 'Missing modifications.' }) mods = req['modifications'] ctx = sessions[user.username][req['key']]['session'].context root = None reorders = [] for key in mods: recursion = False # get correct path and value if needed path = key value = None if mods[key]['type'] == 'change': value = mods[key]['value'] elif mods[key]['type'] == 'create' or mods[key]['type'] == 'replace': if mods[key]['data']['info']['type'] == 1: # creating/replacing container recursion = True elif mods[key]['data']['info']['type'] == 4: # creating/replacing leaf value = mods[key]['data']['value'] elif mods[key]['data']['info']['type'] == 8: # creating/replacing leaf-list value = mods[key]['data']['value'][0] path = mods[key]['data']['path'] elif mods[key]['data']['info']['type'] == 16: recursion = True path = mods[key]['data']['path'] elif mods[key]['type'] == 'reorder': # postpone reorders reorders.extend(mods[key]['transactions']) continue # create node # print("creating " + path) # print("value " + str(value)) if root: root.new_path(ctx, path, value, 0, 0) else: try: root = yang.Data_Node(ctx, path, value, 0, 0) except Exception as e: print(e) return json.dumps({ 'success': False, 'code': 404, 'message': 'Path not found in session context.' }) node = root.find_path(path).data()[0] # set operation attribute and add additional data if any if mods[key]['type'] == 'change': node.insert_attr(None, 'ietf-netconf:operation', 'merge') elif mods[key]['type'] == 'delete': node.insert_attr(None, 'ietf-netconf:operation', 'delete') elif mods[key]['type'] == 'create': node.insert_attr(None, 'ietf-netconf:operation', 'create') elif mods[key]['type'] == 'replace': node.insert_attr(None, 'ietf-netconf:operation', 'replace') else: return json.dumps({ 'success': False, 'error-msg': 'Invalid modification ' + key }) if recursion and 'children' in mods[key]['data']: for child in mods[key]['data']['children']: if 'key' in child['info'] and child['info']['key']: continue _create_child(ctx, node, child) # finally process reorders which must be last since they may refer newly created nodes # and they do not reflect removed nodes for move in reorders: try: node = root.find_path(move['node']).data()[0] parent = node.parent() node.unlink() if parent: parent.insert(node) else: root.insert_sibling(node) except Exception as e: if root: root.new_path(ctx, move['node'], None, 0, 0) else: root = yang.Data_Node(ctx, move['node'], None, 0, 0) node = root.find_path(move['node']).data()[0] node.insert_attr(None, 'yang:insert', move['insert']) if move['insert'] == 'after' or move['insert'] == 'before': if 'key' in move: node.insert_attr(None, 'yang:key', move['key']) elif 'value' in move: node.insert_attr(None, 'yang:value', move['value']) # print(root.print_mem(yang.LYD_XML, yang.LYP_FORMAT)) try: sessions[user.username][req['key']]['session'].rpcEditConfig( nc.DATASTORE_RUNNING, root) except nc.ReplyError as e: reply = {'success': False, 'code': 500, 'message': '[]'} for err in e.args[0]: reply['message'] += json.loads(str(err)) + '; ' return json.dumps(reply) return json.dumps({'success': True})
def schema_checkvalue(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) req = request.args.to_dict() return _checkvalue(session, req, True)
def get_username_from_session(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) return session['user'].username
def schema_get(): session = auth.lookup(request.headers.get('lgui-Authorization', None)) user = session['user'] req = request.args.to_dict() path = os.path.join(INVENTORY, user.username) if not 'key' in req: return (json.dumps({ 'success': False, 'error-msg': 'Missing schema key.' })) key = req['key'] schemas = __schemas_inv_load(path) if key in schemas['schemas']: try: if (not 'type' in req) or req['type'] == 'text': # default (text) representation with open(os.path.join(path, key), 'r') as schema_file: data = schema_file.read() else: if req['type'] == 'tree': # build tree representation for frontend target = None elif req['type'] == 'tree-identity': target = 'identity' + req['path'] elif req['type'] == 'tree-typedef': target = 'typedef' + req['path'] elif req['type'] == 'tree-grouping': target = 'grouping' + req['path'] elif req['type'] == 'tree-node': target = req['path'] elif req['type'] == 'tree-type': target = 'type' + req['path'] elif req['type'] == 'tree-feature': target = 'feature' + req['path'] else: return (json.dumps({ 'success': False, 'error-msg': 'Unsupported schema format ' + req['type'] })) try: ctx = yang.Context(path) module = ctx.parse_module_path(os.path.join(path, key), yang.LYS_IN_YANG) data = json.loads( module.print_mem(yang.LYS_OUT_JSON, target, 0)) except Exception as e: return (json.dumps({ 'success': False, 'error-msg': str(e) })) if 'revision' in schemas['schemas'][key]: return (json.dumps( { 'success': True, 'data': data, 'name': schemas['schemas'][key]['name'], 'revision': schemas['schemas'][key]['revision'] }, ensure_ascii=False)) else: return (json.dumps( { 'success': True, 'data': data, 'name': schemas['schemas'][key]['name'] }, ensure_ascii=False)) except Exception as e: return (json.dumps({ 'success': False, 'error-msg': str(e) })) return (json.dumps({ 'success': False, 'error-msg': 'Schema ' + key + ' not found.' }))