gui CHANGE refactor work with schemas
- store all schemas as files in backend to unify work and keep all
dependencies in a single searchpath
- work with schemas as with dictionary - move key from the structure
itself to the dictionary key. However it is still possible to generate
the key from the schema itself
diff --git a/backend/schemas.py b/backend/schemas.py
index 7b12e9d..7dfef7c 100644
--- a/backend/schemas.py
+++ b/backend/schemas.py
@@ -8,6 +8,8 @@
import os
import errno
import time
+from subprocess import check_output
+from shutil import copy
from liberouterapi import auth
from flask import request
@@ -16,7 +18,7 @@
from .inventory import INVENTORY, inventory_check
from .error import NetopeerException
-__SCHEMAS_EMPTY = '{"schemas":{"timestamp":0,"schema":[]}}'
+__SCHEMAS_EMPTY = '{"timestamp":0, "schemas":{}}'
def __schema_parse(path, format = yang.LYS_IN_UNKNOWN):
@@ -36,9 +38,9 @@
raise NetopeerException(str(e))
return module
-
-def __schemas_init():
+
+def __schemas_init(path):
schemas = json.loads(__SCHEMAS_EMPTY)
try:
ctx = yang.Context()
@@ -48,7 +50,27 @@
# initialize the list with libyang's internal modules
modules = ctx.get_module_iter()
for module in modules:
- schemas['schemas']['schema'].append({'key':module.name() + '@' + module.rev().date(), 'name':module.name(), 'revision':module.rev().date()})
+ name_norm = module.name() + '@' + module.rev().date() + '.yang'
+ schemas['schemas'][name_norm] = {'name':module.name(), 'revision':module.rev().date()}
+ try:
+ with open(os.path.join(path, name_norm), 'w') as schema_file:
+ schema_file.write(module.print_mem(yang.LYS_OUT_YANG, 0))
+ except:
+ pass
+ try:
+ nc_schemas_dir = check_output("pkg-config --variable=LNC2_SCHEMAS_DIR libnetconf2", shell = True).decode()
+ nc_schemas_dir = nc_schemas_dir[:len(nc_schemas_dir) - 1]
+ for file in os.listdir(nc_schemas_dir):
+ if file[-5:] == '.yang' or file[-4:] == '.yin':
+ try:
+ copy(os.path.join(nc_schemas_dir, file), path)
+ except:
+ pass
+ else:
+ continue
+ except:
+ pass
+
return schemas
@@ -59,35 +81,37 @@
schemas = json.load(schemas_file)
except OSError as e:
if e.errno == errno.ENOENT:
- schemas = __schemas_init()
+ schemas = __schemas_init(path)
else:
raise NetopeerException('Unable to use user\'s schemas inventory ' + schemainv_path + ' (' + str(e) + ').')
except ValueError:
- schemas = __schemas_init()
+ schemas = __schemas_init(path)
return schemas
+
def __schemas_inv_save(path, schemas):
schemainv_path = os.path.join(path, 'schemas.json')
# update the timestamp
- schemas['schemas']['timestamp'] = time.time()
+ schemas['timestamp'] = time.time()
#store the list
try:
with open(schemainv_path, 'w') as schema_file:
- json.dump(schemas, schema_file)
+ json.dump(schemas, schema_file, sort_keys = True)
except Exception:
pass
return schemas
+
def __schemas_update(path):
# get schemas database
schemas = __schemas_inv_load(path)
# get the previous timestamp
- timestamp = schemas['schemas']['timestamp']
+ timestamp = schemas['timestamp']
# check the current content of the storage
for file in os.listdir(path):
@@ -104,22 +128,31 @@
try:
module = __schema_parse(schemapath, format)
if module.rev_size():
- schemas['schemas']['schema'].append({'key':module.name() + '@' + module.rev().date(),
- 'name':module.name(),
- 'revision':module.rev().date(),
- 'file':os.path.basename(schemapath)})
+ name_norm = module.name() + '@' + module.rev().date() + '.yang'
+ schemas['schemas'][name_norm] = {'name': module.name(), 'revision': module.rev().date()}
else:
- schemas['schemas']['schema'].append({'key':module.name() + '@',
- 'name':module.name(),
- 'file':os.path.basename(schemapath)})
- except Exception as e:
+ name_norm = module.name() + '.yang'
+ schemas['schemas'][name_norm] = {'name': module.name()}
+ if file != name_norm:
+ try:
+ with open(os.path.join(path, name_norm), 'w') as schema_file:
+ schema_file.write(module.print_mem(yang.LYS_OUT_YANG, 0))
+ except:
+ pass
+
+ try:
+ os.remove(schemapath)
+ except:
+ pass
+ except:
continue
#store the list
__schemas_inv_save(path, schemas)
# return the up-to-date list
- return schemas['schemas']['schema']
+ return schemas['schemas']
+
@auth.required()
def schemas_list():
@@ -130,7 +163,7 @@
inventory_check(path)
schemas = __schemas_update(path)
- return(json.dumps(schemas))
+ return(json.dumps(schemas, sort_keys = True))
@auth.required()
@@ -145,18 +178,13 @@
key = req['key']
schemas = __schemas_inv_load(path)
- for i in range(len(schemas['schemas']['schema'])):
- schema = schemas['schemas']['schema'][i]
- if schema['key'] == key:
- data = ""
- if 'file' in schema:
- with open(os.path.join(path, schema['file']), 'r') as schema_file:
- data = schema_file.read()
- else:
- ctx = yang.Context()
- data = ctx.get_module(schema['name']).print_mem(yang.LYS_OUT_YANG, 0)
+ 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.'}))
@@ -182,13 +210,29 @@
else:
format = yang.LYS_IN_UNKNOWN
module = __schema_parse(path, format)
- # TODO: normalize file name to allow removing without remembering schema path
+
+ # 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:
- os.remove(path)
+ try:
+ os.remove(path)
+ except:
+ pass
return(json.dumps({'success': False}))
return(json.dumps({'success': True}))
+
@auth.required()
def schemas_rm():
session = auth.lookup(request.headers.get('Authorization', None))
@@ -200,15 +244,9 @@
raise NetopeerException('Invalid schema remove request.')
schemas = __schemas_inv_load(path)
- for i in range(len(schemas['schemas']['schema'])):
- schema = schemas['schemas']['schema'][i]
- if schema['key'] == key:
- schemas['schemas']['schema'].pop(i)
- break;
- else:
- schema = None;
-
- if not schema:
+ try:
+ schemas.pop(key)
+ except KeyError:
# schema not in inventory
return (json.dumps({'success': False}))
@@ -216,12 +254,11 @@
__schemas_inv_save(path, schemas)
# remove the schema file
- if 'revision' in schema:
- path = os.path.join(path, schema['name'] + '@' + schema['revision'] + '.yang')
- else:
- path = os.path.join(path, schema['name'] + '.yang')
- os.remove(path)
+ try:
+ os.remove(os.path.join(path, key))
+ except Exception as e:
+ print(e)
- # TODO: resolve dependencies
+ # TODO: resolve dependencies ?
return(json.dumps({'success': True}))
diff --git a/frontend/config/config.component.html b/frontend/config/config.component.html
index 5ef82f4..4b53180 100644
--- a/frontend/config/config.component.html
+++ b/frontend/config/config.component.html
@@ -1,7 +1,8 @@
<nav #subnav id="subnav">
- <a *ngFor="let session of sessionsService.sessions" [class.active]="session.key==activeSession.key"
+ <a *ngFor="let session of sessionsService.sessions" [class.active]="session.key == sessionsService.activeSession"
(click)="changeActiveSession(session.key)">{{session.device.hostname}}:{{session.device.port}}
- <img *ngIf="session.key==activeSession.key" class="tab-icon tab-reload tab-action-first" src="assets/netopeer/icons/reload.svg" alt="o" title="reload"
+ <img *ngIf="session.key == sessionsService.activeSession"
+ class="tab-icon tab-reload tab-action-first" src="assets/netopeer/icons/reload.svg" alt="o" title="reload"
onmouseover="this.src='assets/netopeer/icons/reload_active.svg'"
onmouseout="this.src='assets/netopeer/icons/reload.svg'" (click)="reloadData()"/>
<img class="tab-icon tab-close tab-action-last" src="assets/netopeer/icons/close.svg" alt="x" title="disconnect"
@@ -15,7 +16,7 @@
</nav>
<div class="netopeer-content" [style.padding-top]="'calc(' + subnav.offsetHeight + 'px - -0.7em)'">
-<img *ngIf="!activeSession" src="assets/netopeer/starthere.svg" alt="Start here with that + sign."/>
+<img *ngIf="!activeSession" (click)="addSession()" src="assets/netopeer/starthere.svg" alt="Start here with that + sign."/>
<div *ngIf="activeSession">
<p class="msg-failure msg-rounded" *ngIf="err_msg"><img class="msg-close" (click)="err_msg=''" src="assets/netopeer/icons/close_active.svg" alt="x" title="close"/>{{err_msg}}</p>
<table class="items">
diff --git a/frontend/config/sessions.service.ts b/frontend/config/sessions.service.ts
index 8d28e24..fc850c4 100644
--- a/frontend/config/sessions.service.ts
+++ b/frontend/config/sessions.service.ts
@@ -1,4 +1,4 @@
-import { Injectable } from '@angular/core';
+import { Injectable, OnInit } from '@angular/core';
import { Http, Response, RequestOptions, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
@@ -9,7 +9,7 @@
import { Session } from './session';
@Injectable()
-export class SessionsService{
+export class SessionsService implements OnInit {
public sessions: Session[];
public activeSession;
@@ -18,6 +18,9 @@
if (!this.activeSession) {
this.activeSession = "";
}
+ }
+
+ ngOnInit(): void {
this.checkSessions();
}
diff --git a/frontend/inventory/schema.ts b/frontend/inventory/schema.ts
index fc0fa31..b20c2d3 100644
--- a/frontend/inventory/schema.ts
+++ b/frontend/inventory/schema.ts
@@ -1,5 +1,4 @@
export class Schema {
- key: string;
name: string;
revision: string;
}
diff --git a/frontend/inventory/schemas.component.html b/frontend/inventory/schemas.component.html
index 58cb62b..a95bdd8 100644
--- a/frontend/inventory/schemas.component.html
+++ b/frontend/inventory/schemas.component.html
@@ -22,20 +22,16 @@
<th>name</th>
<th class="item_right">revision</th>
</tr>
- <tr class="item" [class.selected]="schema === selectedSchema" *ngFor="let schema of schemas">
+ <tr class="item" *ngFor="let key of schemasKeys()">
<td class="item_left item_actions">
- <img class="item_action_delete" (click)="remove(schema)"
+ <img class="item_action_delete" (click)="remove(key)"
src="assets/netopeer/icons/close.svg" alt="x" title="delete"
onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
onmouseout="this.src='assets/netopeer/icons/close.svg'"/>
</td>
- <td class="schema schema-name" (click)="onSelect(schema)">{{schema.name}}</td>
- <td class="item_right schema schema-revision" (click)="onSelect(schema)">{{schema.revision}}</td>
+ <td class="schema schema-name" (click)="onSelect(key)">{{schemas[key].name}}</td>
+ <td class="item_right schema schema-revision" (click)="onSelect(key)">{{schemas[key].revision}}</td>
</tr>
</table>
-<div *ngIf="selectedSchema">
- <h3>{{selectedSchema.name}}<span *ngIf="selectedSchema.revision">@{{selectedSchema.revision}}</span></h3>
</div>
-
-</div>
\ No newline at end of file
diff --git a/frontend/inventory/schemas.component.ts b/frontend/inventory/schemas.component.ts
index a1262c1..92f22ea 100644
--- a/frontend/inventory/schemas.component.ts
+++ b/frontend/inventory/schemas.component.ts
@@ -14,14 +14,13 @@
export class InventorySchemasComponent implements OnInit {
schemas: Schema[];
- @Input() selectedSchema: Schema;
addingSchema = false;
addingResult = -1;
constructor( private schemasService: SchemasService,
private router: Router ) { }
getSchemas(): void {
- this.schemasService.getSchemas().then( result => this.schemas = result );
+ this.schemasService.getSchemas().then( result => {this.schemas = result;});
}
showAddSchema() {
@@ -40,8 +39,8 @@
result => { this.addingResult = result['success'] ? 1 : 0; this.getSchemas() } );
}
- remove( schema: Schema ) {
- this.schemasService.rmSchema( schema ).subscribe(
+ remove(key: string) {
+ this.schemasService.rmSchema(key).subscribe(
result => { if ( result['success'] ) { this.getSchemas() } } );
}
@@ -49,9 +48,15 @@
this.getSchemas();
}
- onSelect( schema: Schema ): void {
- this.schemasService.show(schema);
- this.schemasService.changeActiveSchema(schema.key);
+ schemasKeys() {
+ if (this.schemas) {
+ return Object.keys(this.schemas);
+ }
+ }
+
+ onSelect(key: string): void {
+ this.schemasService.show(key, this.schemas[key]);
+ this.schemasService.changeActiveSchemaKey(key);
this.router.navigateByUrl( '/netopeer/yang' );
}
}
diff --git a/frontend/yang/schemas.service.ts b/frontend/yang/schemas.service.ts
index 91b916e..168ddac 100644
--- a/frontend/yang/schemas.service.ts
+++ b/frontend/yang/schemas.service.ts
@@ -8,7 +8,7 @@
@Injectable()
export class SchemasService {
- public schemas: Schema[];
+ public schemas;
public activeSchema: string;
constructor( private http: Http ) {
@@ -28,25 +28,36 @@
this.schemas = JSON.parse(localStorage.getItem('schemas'));
}
- getActiveSchema(key: string = this.activeSchema): Schema {
- if (!key) {
- return null;
+ schemasKeys() {
+ if (this.schemas) {
+ return Object.keys(this.schemas);
}
- for (let i = this.schemas.length; i > 0; i--) {
- if (this.schemas[i - 1].key == key) {
- return this.schemas[i - 1];
- }
- }
- return null;
}
- changeActiveSchema(key: string): Schema {
- let result = this.getActiveSchema(key);
- if (result) {
+ getSchemaKey(schema: Schema) {
+ if (!schema) {
+ return null
+ } else if ('revision' in schema) {
+ return schema.name + '@' + schema.revision + '.yang';
+ } else {
+ return schema.name + '.yang';
+ }
+ }
+
+ getActiveSchema(key: string = this.activeSchema): Schema {
+ if (key in this.schemas) {
+ return this.schemas[key];
+ } else {
+ return null;
+ }
+ }
+
+ changeActiveSchemaKey(key: string): Schema {
+ if (key && (key in this.schemas)) {
this.activeSchema = key;
localStorage.setItem('activeSession', this.activeSchema);
}
- return result;
+ return this.schemas[key];
}
getSchemas() {
@@ -54,19 +65,17 @@
.map(( resp: Response ) => resp.json()).toPromise();
}
- show(schema: Schema) {
+ show(key: string, schema: Schema) {
let newSchema = true;
- for (let i in this.schemas) {
- if (this.schemas[i].key == schema.key) {
- schema = this.schemas[i];
- newSchema = false;
- break;
- }
+
+ if (key in this.schemas) {
+ newSchema = false;
+ schema = this.schemas[key];
}
if (!('data' in schema)) {
let params = new URLSearchParams();
- params.set('key', schema.key);
+ params.set('key', key);
let options = new RequestOptions({ search: params });
this.http.get('/netopeer/inventory/schema', options)
.map((resp: Response) => resp.json()).toPromise().then(result => {
@@ -74,13 +83,12 @@
if (result['success']) {
schema['data'] = result['data'];
this.storeData();
- console.log(this.schemas)
}
});
}
if (newSchema) {
- this.schemas.push(schema);
+ this.schemas[key] = schema;
this.storeData();
}
}
@@ -95,8 +103,8 @@
.catch(( err: Response | any ) => Observable.throw( err ) );
}
- rmSchema( schema: Schema ) {
- let options = new RequestOptions( { body: JSON.stringify(schema.key) } );
+ rmSchema(key: string) {
+ let options = new RequestOptions( { body: JSON.stringify(key) } );
return this.http.delete( '/netopeer/inventory/schemas', options )
.map(( resp: Response ) => resp.json() )
.catch(( err: Response | any ) => Observable.throw( err ) );
diff --git a/frontend/yang/yang.component.html b/frontend/yang/yang.component.html
index 1416bb3..ed016e8 100644
--- a/frontend/yang/yang.component.html
+++ b/frontend/yang/yang.component.html
@@ -1,19 +1,17 @@
<nav #subnav id="subnav">
- <a *ngFor="let schema of schemasService.schemas" [class.active]="schema.key==activeSchema.key"
- (click)="changeActiveSchema(schema.key)">{{schema.name}}@{{schema.revision}}
+ <a *ngFor="let key of schemasService.schemasKeys()" [class.active]="key == schemasService.activeSchema"
+ (click)="schemasService.changeActiveSchemaKey(key)">{{schemasService.schemas[key].name}}@{{schemasService.schemas[key].revision}}
<img class="tab-icon tab-close tab-action-last" src="assets/netopeer/icons/close.svg" alt="x" title="close"
onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
- onmouseout="this.src='assets/netopeer/icons/close.svg'" (click)="close(schema.key)"/>
+ onmouseout="this.src='assets/netopeer/icons/close.svg'" (click)="close(key)"/>
</a><a (click)="addSchema()" onmouseout="getElementById('tabadd').style.filter='invert(100%)'" onmouseover="getElementById('tabadd').style.filter='invert(0%)'">
<img id="tabadd" class="tab-icon tab-add tab-action-last" src="assets/netopeer/icons/add.svg" alt="+" title="open schema"
onmouseover="this.src='assets/netopeer/icons/add_active.svg'"
onmouseout="this.src='assets/netopeer/icons/add.svg'"/>
</a>
</nav>
-
<div class="netopeer-content" [style.padding-top]="'calc(' + subnav.offsetHeight + 'px - -0.7em)'">
-<img *ngIf="!activeSchema" src="assets/netopeer/starthere.svg" alt="Start here with that + sign."/>
+<img *ngIf="!schemasService.activeSchema" (click)="addSchema()" src="assets/netopeer/starthere.svg" alt="Start here with that + sign."/>
-<pre *ngIf="activeSchema">{{activeSchema.data}}</pre>
-
-</div>
\ No newline at end of file
+<pre *ngIf="schemasService.activeSchema">{{schemasService.schemas[schemasService.activeSchema].data}}</pre>
+</div>
diff --git a/frontend/yang/yang.component.ts b/frontend/yang/yang.component.ts
index 388c7ae..eddcf7c 100644
--- a/frontend/yang/yang.component.ts
+++ b/frontend/yang/yang.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
import {Router} from '@angular/router';
import {SchemasService} from './schemas.service';
@@ -10,9 +10,8 @@
styleUrls : ['./yang.component.scss']
})
-export class YANGComponent implements OnInit {
+export class YANGComponent {
title = 'YANG Explorer';
- activeSchema: Schema;
constructor(private schemasService: SchemasService,
private router: Router) {}
@@ -22,29 +21,18 @@
this.router.navigateByUrl('/netopeer/inventory/schemas');
}
- changeActiveSchema(key: string) {
- this.activeSchema = this.schemasService.changeActiveSchema(key);
- }
-
close(key: string) {
- for (let i in this.schemasService.schemas) {
- if (this.schemasService.schemas[i].key == key) {
- this.schemasService.schemas.splice(Number(i), 1);
- if (this.schemasService.activeSchema == key) {
- if (Number(i) > 0) {
- this.changeActiveSchema(this.schemasService.schemas[Number(i) - 1].key)
- } else if (this.schemasService.schemas.length) {
- this.changeActiveSchema(this.schemasService.schemas[0].key)
- }
- }
- this.schemasService.storeData();
- break;
+ let index = Object.keys(this.schemasService.schemas).indexOf(key);
+ if (this.schemasService.activeSchema == key) {
+ if (index > 0) {
+ this.schemasService.changeActiveSchemaKey(Object.keys(this.schemasService.schemas)[index - 1])
+ } else if (Object.keys(this.schemasService.schemas).length > 1) {
+ this.schemasService.changeActiveSchemaKey(Object.keys(this.schemasService.schemas)[1])
+ } else {
+ this.schemasService.activeSchema = null;
}
}
- this.activeSchema = this.schemasService.getActiveSchema();
- }
-
- ngOnInit(): void {
- this.activeSchema = this.schemasService.getActiveSchema();
+ delete this.schemasService.schemas[key];
+ this.schemasService.storeData();
}
}