Available Workgroups
Select a workgroup to use
diff --git a/frontend/www/index.cgi b/frontend/www/index.cgi
index eacd2c3d0..74c0954bf 100755
--- a/frontend/www/index.cgi
+++ b/frontend/www/index.cgi
@@ -43,49 +43,21 @@ use Log::Log4perl;
Log::Log4perl::init('/etc/oess/logging.conf');
-my $config = new OESS::Config();
-my $db= OESS::Database->new();
-
-
-my $ADD_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
- {title => "Home", url => "?action=index"},
- {title => "Endpoints", url => "?action=endpoints"},
- {title => "Options", url => "?action=options"},
- {title => "Primary Path", url => "?action=primary_path"},
- {title => "Backup Path", url => "?action=backup_path"},
- {title => "Scheduling", url => "?action=scheduling"},
- {title => "Provisioning", url => "?action=provisioning"},
- ];
-
-my $REMOVE_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
- {title => "Home", url => "?action=index"},
- {title => "Scheduling", url => "?action=remove_scheduling"},
- {title => "Provisioning", url => "?action=remove_provisioning"},
- ];
-
-my $HOME_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
- {title => "Home", url => "?action=index"}
- ];
-
-my $DETAILS_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},,
- {title => "Home", url => "?action=index"},
- {title => "Circuit Details", url => "?action=view_details"},
- ];
sub main{
-
+ my $config = new OESS::Config();
+ my $db = OESS::Database->new();
my $cgi = new CGI;
-
my $tt = Template->new(INCLUDE_PATH => "$FindBin::Bin") || die $Template::ERROR;
my $is_valid_user = $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'});
if(!defined($is_valid_user)){
- #-- What to pass to the TT and what http headers to send
+ #-- What to pass to the TT and what http headers to send
my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
- $filename = "html_templates/denied.html";
- $title = "Access Denied";
+ $filename = "html_templates/denied2.html";
+ $title = "Access Denied";
$vars->{'admin_email'} = $db->get_admin_email();
$vars->{'page'} = $filename;
@@ -93,146 +65,141 @@ sub main{
$vars->{'breadcrumbs'} = $breadcrumbs;
$vars->{'current_breadcrumb'} = $current_breadcrumb;
$vars->{'is_admin'} = 0;
+ $vars->{'path'} = "./";
$vars->{'is_read_only'} = 1;
$vars->{'version'} = OESS::Database::VERSION;
+ $vars->{'network_type'} = $config->network_type;
- $tt->process("html_templates/page_base.html", $vars, \$output) or warn $tt->error();
- print "Content-type: text/html\n\n" . $output;
- return;
+ $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
+ print "Content-type: text/html\n\n" . $output;
+ return;
}
-
+
my $is_admin = $db->get_user_admin_status(username=>$ENV{'REMOTE_USER'})->[0]{'is_admin'};
- if(!defined($is_admin)){
+ if (!defined $is_admin) {
$is_admin = 0;
}
- my $is_read_only =0;
+ my $is_read_only = 0;
my $user = $db->get_user_by_id( user_id => $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'}))->[0];
-
+
#-- What to pass to the TT and what http headers to send
my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
- #-- Figure out what we're trying to templatize here or default to workgroups page.
- my $action = "workgroups";
-
+ #-- Figure out what we're trying to templatize here or default to welcome page.
+ my $action = "welcome";
+
if ($cgi->param('action') =~ /^(\w+)$/){
$action = $1;
}
-
+
if ($user->{'status'} eq 'decom') {
- $action = "decom";
+ $action = "decom";
}
-
switch ($action) {
-
- case "workgroups" { $filename = "html_templates/workgroups.html";
- $title = "Workgroups";
- $breadcrumbs = [{title => "Workgroups", url => "?action=workgroups"}];
- $current_breadcrumb = "Workgroups";
- }
- case "index" { $filename = "html_templates/index.html";
- $title = "Home";
- $breadcrumbs = $HOME_BREADCRUMBS;
- $current_breadcrumb = "Home";
- }
- case "edit_details" { $filename = "html_templates/edit_details.html";
- $title = "Details";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Details";
- }
-
- case "loop_circuit" { $filename = "html_templates/loop_circuit.html";
- $title = "Loop Circuit";
- $breadcrumbs = $DETAILS_BREADCRUMBS;
- $current_breadcrumb = "Loop Circuit";
- }
- case "view_details" { $filename = "html_templates/view_details.html";
- $title = "Circuit Details";
- $breadcrumbs = $DETAILS_BREADCRUMBS;
- $current_breadcrumb = "Circuit Details";
- }
- case "interdomain" { $filename = "html_templates/interdomain.html";
- $title = "Interdomain Endpoints";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Endpoints";
- }
- case "endpoints" { $filename = "html_templates/endpoints.html";
- $title = "Endpoints";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Endpoints";
- }
- case "options" { $filename = "html_templates/options.html";
- $title = "Options";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Options";
- }
- case "primary_path" { $filename = "html_templates/primary_path.html";
- $title = "Primary Path";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Primary Path";
- }
- case "backup_path" { $filename = "html_templates/backup_path.html";
- $title = "Backup Path";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Backup Path";
- }
- case "scheduling" { $filename = "html_templates/scheduling.html";
- $title = "Scheduling";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Scheduling";
- }
-
- case "provisioning" {
- $filename = "html_templates/provisioning.html";
- $title = "Provisioning";
- $breadcrumbs = $ADD_BREADCRUMBS;
- $current_breadcrumb = "Provisioning";
- }
- case "remove_scheduling" {
- $filename = "html_templates/remove_scheduling.html";
- $title = "Removal Scheduling";
- $breadcrumbs = $REMOVE_BREADCRUMBS;
- $current_breadcrumb = "Scheduling";
- }
- case "remove_provisioning" {
- $filename = "html_templates/remove_provisioning.html";
- $title = "Removal Provisioning";
- $breadcrumbs = $REMOVE_BREADCRUMBS;
- $current_breadcrumb = "Provisioning";
- }
- case "decom" {
- $filename = "html_templates/denied.html";
- $title = "Access Denied";
- }
- case "about" {
- $filename = "html_templates/splash.html";
- $title = "About";
- }
+ case "modify_l2vpn" {
+ $title = "Layer 2 Connection";
+ $filename = "html_templates/modify_l2vpn.html";
+ $current_breadcrumb = "Layer 2 Connection";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "Layer 2 Connection", url => "#"}
+ ];
+ }
+ case "provision_l2vpn" {
+ $title = "New Layer 2 Connection";
+ $filename = "html_templates/provision_l2vpn.html";
+ $current_breadcrumb = "New Layer 2 Connection";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "New Layer 2 Connection", url => "#"}
+ ];
+ }
+ case "modify_cloud" {
+ $title = "Layer 3 Connection";
+ $filename = "html_templates/modify_cloud.html";
+ $current_breadcrumb = "Layer 3 Connection";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "Layer 3 Connection", url => "#"}
+ ];
+ }
+ case "provision_cloud" {
+ $title = "New Layer 3 Connection";
+ $filename = "html_templates/provision_cloud.html";
+ $current_breadcrumb = "New Layer 3 Connection";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "New Layer 3 Connection", url => "#"}
+ ];
+ }
+ case "phonebook" {
+ $title = "Phonebook";
+ $filename = "html_templates/phonebook.html";
+ $current_breadcrumb = "Phonebook";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "Phonebook", url => "#"}
+ ];
+ }
+ case "welcome" {
+ $title = "Welcome";
+ $filename = "html_templates/welcome.html";
+ $current_breadcrumb = "Welcome";
+ $breadcrumbs = [
+ {title => "Welcome", url => "#"}
+ ];
+ }
+ case "acl" {
+ $filename = "html_templates/acl.html";
+ $title = "Edit ACL";
+ }
+ case "decom" {
+ $filename = "html_templates/denied.html";
+ $title = "Access Denied";
+ }
+ case "edit_entity" {
+ $filename = "html_templates/edit_entity.html";
+ $current_breadcrumb = "Edit Entity";
+ $title = "Edit Entity";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "Edit Entity", url => "#"}
+ ];
+ }
+ case "add_entity" {
+ $filename = "html_templates/add_entity.html";
+ $current_breadcrumb = "Add Entity";
+ $title = "Add Entity";
+ $breadcrumbs = [
+ {title => "Welcome", url => "?action=welcome"},
+ {title => "Add Entity", url => "#"}
+ ];
+ }
else {
- $filename = "html_templates/error.html";
- $title = "Error";
- }
-
+ $filename = "html_templates/error.html";
+ $title = "Error";
+ }
}
+
+ $vars->{'g_port'} = $db->{grafana}->{'oess-interface'};
+ $vars->{'g_l2_port'} = $db->{grafana}->{'oess-l2-interface'};
+ $vars->{'g_peer'} = $db->{grafana}->{'oess-bgp-peer'};
+ $vars->{'g_route'} = $db->{grafana}->{'oess-routing-table'};
+
$vars->{'admin_email'} = $db->get_admin_email();
-
$vars->{'page'} = $filename;
$vars->{'title'} = $title;
$vars->{'breadcrumbs'} = $breadcrumbs;
$vars->{'current_breadcrumb'} = $current_breadcrumb;
- $vars->{'is_admin'} = $is_admin;
+ $vars->{'path'} = "./";
+ $vars->{'is_admin'} = $is_admin;
$vars->{'is_read_only'} = $is_read_only;
$vars->{'version'} = OESS::Database::VERSION;
$vars->{'network_type'} = $config->network_type;
-
- #print STDERR Dumper($vars);
- if ($action eq 'view_l3vpn' || $action eq 'provision_cloud' || $action eq 'modify_cloud' || $action eq 'phonebook' || $action eq 'welcome') {
- $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
- } else {
- $tt->process("html_templates/page_base.html", $vars, \$output) or warn $tt->error();
- }
+
+ $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
print "Content-type: text/html\n\n" . $output;
}
-
main();
diff --git a/frontend/www/js_templates/admin.js b/frontend/www/js_templates/admin.js
index 967f50ba4..d776c54a3 100644
--- a/frontend/www/js_templates/admin.js
+++ b/frontend/www/js_templates/admin.js
@@ -1267,7 +1267,7 @@ function setup_users_tab(){
else{
- var ds = new YAHOO.util.DataSource("../services/admin/admin.cgi?method=add_user_to_workgroup&workgroup_id=" + add_new_user_to_workgroup + "&user_id="+ user_id + "&role=normal");
+ var ds = new YAHOO.util.DataSource("../services/admin/admin.cgi?method=add_user_to_workgroup&workgroup_id=" + add_new_user_to_workgroup + "&user_id="+ user_id + "&role=" + encodeURIComponent(type));
ds.responseType = YAHOO.util.DataSource.TYPE_JSON;
ds.responseSchema = {
resultsList: "results",
@@ -1518,7 +1518,7 @@ function setup_workgroup_tab(){
var rec = this.getRecord(oArgs.target);
var user_id = rec.getData('user_id');
- var user = rec.getData('first_name') + " " + rec.getData('family_name');
+ var user = rec.getData('first_name') + " " + rec.getData('last_name');
if (col.label != "Remove"){
return;
@@ -2399,6 +2399,7 @@ function setup_network_tab(){
var vendor = args[0].vendor;
var model = args[0].model;
var sw_version = args[0].sw_version;
+ var controller = args[0].controller;
function show_interface_acl_panel(args){
var interface_id = args.interface_id;
@@ -2893,6 +2894,13 @@ function setup_network_tab(){
"
Short Name: | " +
"
| " +
"" +
+ // MPLS - Software Version
+ "
" +
+ "Southbound | " +
+ " | " +
+ " | " +
+ " | " +
+ "
" +
"
|
" +
"" +
"
Interfaces
"+
@@ -2908,6 +2916,18 @@ function setup_network_tab(){
panel.render(YAHOO.util.Dom.get("active_element_details"));
+ $('#controller').on('change', function() {
+ if ($('#controller').val() == 'netconf') {
+ $('#vendor').prop('disabled', false);
+ $('#model').prop('disabled', false);
+ $('#sw_version').prop('disabled', false);
+ } else {
+ $('#vendor').prop('disabled', true);
+ $('#model').prop('disabled', true);
+ $('#sw_version').prop('disabled', true);
+ }
+ });
+
var table = make_node_intf_table();
table.subscribe("rowMouseoverEvent", table.onEventHighlightRow);
@@ -2972,6 +2992,13 @@ function setup_network_tab(){
YAHOO.util.Dom.get('vendor').value = vendor;
YAHOO.util.Dom.get('model').value = model;
YAHOO.util.Dom.get('sw_version').value = sw_version;
+ YAHOO.util.Dom.get('controller').value = controller;
+
+ if (controller == 'nso') {
+ YAHOO.util.Dom.get('vendor').disabled = true;
+ YAHOO.util.Dom.get('model').disabled = true;
+ YAHOO.util.Dom.get('sw_version').disabled = true;
+ }
}
if(default_drop == 0){
@@ -3009,12 +3036,13 @@ function setup_network_tab(){
var new_max_static_mac_flows = YAHOO.util.Dom.get('active_max_static_mac_flows').value;
var openflow = YAHOO.util.Dom.get('openflow_enabled').value;
var mpls = YAHOO.util.Dom.get('mpls_enabled').checked;
- var mgmt_addr = YAHOO.util.Dom.get('mgmt_addr').value;
- var tcp_port = YAHOO.util.Dom.get('tcp_port').value;
- var vendor = YAHOO.util.Dom.get('vendor').value;
- var model = YAHOO.util.Dom.get('model').value;
- var sw_version = YAHOO.util.Dom.get('sw_version').value;
- var short_name = YAHOO.util.Dom.get('short_name').value;
+ var mgmt_addr = YAHOO.util.Dom.get('mgmt_addr').value;
+ var tcp_port = YAHOO.util.Dom.get('tcp_port').value;
+ var vendor = YAHOO.util.Dom.get('vendor').value;
+ var model = YAHOO.util.Dom.get('model').value;
+ var sw_version = YAHOO.util.Dom.get('sw_version').value;
+ var controller = YAHOO.util.Dom.get('controller').value;
+ var short_name = YAHOO.util.Dom.get('short_name').value;
if (! new_name){
alert("You must specify a name for this device.");
@@ -3059,6 +3087,7 @@ function setup_network_tab(){
"&vendor=" + encodeURIComponent(vendor) +
"&model=" + encodeURIComponent(model) +
"&sw_version=" + encodeURIComponent(sw_version) +
+ "&controller=" + encodeURIComponent(controller) +
"&short_name=" + encodeURIComponent(short_name);
var openflow_args = "&default_drop=" + encodeURIComponent(new_default_drop) +
@@ -3253,40 +3282,43 @@ function setup_discovery_tab(){
this.new_mpls.setBody("
"
);
@@ -3295,6 +3327,18 @@ function setup_discovery_tab(){
this.new_mpls.render(document.body);
+ $('#controller').on('change', function() {
+ if ($('#controller').val() == 'netconf') {
+ $('#new_mpls_vendor').prop('disabled', false);
+ $('#new_mpls_model').prop('disabled', false);
+ $('#new_mpls_software').prop('disabled', false);
+ } else {
+ $('#new_mpls_vendor').prop('disabled', true);
+ $('#new_mpls_model').prop('disabled', true);
+ $('#new_mpls_software').prop('disabled', true);
+ }
+ });
+
$('#new_mpls_vendor').on('change', function(){
var vendor = $('#new_mpls_vendor').val();
if(vendor == 'Juniper'){
@@ -3312,9 +3356,6 @@ function setup_discovery_tab(){
var add_button = new YAHOO.widget.Button("add_node", {label: "Add Switch"});
var cancel_button = new YAHOO.widget.Button("node_add_cancel", {label: "Cancel"});
-
-
- //do the add event!
add_button.on('click', function(){
var lat = YAHOO.util.Dom.get('new_node_lat').value;
@@ -3323,10 +3364,11 @@ function setup_discovery_tab(){
var short_name = YAHOO.util.Dom.get('new_node_short_name').value;
var ip = YAHOO.util.Dom.get('new_ip_address').value;
var port = YAHOO.util.Dom.get('new_port').value;
- var vendor= YAHOO.util.Dom.get('new_mpls_vendor').value;
- var model = YAHOO.util.Dom.get('new_mpls_model').value;
- var sw_ver= YAHOO.util.Dom.get('new_mpls_software').value;
-
+ var controller = YAHOO.util.Dom.get('controller').value;
+ var vendor = $('#new_mpls_vendor').prop('disabled') ? null : YAHOO.util.Dom.get('new_mpls_vendor').value;
+ var model = $('#new_mpls_model').prop('disabled') ? null : YAHOO.util.Dom.get('new_mpls_model').value;
+ var sw_ver = $('#new_mpls_software').prop('disabled') ? null : YAHOO.util.Dom.get('new_mpls_software').value;
+
if (! name){
alert("You must specify a name for this device.");
return;
@@ -3357,18 +3399,30 @@ function setup_discovery_tab(){
return;
}
- if(vendor == undefined || model == undefined || sw_ver == undefined){
- alert('Hardware vendor, model and software version are required');
+ if (controller === 'netconf' && (vendor === '' || model === '' || sw_ver === '')) {
+ alert('Hardware vendor, model, and software version are required for NETCONF controlled devices.');
return;
}
add_button.set("disabled", true);
add_button.set("label", "Adding device....");
- var ds = new YAHOO.util.DataSource("../services/admin/admin.cgi?method=add_mpls_switch&name=" + encodeURIComponent(name) + "&short_name=" + encodeURIComponent(short_name) + "&latitude=" + encodeURIComponent(lat) + "&longitude=" + encodeURIComponent(lon) + "&ip_address=" + encodeURIComponent(ip) + "&port=" + encodeURIComponent(port) + "&vendor=" + encodeURIComponent(vendor) + "&model=" + encodeURIComponent(model) + "&sw_ver=" + encodeURIComponent(sw_ver));
- ds.responseType = YAHOO.util.DataSource.TYPE_JSON;
+ var url = "../services/admin/admin.cgi?method=add_mpls_switch";
+ url += `&name=${encodeURIComponent(name)}`;
+ url += `&short_name=${encodeURIComponent(short_name)}`;
+ url += `&latitude=${encodeURIComponent(lat)}`;
+ url += `&longitude=${encodeURIComponent(lon)}`;
+ url += `&ip_address=${encodeURIComponent(ip)}`;
+ url += `&port=${encodeURIComponent(port)}`;
+ url += `&controller=${encodeURIComponent(controller)}`;
+ if (vendor) url += `&vendor=${encodeURIComponent(vendor)}`;
+ if (model) url += `&model=${encodeURIComponent(model)}`;
+ if (sw_ver) url += `&sw_ver=${encodeURIComponent(sw_ver)}`;
+
+ var ds = new YAHOO.util.DataSource(url);
+ ds.responseType = YAHOO.util.DataSource.TYPE_JSON;
- ds.responseSchema = {
+ ds.responseSchema = {
resultsList: "results",
fields: [{key: "success"}],
metaFields: {
diff --git a/frontend/www/js_templates/api/circuit.js b/frontend/www/js_templates/api/circuit.js
index 05fc9fa28..9d0c45558 100644
--- a/frontend/www/js_templates/api/circuit.js
+++ b/frontend/www/js_templates/api/circuit.js
@@ -2,17 +2,13 @@ async function deleteCircuit(workgroupID, circuitID, end=-1) {
let url = '[% path %]services/circuit.cgi?method=remove';
url += `&circuit_id=${circuitID}`;
url += `&workgroup_id=${workgroupID}`;
+
+ const resp = await fetch(url, {method: 'get', credentials: 'include'});
+ const data = await resp.json();
- try {
- const resp = await fetch(url, {method: 'get', credentials: 'include'});
- const data = await resp.json();
-
- if ('error_text' in data) throw(data.error_text);
- return data.results;
- } catch(error) {
- console.log('Failure occurred in deleteCircuit:', error);
- return null;
- }
+ if ('error_text' in data) throw(data.error_text);
+ return data.results;
+
}
/**
diff --git a/frontend/www/js_templates/api/entity.js b/frontend/www/js_templates/api/entity.js
index 2d89d355b..2bbfaf05f 100644
--- a/frontend/www/js_templates/api/entity.js
+++ b/frontend/www/js_templates/api/entity.js
@@ -59,7 +59,7 @@ async function getEntitiesAll(workgroupID, queryString=null) {
*/
async function edit_entity(entityID, entity_name, description, logo_url, entity_url){
- let url = `[% path %]services/entity.cgi?action=update_entity&entity_id=${entityID}`;
+ let url = `[% path %]services/entity.cgi?method=update_entity&entity_id=${entityID}`;
if (entity_name.value)
{
url += `&name=${entity_name.value}`;
@@ -101,7 +101,7 @@ async function edit_entity(entityID, entity_name, description, logo_url, entity_
async function add_entity(entityID, entity_name, desctiption, logo_url, entity_url){
let user = await getCurrentUser();
- let url = `[% path %]services/entity.cgi?action=add_child_entity¤t_entity_id=${entityID}&user_id=${user.user_id}`;
+ let url = `[% path %]services/entity.cgi?method=add_child_entity¤t_entity_id=${entityID}&user_id=${user.user_id}`;
if (entity_name.value)
{
url += `&name=${entity_name.value}`;
@@ -137,7 +137,7 @@ async function add_entity(entityID, entity_name, desctiption, logo_url, entity_u
* @params {integer} entityID - Identifier of the currnt entity
*/
async function add_user(user_id, entityID){
- const url = `[% path %]services/entity.cgi?action=add_user&entity_id=${entityID}&user_id=${user_id}`;
+ const url = `[% path %]services/entity.cgi?method=add_user&entity_id=${entityID}&user_id=${user_id}`;
try {
const resp = await fetch(url, {method: 'get', credentials: 'include'});
const data = await resp.json();
@@ -157,7 +157,7 @@ async function add_user(user_id, entityID){
*/
async function remove_user(user_id, entityID){
console.log("remove user");
- const url = `[% path %]services/entity.cgi?action=remove_user&entity_id=${entityID}&user_id=${user_id}`;
+ const url = `[% path %]services/entity.cgi?method=remove_user&entity_id=${entityID}&user_id=${user_id}`;
try {
const resp = await fetch(url, {method: 'get', credentials: 'include'});
const data = await resp.json();
diff --git a/frontend/www/js_templates/api/vrf.js b/frontend/www/js_templates/api/vrf.js
index 0a5767998..04f55b768 100644
--- a/frontend/www/js_templates/api/vrf.js
+++ b/frontend/www/js_templates/api/vrf.js
@@ -114,16 +114,11 @@ async function getVRF(workgroupID, vrfID) {
async function deleteVRF(workgroupID, vrfID) {
let url = `[% path %]services/vrf.cgi?method=remove&vrf_id=${vrfID}&workgroup_id=${workgroupID}`;
- try {
- const resp = await fetch(url, {method: 'get', credentials: 'include'});
- const data = await resp.json();
- console.log(data);
- return data.results;
- } catch(error) {
- console.log('Failure occurred in deleteVRF.');
- console.log(error);
- return null;
- }
+ const resp = await fetch(url, {method: 'get', credentials: 'include'});
+ const data = await resp.json();
+ console.log(data);
+ if ('error_text' in data) throw(data.error_text);
+ return data.results;
}
async function getVRFs(workgroupID) {
diff --git a/frontend/www/js_templates/edit_circuit_name.js b/frontend/www/js_templates/edit_circuit_name.js
new file mode 100644
index 000000000..6385649e0
--- /dev/null
+++ b/frontend/www/js_templates/edit_circuit_name.js
@@ -0,0 +1,37 @@
+function doneEditingName(name){
+ let description = document.querySelector('#header-description');
+ let button = document.getElementById("edit-description-button")
+ description.innerHTML = " "
+ document.getElementById("change-description-button").hidden = true
+ button.textContent = "Edit Name"
+}
+function addEditNameEvents(default_name){
+ document.querySelector('.change-description-button').addEventListener('click', function(e) {
+ const newName = document.getElementById("description-input").value == "" ? default_name : document.getElementById("description-input").value
+ doneEditingName(newName)
+ })
+
+ document.querySelector('.edit-description-button').addEventListener('click', function(e) {
+ let name = document.querySelector('#header-description');
+ let button = document.getElementById("edit-description-button")
+
+ if(button.textContent.trim() == "Edit Name"){
+ name.innerHTML = `
+
+
+ `;
+ name.addEventListener("keyup", function(event) {
+ // Number 13 is the "Enter" key on the keyboard
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ const newName = document.getElementById("description-input").value == "" ? default_name: document.getElementById("description-input").value
+ doneEditingName(newName)
+ }
+ });
+ button.textContent = "Revert"
+ document.getElementById("change-description-button").hidden = false
+ }else{
+ doneEditingName(default_name)
+ }
+ });
+}
\ No newline at end of file
diff --git a/frontend/www/js_templates/entity.js b/frontend/www/js_templates/entity.js
index 85bce3ce8..ed868998b 100644
--- a/frontend/www/js_templates/entity.js
+++ b/frontend/www/js_templates/entity.js
@@ -21,7 +21,7 @@ async function loadEntityContent(parentEntity=null, action){
e.preventDefault();
try {
let res = await add_entity(entityID, entity_name, description, logo_url, entity_url);
- window.location.href = `[% path %]new/index.cgi?action=phonebook&entity_id=${entityID}`;
+ window.location.href = `[% path %]index.cgi?action=phonebook&entity_id=${entityID}`;
}
catch (error) {
console.error(error);
@@ -37,11 +37,11 @@ async function loadEntityContent(parentEntity=null, action){
entity_url.value = entity.url;
document.querySelector('#edit-entity-btn').onclick = async function(){
await edit_entity(entityID, entity_name, description, logo_url, entity_url);
- window.location.href = `[% path %]new/index.cgi?action=phonebook&entity_id=${entityID}`;
+ window.location.href = `[% path %]index.cgi?action=phonebook&entity_id=${entityID}`;
};
}
document.querySelector('#cancel').onclick = function(){
- window.location.href = `[% path %]new/index.cgi?action=phonebook&entity_id=${entityID}`;
+ window.location.href = `[% path %]index.cgi?action=phonebook&entity_id=${entityID}`;
};
}
diff --git a/frontend/www/js_templates/l2/circuit.js b/frontend/www/js_templates/l2/circuit.js
index 1136755f8..76608e0c7 100644
--- a/frontend/www/js_templates/l2/circuit.js
+++ b/frontend/www/js_templates/l2/circuit.js
@@ -101,21 +101,32 @@ class CircuitHeader extends Component {
}
async render(props) {
- let displayEdits = (props.editable) ? 'block' : 'none';
+ let displayEdits = (props.editable) ? 'inline-block' : 'none';
return `
-
-
${props.description} ${props.connectionId}
-
-
-
-
-
-
-`;
+
+
+
+
+ ${props.connectionId}
+
+
+
+
+
+
+
+
+
+
+ `;
}
}
diff --git a/frontend/www/js_templates/l2/endpoint_selection_modal.js b/frontend/www/js_templates/l2/endpoint_selection_modal.js
index 974c82a1e..329a5cf5c 100644
--- a/frontend/www/js_templates/l2/endpoint_selection_modal.js
+++ b/frontend/www/js_templates/l2/endpoint_selection_modal.js
@@ -3,6 +3,7 @@ class EndpointSelectionModal2 {
let template = document.querySelector('#endpoint-selection-modal2');
this.element = document.importNode(template.content, true);
+ this.endpoint = null;
this.searchTimeout = null;
this.parent = document.querySelector(query);
@@ -10,6 +11,8 @@ class EndpointSelectionModal2 {
}
display(endpoint) {
+ this.endpoint = endpoint;
+
if (endpoint !== undefined && endpoint !== null && endpoint.interface === 'TBD') {
this.populateEntityForm(endpoint);
} else {
@@ -173,24 +176,24 @@ class EndpointSelectionModal2 {
if (interconnectType === 'null') {
interconnectType = null;
}
-
- let endpoint = {
- index: index,
- bandwidth: this.parent.querySelector('.endpoint-bandwidth').value,
- interface: interfaceSelector.options[interfaceSelector.selectedIndex].dataset.name,
- interface_id: interfaceSelector.options[interfaceSelector.selectedIndex].value,
- description: interfaceSelector.options[interfaceSelector.selectedIndex].dataset.description,
- node: interfaceSelector.options[interfaceSelector.selectedIndex].dataset.node,
- entity: null, // entity,
- entity_id: null, // entity_id,
- peerings: [],
- cloud_account_id: '',
- tag: vlanSelector.options[vlanSelector.selectedIndex].value,
- jumbo: this.parent.querySelector('.endpoint-jumbo-frames').checked,
- cloud_interconnect_type: interconnectType
- };
-
- state.updateEndpoint(endpoint);
+ if (this.endpoint === null || !this.endpoint) {
+ this.endpoint = { index: index };
+ }
+ this.endpoint.bandwidth = this.parent.querySelector('.endpoint-bandwidth').value;
+ this.endpoint.name = interfaceSelector.options[interfaceSelector.selectedIndex].dataset.name;
+ this.endpoint.interface = interfaceSelector.options[interfaceSelector.selectedIndex].dataset.name;
+ this.endpoint.interface_id = interfaceSelector.options[interfaceSelector.selectedIndex].value;
+ this.endpoint.description = interfaceSelector.options[interfaceSelector.selectedIndex].dataset.description;
+ this.endpoint.node = interfaceSelector.options[interfaceSelector.selectedIndex].dataset.node;
+ this.endpoint.entity = null;
+ this.endpoint.entity_id = null;
+ this.endpoint.peerings = [];
+ this.endpoint.cloud_account_id = '';
+ this.endpoint.tag = vlanSelector.options[vlanSelector.selectedIndex].value;
+ this.endpoint.jumbo = this.parent.querySelector('.endpoint-jumbo-frames').checked;
+ this.endpoint.cloud_interconnect_type = interconnectType;
+
+ state.updateEndpoint(this.endpoint);
$('#add-endpoint-modal2').modal('hide');
}.bind(this);
diff --git a/frontend/www/js_templates/maps.js b/frontend/www/js_templates/maps.js
index f18af076c..5cc58ffb4 100644
--- a/frontend/www/js_templates/maps.js
+++ b/frontend/www/js_templates/maps.js
@@ -285,6 +285,7 @@ function NDDIMap(div_id, interdomain_mode, options){
var vendor = node_info.vendor;
var model = node_info.model;
var sw_version = node_info.sw_version;
+ var controller = node_info.controller;
var short_name = node_info.short_name;
var avail_endpoints = node_info.number_available_endpoints;
var barrier_bulk = node_info.barrier_bulk;
@@ -345,6 +346,7 @@ function NDDIMap(div_id, interdomain_mode, options){
point.model = model;
point.short_name = short_name;
point.sw_version = sw_version;
+ point.controller = controller;
point.barrier_bulk = barrier_bulk;
point.max_static_mac_flows = max_static_mac_flows;
point.dpid = dpid;
@@ -1370,17 +1372,18 @@ function NDDIMap(div_id, interdomain_mode, options){
var max_flows = geo.max_flows;
var openflow = geo.openflow;
var mpls = geo.mpls;
- var mgmt_addr = geo.mgmt_addr;
- var tcp_port = geo.tcp_port;
- var vendor = geo.vendor;
- var model = geo.model;
- var sw_version = geo.sw_version;
- var tx_delay_ms = geo.tx_delay_ms;
- var short_name = geo.short_name;
+ var mgmt_addr = geo.mgmt_addr;
+ var tcp_port = geo.tcp_port;
+ var vendor = geo.vendor;
+ var model = geo.model;
+ var sw_version = geo.sw_version;
+ var controller = geo.controller;
+ var tx_delay_ms = geo.tx_delay_ms;
+ var short_name = geo.short_name;
var barrier_bulk = geo.barrier_bulk;
var max_static_mac_flows = geo.max_static_mac_flows;
var dpid = geo.dpid;
- self.events['clickNode'].fire({name: node, lat: lat, lon: lon, node_id: node_id, vlan_range: range,default_forward: default_forward, default_drop: default_drop,max_flows: max_flows, tx_delay_ms: tx_delay_ms, feature: e.feature, barrier_bulk: barrier_bulk, max_static_mac_flows: max_static_mac_flows, dpid: dpid, openflow: openflow, mpls: mpls, mgmt_addr: mgmt_addr, tcp_port: tcp_port, vendor: vendor, model: model,short_name: short_name, sw_version: sw_version});
+ self.events['clickNode'].fire({name: node, lat: lat, lon: lon, node_id: node_id, vlan_range: range,default_forward: default_forward, default_drop: default_drop,max_flows: max_flows, tx_delay_ms: tx_delay_ms, feature: e.feature, barrier_bulk: barrier_bulk, max_static_mac_flows: max_static_mac_flows, dpid: dpid, openflow: openflow, mpls: mpls, mgmt_addr: mgmt_addr, tcp_port: tcp_port, vendor: vendor, model: model,short_name: short_name, sw_version: sw_version, controller: controller});
}
// otherwise we're clicking on a link
else{
diff --git a/frontend/www/js_templates/modify_cloud.js b/frontend/www/js_templates/modify_cloud.js
index 30f104288..fb98b692f 100644
--- a/frontend/www/js_templates/modify_cloud.js
+++ b/frontend/www/js_templates/modify_cloud.js
@@ -130,12 +130,11 @@ class GlobalState extends Component {
let addNetworkLoadingModal = $('#add-connection-loading');
addNetworkLoadingModal.modal('show');
-
try {
let vrfID = await provisionVRF(
session.data.workgroup_id,
this.connection.name,
- this.connection.description,
+ document.querySelector('#header-description').textContent,
this.connection.endpoints,
-1,
-1,
@@ -189,7 +188,7 @@ document.addEventListener('DOMContentLoaded', async function() {
description: state.connection.description,
editable: editable
});
-
+ addEditNameEvents(state.connection.description);
});
let addNetworkEndpoint = document.querySelector('#new-endpoint-button');
@@ -201,7 +200,6 @@ document.addEventListener('DOMContentLoaded', async function() {
map.on("loaded", function(){
this.updateMapFromSession(session);
});
-
});
async function update() {
diff --git a/frontend/www/js_templates/modify_l2vpn.js b/frontend/www/js_templates/modify_l2vpn.js
index 577cfb423..36620912b 100644
--- a/frontend/www/js_templates/modify_l2vpn.js
+++ b/frontend/www/js_templates/modify_l2vpn.js
@@ -54,10 +54,9 @@ class GlobalState extends Component {
let provisionModal = $('#modify-loading');
provisionModal.find('p').text("Give us a few seconds. We're modifying your connection now.");
provisionModal.modal('show');
-
provisionCircuit(
session.data.workgroup_id,
- this.circuit.description,
+ document.querySelector('#header-description').textContent,
this.circuit.endpoints,
this.circuit.provision_time,
this.circuit.remove_time,
@@ -147,6 +146,8 @@ async function update(props) {
let elem = NewEndpoint(e);
list.appendChild(elem);
});
+
+ addEditNameEvents(state.circuit.description);
}
document.addEventListener('DOMContentLoaded', async function() {
diff --git a/frontend/www/js_templates/phonebook.js b/frontend/www/js_templates/phonebook.js
index 01c61b67f..592f42e67 100644
--- a/frontend/www/js_templates/phonebook.js
+++ b/frontend/www/js_templates/phonebook.js
@@ -217,12 +217,12 @@ async function loadEntityList(parentEntity=null) {
if ((user.is_admin == 1 && user.type != 'read-only') || valid_users.includes(user.user_id)){
edit_entity_btn.style.display = 'block';
edit_entity_btn.onclick = function(){
- window.location.href = `[% path %]new/index.cgi?action=edit_entity&entity_id=${entityID}`;
+ window.location.href = `[% path %]index.cgi?action=edit_entity&entity_id=${entityID}`;
};
add_entity_btn.style.display = 'block';
add_entity_btn.onclick = function(){
- window.location.href = `[% path %]new/index.cgi?action=add_entity&entity_id=${entityID}`;
+ window.location.href = `[% path %]index.cgi?action=add_entity&entity_id=${entityID}`;
};
let user_list = document.querySelector('#user-list');
diff --git a/frontend/www/js_templates/welcome.js b/frontend/www/js_templates/welcome.js
index 1b15b1838..3c7f41412 100644
--- a/frontend/www/js_templates/welcome.js
+++ b/frontend/www/js_templates/welcome.js
@@ -13,14 +13,20 @@ document.addEventListener('DOMContentLoaded', function() {
});
async function deleteConnection(id, name) {
- let ok = confirm(`Are you sure you want to delete "${name}"?`);
- if (ok) {
- let deleteCircuitModal = $('#delete-circuit-loading');
- deleteCircuitModal.modal('show');
-
- await deleteVRF(session.data.workgroup_id, id);
- window.location = '?action=welcome';
+ let ok = confirm(`Are you sure you want to delete "${name}"?`);
+ if (ok) {
+ let deleteCircuitModal = $('#delete-circuit-loading');
+ deleteCircuitModal.modal('show');
+ try{
+ let result = await deleteVRF(session.data.workgroup_id, id);
+ window.location="?action=welcome";
+ }catch(error){
+ deleteCircuitModal.modal('hide');
+ alert('An error occured while deleting a VRF:\n ' + error);
}
+
+
+ }
}
async function deleteL2VPN(id, name) {
@@ -28,9 +34,13 @@ async function deleteL2VPN(id, name) {
if (ok) {
let deleteCircuitModal = $('#delete-circuit-loading');
deleteCircuitModal.modal('show');
-
- await deleteCircuit(session.data.workgroup_id, id);
- window.location = '?action=welcome';
+ try{
+ let result = await deleteCircuit(session.data.workgroup_id, id);
+ window.location="?action=welcome";
+ }catch(error){
+ deleteCircuitModal.modal('hide');
+ alert('An error occured while deleting a circuit:\n ' + error);
+ }
}
}
@@ -58,7 +68,7 @@ async function loadEntityList() {
let ok = true;
if (entities.length === 0) {
- html = '
There are no Layer 3 Connections currently provisioned. Click here to create one.
';
+ html = '
There are no Layer 3 Connections currently provisioned. Click here to create one.
';
}
entities.forEach(function(entity, index) {
@@ -179,13 +189,13 @@ async function loadL2VPNs() {
let ok = true;
if (circuits.length === 0) {
- html = '
There are no Layer 2 Connections currently provisioned. Click here to create one.
';
+ html = '
There are no Layer 2 Connections currently provisioned. Click here to create one.
';
}
circuits.forEach(function(circuit, index) {
ok = true;
let createdOn = new Date(circuit.created_on);
- let modifiedOn = new Date(circuit.last_edited);
+ let modifiedOn = new Date(circuit.last_modified_on);
let bg_color = '#fff';
let owner = 1;
if(circuit.workgroup_id != session.data.workgroup_id){
diff --git a/frontend/www/js_utilities/interface_acl_panel.js b/frontend/www/js_utilities/interface_acl_panel.js
index eb48ad9b6..6166d07fe 100644
--- a/frontend/www/js_utilities/interface_acl_panel.js
+++ b/frontend/www/js_utilities/interface_acl_panel.js
@@ -143,14 +143,14 @@ var get_interface_acl_panel = function(container_id, interface_id, options){
}
//required
url += "&allow_deny="+allow_deny;
- url += "&start="+vlan_start;
+ url += "&vlan_start="+vlan_start;
url += "&interface_id="+interface_id;
//optional
if(workgroup_id) {url += "&workgroup_id="+workgroup_id;}
if(entity_id) {url += "&entity_id="+entity_id;}
if(notes) {url += "¬es="+notes;}
- if(vlan_end) {url += "&end="+vlan_end;}
+ if(vlan_end) {url += "&vlan_end="+vlan_end;}
var ds = new YAHOO.util.DataSource(url);
ds.responseType = YAHOO.util.DataSource.TYPE_JSON;
diff --git a/frontend/www/new/index.cgi b/frontend/www/new/index.cgi
deleted file mode 100755
index d3f960b9a..000000000
--- a/frontend/www/new/index.cgi
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/perl
-
-#---------
-# This is the main workhorse service for serving up all the template toolkit
-# pages that serve the OE-SS frontend. There is nothing particularly special in here,
-# it just accepts what page the user wants to see and returns it templatized.
-#---------
-##-----
-##----- $HeadURL: svn+ssh://svn.grnoc.iu.edu/grnoc/oe-ss/frontend/trunk/www/index.cgi $
-##----- $Id$
-##----- $Date$
-##----- $LastChangedBy$
-##-----
-##----- Provides object oriented methods to interact with the DBus test
-##
-##-------------------------------------------------------------------------
-##
-##
-## Copyright 2011 Trustees of Indiana University
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-#
-use strict;
-use warnings;
-use OESS::Config;
-use OESS::Database;
-use Data::Dumper;
-use CGI;
-use Template;
-use Switch;
-use FindBin;
-use Log::Log4perl;
-
-Log::Log4perl::init('/etc/oess/logging.conf');
-
-
-
-sub main{
- my $config = new OESS::Config();
- my $db = OESS::Database->new();
- my $cgi = new CGI;
- my $tt = Template->new(INCLUDE_PATH => "$FindBin::Bin/..") || die $Template::ERROR;
-
- my $is_valid_user = $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'});
- if(!defined($is_valid_user)){
-
- #-- What to pass to the TT and what http headers to send
- my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
- $filename = "html_templates/denied2.html";
- $title = "Access Denied";
- $vars->{'admin_email'} = $db->get_admin_email();
-
- $vars->{'page'} = $filename;
- $vars->{'title'} = $title;
- $vars->{'breadcrumbs'} = $breadcrumbs;
- $vars->{'current_breadcrumb'} = $current_breadcrumb;
- $vars->{'is_admin'} = 0;
- $vars->{'path'} = "../";
- $vars->{'is_read_only'} = 1;
- $vars->{'version'} = OESS::Database::VERSION;
- $vars->{'network_type'} = $config->network_type;
-
- $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
- print "Content-type: text/html\n\n" . $output;
- return;
- }
-
- my $is_admin = $db->get_user_admin_status(username=>$ENV{'REMOTE_USER'})->[0]{'is_admin'};
- if (!defined $is_admin) {
- $is_admin = 0;
- }
- my $is_read_only = 0;
- my $user = $db->get_user_by_id( user_id => $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'}))->[0];
-
- #-- What to pass to the TT and what http headers to send
- my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
-
- #-- Figure out what we're trying to templatize here or default to welcome page.
- my $action = "welcome";
-
- if ($cgi->param('action') =~ /^(\w+)$/){
- $action = $1;
- }
-
- if ($user->{'status'} eq 'decom') {
- $action = "decom";
- }
-
- switch ($action) {
- case "modify_l2vpn" {
- $title = "Layer 2 Connection";
- $filename = "html_templates/modify_l2vpn.html";
- $current_breadcrumb = "Layer 2 Connection";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "Layer 2 Connection", url => "#"}
- ];
- }
- case "provision_l2vpn" {
- $title = "New Layer 2 Connection";
- $filename = "html_templates/provision_l2vpn.html";
- $current_breadcrumb = "New Layer 2 Connection";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "New Layer 2 Connection", url => "#"}
- ];
- }
- case "modify_cloud" {
- $title = "Layer 3 Connection";
- $filename = "html_templates/modify_cloud.html";
- $current_breadcrumb = "Layer 3 Connection";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "Layer 3 Connection", url => "#"}
- ];
- }
- case "provision_cloud" {
- $title = "New Layer 3 Connection";
- $filename = "html_templates/provision_cloud.html";
- $current_breadcrumb = "New Layer 3 Connection";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "New Layer 3 Connection", url => "#"}
- ];
- }
- case "phonebook" {
- $title = "Phonebook";
- $filename = "html_templates/phonebook.html";
- $current_breadcrumb = "Phonebook";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "Phonebook", url => "#"}
- ];
- }
- case "welcome" {
- $title = "Welcome";
- $filename = "html_templates/welcome.html";
- $current_breadcrumb = "Welcome";
- $breadcrumbs = [
- {title => "Welcome", url => "#"}
- ];
- }
- case "acl" {
- $filename = "html_templates/acl.html";
- $title = "Edit ACL";
- }
- case "decom" {
- $filename = "html_templates/denied.html";
- $title = "Access Denied";
- }
- case "edit_entity" {
- $filename = "html_templates/edit_entity.html";
- $current_breadcrumb = "Edit Entity";
- $title = "Edit Entity";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "Edit Entity", url => "#"}
- ];
- }
- case "add_entity" {
- $filename = "html_templates/add_entity.html";
- $current_breadcrumb = "Add Entity";
- $title = "Add Entity";
- $breadcrumbs = [
- {title => "Welcome", url => "?action=welcome"},
- {title => "Add Entity", url => "#"}
- ];
- }
- else {
- $filename = "html_templates/error.html";
- $title = "Error";
- }
- }
-
- $vars->{'g_port'} = $db->{grafana}->{'oess-interface'};
- $vars->{'g_l2_port'} = $db->{grafana}->{'oess-l2-interface'};
- $vars->{'g_peer'} = $db->{grafana}->{'oess-bgp-peer'};
- $vars->{'g_route'} = $db->{grafana}->{'oess-routing-table'};
-
- $vars->{'admin_email'} = $db->get_admin_email();
- $vars->{'page'} = $filename;
- $vars->{'title'} = $title;
- $vars->{'breadcrumbs'} = $breadcrumbs;
- $vars->{'current_breadcrumb'} = $current_breadcrumb;
- $vars->{'path'} = "../";
- $vars->{'is_admin'} = $is_admin;
- $vars->{'is_read_only'} = $is_read_only;
- $vars->{'version'} = OESS::Database::VERSION;
- $vars->{'network_type'} = $config->network_type;
-
- $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
- print "Content-type: text/html\n\n" . $output;
-}
-
-main();
diff --git a/frontend/www/old.cgi b/frontend/www/old.cgi
new file mode 100755
index 000000000..eacd2c3d0
--- /dev/null
+++ b/frontend/www/old.cgi
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+
+#---------
+# This is the main workhorse service for serving up all the template toolkit
+# pages that serve the OE-SS frontend. There is nothing particularly special in here,
+# it just accepts what page the user wants to see and returns it templatized.
+#---------
+##-----
+##----- $HeadURL: svn+ssh://svn.grnoc.iu.edu/grnoc/oe-ss/frontend/trunk/www/index.cgi $
+##----- $Id$
+##----- $Date$
+##----- $LastChangedBy$
+##-----
+##----- Provides object oriented methods to interact with the DBus test
+##
+##-------------------------------------------------------------------------
+##
+##
+## Copyright 2011 Trustees of Indiana University
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+#
+use strict;
+use warnings;
+use OESS::Config;
+use OESS::Database;
+use Data::Dumper;
+use CGI;
+use Template;
+use Switch;
+use FindBin;
+use Log::Log4perl;
+
+Log::Log4perl::init('/etc/oess/logging.conf');
+
+my $config = new OESS::Config();
+my $db= OESS::Database->new();
+
+
+my $ADD_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
+ {title => "Home", url => "?action=index"},
+ {title => "Endpoints", url => "?action=endpoints"},
+ {title => "Options", url => "?action=options"},
+ {title => "Primary Path", url => "?action=primary_path"},
+ {title => "Backup Path", url => "?action=backup_path"},
+ {title => "Scheduling", url => "?action=scheduling"},
+ {title => "Provisioning", url => "?action=provisioning"},
+ ];
+
+my $REMOVE_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
+ {title => "Home", url => "?action=index"},
+ {title => "Scheduling", url => "?action=remove_scheduling"},
+ {title => "Provisioning", url => "?action=remove_provisioning"},
+ ];
+
+my $HOME_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},
+ {title => "Home", url => "?action=index"}
+ ];
+
+my $DETAILS_BREADCRUMBS = [{title => "Workgroups", url => "?action=workgroups"},,
+ {title => "Home", url => "?action=index"},
+ {title => "Circuit Details", url => "?action=view_details"},
+ ];
+
+
+sub main{
+
+ my $cgi = new CGI;
+
+ my $tt = Template->new(INCLUDE_PATH => "$FindBin::Bin") || die $Template::ERROR;
+
+ my $is_valid_user = $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'});
+ if(!defined($is_valid_user)){
+
+ #-- What to pass to the TT and what http headers to send
+ my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
+ $filename = "html_templates/denied.html";
+ $title = "Access Denied";
+ $vars->{'admin_email'} = $db->get_admin_email();
+
+ $vars->{'page'} = $filename;
+ $vars->{'title'} = $title;
+ $vars->{'breadcrumbs'} = $breadcrumbs;
+ $vars->{'current_breadcrumb'} = $current_breadcrumb;
+ $vars->{'is_admin'} = 0;
+ $vars->{'is_read_only'} = 1;
+ $vars->{'version'} = OESS::Database::VERSION;
+
+ $tt->process("html_templates/page_base.html", $vars, \$output) or warn $tt->error();
+ print "Content-type: text/html\n\n" . $output;
+ return;
+ }
+
+ my $is_admin = $db->get_user_admin_status(username=>$ENV{'REMOTE_USER'})->[0]{'is_admin'};
+ if(!defined($is_admin)){
+ $is_admin = 0;
+ }
+ my $is_read_only =0;
+ my $user = $db->get_user_by_id( user_id => $db->get_user_id_by_auth_name( auth_name => $ENV{'REMOTE_USER'}))->[0];
+
+ #-- What to pass to the TT and what http headers to send
+ my ($vars, $output, $filename, $title, $breadcrumbs, $current_breadcrumb);
+
+ #-- Figure out what we're trying to templatize here or default to workgroups page.
+ my $action = "workgroups";
+
+ if ($cgi->param('action') =~ /^(\w+)$/){
+ $action = $1;
+ }
+
+ if ($user->{'status'} eq 'decom') {
+ $action = "decom";
+ }
+
+
+ switch ($action) {
+
+ case "workgroups" { $filename = "html_templates/workgroups.html";
+ $title = "Workgroups";
+ $breadcrumbs = [{title => "Workgroups", url => "?action=workgroups"}];
+ $current_breadcrumb = "Workgroups";
+ }
+ case "index" { $filename = "html_templates/index.html";
+ $title = "Home";
+ $breadcrumbs = $HOME_BREADCRUMBS;
+ $current_breadcrumb = "Home";
+ }
+ case "edit_details" { $filename = "html_templates/edit_details.html";
+ $title = "Details";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Details";
+ }
+
+ case "loop_circuit" { $filename = "html_templates/loop_circuit.html";
+ $title = "Loop Circuit";
+ $breadcrumbs = $DETAILS_BREADCRUMBS;
+ $current_breadcrumb = "Loop Circuit";
+ }
+ case "view_details" { $filename = "html_templates/view_details.html";
+ $title = "Circuit Details";
+ $breadcrumbs = $DETAILS_BREADCRUMBS;
+ $current_breadcrumb = "Circuit Details";
+ }
+ case "interdomain" { $filename = "html_templates/interdomain.html";
+ $title = "Interdomain Endpoints";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Endpoints";
+ }
+ case "endpoints" { $filename = "html_templates/endpoints.html";
+ $title = "Endpoints";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Endpoints";
+ }
+ case "options" { $filename = "html_templates/options.html";
+ $title = "Options";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Options";
+ }
+ case "primary_path" { $filename = "html_templates/primary_path.html";
+ $title = "Primary Path";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Primary Path";
+ }
+ case "backup_path" { $filename = "html_templates/backup_path.html";
+ $title = "Backup Path";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Backup Path";
+ }
+ case "scheduling" { $filename = "html_templates/scheduling.html";
+ $title = "Scheduling";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Scheduling";
+ }
+
+ case "provisioning" {
+ $filename = "html_templates/provisioning.html";
+ $title = "Provisioning";
+ $breadcrumbs = $ADD_BREADCRUMBS;
+ $current_breadcrumb = "Provisioning";
+ }
+ case "remove_scheduling" {
+ $filename = "html_templates/remove_scheduling.html";
+ $title = "Removal Scheduling";
+ $breadcrumbs = $REMOVE_BREADCRUMBS;
+ $current_breadcrumb = "Scheduling";
+ }
+ case "remove_provisioning" {
+ $filename = "html_templates/remove_provisioning.html";
+ $title = "Removal Provisioning";
+ $breadcrumbs = $REMOVE_BREADCRUMBS;
+ $current_breadcrumb = "Provisioning";
+ }
+ case "decom" {
+ $filename = "html_templates/denied.html";
+ $title = "Access Denied";
+ }
+ case "about" {
+ $filename = "html_templates/splash.html";
+ $title = "About";
+ }
+ else {
+ $filename = "html_templates/error.html";
+ $title = "Error";
+ }
+
+ }
+ $vars->{'admin_email'} = $db->get_admin_email();
+
+ $vars->{'page'} = $filename;
+ $vars->{'title'} = $title;
+ $vars->{'breadcrumbs'} = $breadcrumbs;
+ $vars->{'current_breadcrumb'} = $current_breadcrumb;
+ $vars->{'is_admin'} = $is_admin;
+ $vars->{'is_read_only'} = $is_read_only;
+ $vars->{'version'} = OESS::Database::VERSION;
+ $vars->{'network_type'} = $config->network_type;
+
+ #print STDERR Dumper($vars);
+ if ($action eq 'view_l3vpn' || $action eq 'provision_cloud' || $action eq 'modify_cloud' || $action eq 'phonebook' || $action eq 'welcome') {
+ $tt->process("html_templates/base.html", $vars, \$output) or warn $tt->error();
+ } else {
+ $tt->process("html_templates/page_base.html", $vars, \$output) or warn $tt->error();
+ }
+ print "Content-type: text/html\n\n" . $output;
+}
+
+
+main();
diff --git a/oess.spec b/oess.spec
index 98db9d10f..01f6d6fe1 100644
--- a/oess.spec
+++ b/oess.spec
@@ -1,14 +1,14 @@
Summary: OESS Metapackage
Name: oess
-Version: 2.0.11
-Release: 3%{?dist}
+Version: 2.0.12
+Release: 1%{?dist}
License: Apache
Group: GRNOC
#Source:
URL: http://globalnoc.iu.edu
Buildroot: %{_tmppath}/%{name}-root
-Requires: oess-core >= 2.0.11
-Requires: oess-frontend >= 2.0.11
+Requires: oess-core >= 2.0.12
+Requires: oess-frontend >= 2.0.12
%description
Package that installs all of the OESS packages
diff --git a/perl-lib/OESS/MANIFEST b/perl-lib/OESS/MANIFEST
index 73ca6ce7f..6a0d13892 100644
--- a/perl-lib/OESS/MANIFEST
+++ b/perl-lib/OESS/MANIFEST
@@ -1,7 +1,10 @@
+aj.patch
+entrypoint.dev.sh
+entrypoint.sh
etc/notification.tt.html
-etc/notification_vrf.tt.html
etc/notification_templates.tmpl
etc/notification_templates_vrf.tmpl
+etc/notification_vrf.tt.html
lib/OESS/ACL.pm
lib/OESS/Circuit.pm
lib/OESS/Cloud.pm
@@ -51,7 +54,6 @@ lib/OESS/MPLS/Switch.pm
lib/OESS/MPLS/Topology.pm
lib/OESS/Node.pm
lib/OESS/Notification.pm
-lib/OESS/Path.pm
lib/OESS/NSI/Constant.pm
lib/OESS/NSI/Daemon.pm
lib/OESS/NSI/MessageQueue.pm
@@ -61,22 +63,28 @@ lib/OESS/NSI/Query.pm
lib/OESS/NSI/Reservation.pm
lib/OESS/NSI/Server.pm
lib/OESS/NSI/Utils.pm
+lib/OESS/NSO/Client.pm
+lib/OESS/NSO/ClientStub.pm
+lib/OESS/NSO/ConnectionCache.pm
+lib/OESS/NSO/Discovery.pm
+lib/OESS/NSO/FWDCTL.pm
+lib/OESS/NSO/FWDCTLService.pm
+lib/OESS/Path.pm
lib/OESS/Peer.pm
lib/OESS/RabbitMQ/Client.pm
lib/OESS/RabbitMQ/Dispatcher.pm
+lib/OESS/RabbitMQ/Topic.pm
lib/OESS/Topology.pm
lib/OESS/Traceroute.pm
lib/OESS/User.pm
lib/OESS/VRF.pm
lib/OESS/Watchdog.pm
-lib/OESS/Workgroup.pm
lib/OESS/Webservice.pm
+lib/OESS/Workgroup.pm
Makefile.PL
MANIFEST This list of files
-perl-OESS-2.0.11.tar.gz
+perl-OESS-2.0.12.tar.gz
perl-OESS.spec
-share/fresh_backup.sql
-share/fresh_schema.sql
share/customer-templates/cisco/2900/ios124/template.txt
share/customer-templates/cisco/3700/ios124/template.txt
share/customer-templates/cisco/7200/ios124/template.txt
@@ -86,6 +94,8 @@ share/customer-templates/juniper/srx/junos95/template.txt
share/customer-templates/juniper/t/junos95/template.txt
share/customer-templates/paloalto/pa3000/panos803/template.txt
share/customer-templates/paloalto/pa5000/panos803/template.txt
+share/fresh_backup.sql
+share/fresh_schema.sql
share/mpls/templates/juniper/13.3R8/EVPN/ep_config.xml
share/mpls/templates/juniper/13.3R8/EVPN/ep_config_delete.xml
share/mpls/templates/juniper/13.3R8/L2CCC/ep_config.xml
@@ -128,6 +138,8 @@ share/upgrade/oess-1.2.5-1.2.5a
share/upgrade/oess-1.2.5a-2.0.0
share/upgrade/oess-2.0.0-2.0.1
share/upgrade/oess-2.0.1-2.0.2
+share/upgrade/oess-2.0.10-2.0.11
+share/upgrade/oess-2.0.11-2.0.12
share/upgrade/oess-2.0.2-2.0.3
share/upgrade/oess-2.0.3-2.0.4
share/upgrade/oess-2.0.4-2.0.5
@@ -136,7 +148,6 @@ share/upgrade/oess-2.0.6-2.0.7
share/upgrade/oess-2.0.7-2.0.8
share/upgrade/oess-2.0.8-2.0.9
share/upgrade/oess-2.0.9-2.0.10
-share/upgrade/oess-2.0.10-2.0.11
t/00-load_base.t
t/01-load_known_state.t
t/02-pod.t
@@ -146,6 +157,7 @@ t/acl-02-export.t
t/acl-03-logic.t
t/circuit-backup_path_flows.t
t/circuit-change_path.t
+t/circuit-change_path2.t
t/circuit-create.t
t/circuit-endpoint_flows.t
t/circuit-generate_clr.t
@@ -161,8 +173,12 @@ t/circuit-static_mac_addr.t
t/circuit-static_mac_addr_simple.t
t/conf/.oess_known_state.sql.swp
t/conf/database.xml
+t/conf/interface-speed-config.xml
t/conf/logging.conf
+t/conf/mpls/discovery.sql
+t/conf/mpls/discovery.xml
t/conf/oess_known_state.sql
+t/conf/passwd.xml
t/conf/snapp_config.xml
t/conf/snapp_known_state.sql
t/conf/SNMP/snapp/db/per_flow/111/111-1-145.rrd
@@ -219,6 +235,9 @@ t/entity-01-initialization.t
t/entity-02-logic.t
t/entity-03-export-save.t
t/entity-99-reset-db.t
+t/entity/select_interface.t
+t/entity/select_interface_gcp.t
+t/entity_cgi.t
t/flow_rule-compare_actions.t
t/flow_rule-compare_match.t
t/flow_rule-merge_actions.t
@@ -230,10 +249,19 @@ t/flow_rule-validate_flow.t
t/fwdctl-failover.t
t/fwdctl-topo_port_status.t
t/get_user_admin_status.t
+t/interface_cgi.t
+t/Interface_test.t
+t/l3vpn/interface-selection-gcp.t
t/maintenance-link.t
t/maintenance-node.t
t/mpls-discovery-interface.t
+t/mpls/discovery/handle_links.t
t/mpls/mx-add_vlan.t
+t/mpls/mx-add_vlan_xml.evpn.00.t
+t/mpls/mx-add_vlan_xml.l2ccc.00.t
+t/mpls/mx-add_vlan_xml.l2vpls.00.t
+t/mpls/mx-add_vlan_xml.l2vpn.00.t
+t/mpls/mx-add_vrf_xml.00.t
t/mpls/mx-commit.t
t/mpls/mx-connected.t
t/mpls/mx-disconnect.t
@@ -244,10 +272,19 @@ t/mpls/mx-get_LSPs.t
t/mpls/mx-get_routed_lsps.t
t/mpls/mx-get_system_information.t
t/mpls/mx-lock.t
+t/mpls/mx-modify_vrf.00.t
t/mpls/mx-remove_vlan.t
+t/mpls/mx-remove_vlan_xml.00.t
+t/mpls/mx-remove_vrf_xml.00.t
t/mpls/mx-unit_name_available.t
t/mpls/mx-unlock.t
t/mpls/mx-verify_connection.t
+t/mpls/mx-xml_configuration.00.t
+t/mpls/mx-xml_configuration.evpn.00.t
+t/mpls/mx-xml_configuration.l2ccc.00.t
+t/mpls/mx-xml_configuration.l2vpls.00.t
+t/mpls/mx-xml_configuration.l2vpn.00.t
+t/mpls/mx-xml_configuration.l3vpn.00.t
t/mpls/mx-xml_configuration.t
t/notification-send_notification.t
t/OESSDatabaseTester.pm
@@ -257,3 +294,47 @@ t/topology-is_path_up.t
t/topology-shortest_path.t
t/topology-validate_paths.t
t/traceroute_test.t
+t/vrf_cgi.t
+t/z-DB/ACL.create_delete.00.t
+t/z-DB/Circuit.t
+t/z-DB/Endpoint.find_available_unit.00.t
+t/z-DB/Endpoint.find_available_unit.01.t
+t/z-DB/Interface.create.00.t
+t/z-DB/Interface.update.00.t
+t/z-DB/Interface.update.01.t
+t/z-DB/Interface.update.02.t
+t/z-DB/Link.t
+t/z-DB/Node.t
+t/z-DB/Node.update.00.t
+t/z-DB/Path.t
+t/z-DB/Peer.create.00.t
+t/z-DB/Peer.update.00.t
+t/z-DB/User.add_user.00.t
+t/z-DB/User.delete_user.00.t
+t/z-DB/User.edit_user.00.t
+t/z-DB/User.edit_user.01.t
+t/z-DB/User.fetch_all.00.t
+t/z-DB/User.has_system_access.00.t
+t/z-DB/User.has_workgroup_access.00.t
+t/z-DB/Workgroup.add_user.00.t
+t/z-DB/Workgroup.create.00.t
+t/z-DB/Workgroup.create.01.t
+t/z-DB/Workgroup.edit_user_role.00.t
+t/z-DB/Workgroup.remove_user.00.t
+t/z-DB/Workgroup.update.00.t
+t/z-Object/ACL.vlan_allowed.00.t
+t/z-Object/AzureInterfaceSelector.t
+t/z-Object/BandwidthValidator.t
+t/z-Object/Endpoint._validate.00.t
+t/z-Object/Endpoint.t
+t/z-Object/Interface.t
+t/z-Object/L2Circuit.nso_diff.00.t
+t/z-Object/L2Circuit.t
+t/z-Object/NSO/FWDCTL.addVlan.00.t
+t/z-Object/NSO/FWDCTL.get_diff_text.00.t
+t/z-Object/NSO/FWDCTL.get_diff_text.01.t
+t/z-Object/Path.t
+t/z-Object/VRF.create.00.t
+t/z-Object/VRF.nso_diff.00.t
+t/z-Object/VRF.update.00.t
+t/z-Object/VRF.update.01.t
diff --git a/perl-lib/OESS/entrypoint.dev.sh b/perl-lib/OESS/entrypoint.dev.sh
new file mode 100644
index 000000000..6b0e7c664
--- /dev/null
+++ b/perl-lib/OESS/entrypoint.dev.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Configure and start all oess services
+
+# Start httpd
+htpasswd -b -c /usr/share/oess-frontend/www/.htpasswd admin ${OESS_PASSWORD}
+/usr/sbin/httpd
+sleep 1
+
+# Start mysql
+/usr/bin/mysql_install_db --user=mysql --ldata=/var/lib/mysql --force
+/usr/bin/mysqld_safe --datadir='/var/lib/mysql' &
+sleep 3
+/usr/bin/mysqladmin -u root password ${MYSQL_PASSWORD}
+/usr/bin/mysql --user=root --password=${MYSQL_PASSWORD} < /usr/share/doc/perl-OESS-2.0.12/share/nddi.sql
+
+# Start RabbitMQ
+rabbitmq-server start -detached
+sleep 15
+
+# Populate OESS config with mysql credentials
+sed -i "s/oess_test/oess/" /etc/oess/database.xml
+sed -i "s/test/$MYSQL_PASSWORD/" /etc/oess/database.xml
+sed -i "s/vpn\-mpls/$OESS_NETWORK_TYPE/" /etc/oess/database.xml
+sed -i "s/NSO_HOST/$NSO_HOST/" /etc/oess/database.xml
+sed -i "s/NSO_PASSWORD/$NSO_PASSWORD/" /etc/oess/database.xml
+sed -i "s/NSO_USERNAME/$NSO_USERNAME/" /etc/oess/database.xml
+sed -i "s/OESS_LOCAL_ASN/$OESS_LOCAL_ASN/" /etc/oess/database.xml
+sed -i "s/TSDS_URL/$TSDS_URL/" /etc/oess/database.xml
+sed -i "s/TSDS_PASSWORD/$TSDS_PASSWORD/" /etc/oess/database.xml
+sed -i "s/TSDS_USERNAME/$TSDS_USERNAME/" /etc/oess/database.xml
+sed -i "s/TSDS_REALM/$TSDS_REALM/" /etc/oess/database.xml
+
+# Start OESS
+/usr/bin/oess-notify.pl &
+/usr/bin/mpls_discovery.pl &
+/usr/bin/mpls_fwdctl.pl &
+/usr/bin/oess-nsi &
diff --git a/perl-lib/OESS/lib/OESS/Cloud.pm b/perl-lib/OESS/lib/OESS/Cloud.pm
index a8dc17238..0b636d7eb 100644
--- a/perl-lib/OESS/lib/OESS/Cloud.pm
+++ b/perl-lib/OESS/lib/OESS/Cloud.pm
@@ -146,6 +146,7 @@ sub setup_endpoints {
portal_url => $config->base_url,
vlan => $ep->tag
);
+
$ep->cloud_connection_id($connection_id);
push @$result, $ep;
diff --git a/perl-lib/OESS/lib/OESS/Cloud/BandwidthValidator.pm b/perl-lib/OESS/lib/OESS/Cloud/BandwidthValidator.pm
index aad408967..b58c9e1d0 100644
--- a/perl-lib/OESS/lib/OESS/Cloud/BandwidthValidator.pm
+++ b/perl-lib/OESS/lib/OESS/Cloud/BandwidthValidator.pm
@@ -82,7 +82,7 @@ sub is_bandwidth_valid {
}
# 1. Matched on interface interconnect type
- if ($self->{interface}->bandwidth > $selector->{max_bandwidth} || $self->{interface}->bandwidth < $selector->{min_bandwidth}) {
+ if ($self->{interface}->{'bandwidth'} > $selector->{max_bandwidth} || $self->{interface}->{'bandwidth'} < $selector->{min_bandwidth}) {
next;
}
# 2. Matched on interface speed
diff --git a/perl-lib/OESS/lib/OESS/Cloud/GCP.pm b/perl-lib/OESS/lib/OESS/Cloud/GCP.pm
index 23f0938e4..44ff36ea3 100644
--- a/perl-lib/OESS/lib/OESS/Cloud/GCP.pm
+++ b/perl-lib/OESS/lib/OESS/Cloud/GCP.pm
@@ -379,13 +379,13 @@ sub insert_interconnect_attachment {
my $api_response = $http->request($req);
if (!$api_response->is_success && $api_response->code == 500) {
$self->{logger}->error("insert_interconnect_attachment: HTTP 500");
- return;
+ die "Failed to provision google cloud endpoints, please try again later. If the problem persists contact support";
}
my $api_data = decode_json($api_response->content);
if (defined $api_data->{error}) {
$self->{logger}->error($api_data->{error}->{message});
- return;
+ die $api_data->{error}->{message};
}
$self->{logger}->info("insert_interconnect_attachment: Status is $api_data->{status}.");
diff --git a/perl-lib/OESS/lib/OESS/Config.pm b/perl-lib/OESS/lib/OESS/Config.pm
index 83cc43407..eaac120a5 100644
--- a/perl-lib/OESS/lib/OESS/Config.pm
+++ b/perl-lib/OESS/lib/OESS/Config.pm
@@ -82,6 +82,14 @@ sub db_credentials {
password => $password};
}
+=head2 filename
+
+=cut
+sub filename {
+ my $self = shift;
+ return $self->{config_filename};
+}
+
=head2 fwdctl_enabled
=cut
@@ -138,7 +146,7 @@ sub network_type {
}
my $type = $self->{'config'}->{'network_type'};
- my $valid_types = ['openflow', 'vpn-mpls', 'evpn-vxlan'];
+ my $valid_types = ['openflow', 'vpn-mpls', 'evpn-vxlan', 'nso', 'nso+vpn-mpls'];
foreach my $valid_type (@$valid_types) {
if ($type eq $valid_type) {
return $type;
@@ -236,4 +244,67 @@ sub third_party_mgmt {
return $self->{'config'}->{'third_party_mgmt'};
}
+=head2 nso_host
+
+=cut
+sub nso_host {
+ my $self = shift;
+ return if (!defined $self->{config}->{nso});
+ return $self->{config}->{nso}->{host};
+}
+
+=head2 nso_password
+
+=cut
+sub nso_password {
+ my $self = shift;
+ return if (!defined $self->{config}->{nso});
+ return $self->{config}->{nso}->{password};
+}
+
+=head2 nso_username
+
+=cut
+sub nso_username {
+ my $self = shift;
+ return if (!defined $self->{config}->{nso});
+ return $self->{config}->{nso}->{username};
+}
+
+=head2 tsds_url
+
+=cut
+sub tsds_url {
+ my $self = shift;
+ return if (!defined $self->{config}->{tsds});
+ return $self->{config}->{tsds}->{url};
+}
+
+=head2 tsds_password
+
+=cut
+sub tsds_password {
+ my $self = shift;
+ return if (!defined $self->{config}->{tsds});
+ return $self->{config}->{tsds}->{password};
+}
+
+=head2 tsds_username
+
+=cut
+sub tsds_username {
+ my $self = shift;
+ return if (!defined $self->{config}->{tsds});
+ return $self->{config}->{tsds}->{username};
+}
+
+=head2 tsds_realm
+
+=cut
+sub tsds_realm {
+ my $self = shift;
+ return if (!defined $self->{config}->{tsds});
+ return $self->{config}->{tsds}->{realm};
+}
+
1;
diff --git a/perl-lib/OESS/lib/OESS/DB/Circuit.pm b/perl-lib/OESS/lib/OESS/DB/Circuit.pm
index 811d55c27..8abb702da 100644
--- a/perl-lib/OESS/lib/OESS/DB/Circuit.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Circuit.pm
@@ -16,6 +16,7 @@ use Data::Dumper;
my $id = OESS::DB::Circuit::create(
db => $db,
model => {
+ status => $status,
name => $name,
description => $description,
user_id => $user_id,
@@ -38,11 +39,13 @@ sub create {
return (undef, 'Required argument `db` is missing.') if !defined $args->{db};
return (undef, 'Required argument `model` is missing.') if !defined $args->{model};
-
- my $circuit_state = 'active';
- if (defined $args->{model}->{provision_time}) {
- # TODO add provision event
- $circuit_state = 'scheduled';
+ my $circuit_state = $args->{model}->{status};
+ if(!defined($circuit_state)){
+ $circuit_state = 'active';
+ if (defined $args->{model}->{provision_time}) {
+ # TODO add provision event
+ $circuit_state = 'scheduled';
+ }
}
if (defined $args->{model}->{remove_time}) {
diff --git a/perl-lib/OESS/lib/OESS/DB/Endpoint.pm b/perl-lib/OESS/lib/OESS/DB/Endpoint.pm
index 84c47a76c..90920eeef 100644
--- a/perl-lib/OESS/lib/OESS/DB/Endpoint.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Endpoint.pm
@@ -145,12 +145,13 @@ sub fetch_all {
SELECT circuit_ep.circuit_edge_id AS circuit_ep_id, circuit_ep.circuit_id,
interface.interface_id, interface.name AS interface, interface.operational_state,
interface.description, interface.cloud_interconnect_id, interface.cloud_interconnect_type,
- node.node_id, node.name AS node,
+ node.node_id, node.name AS node, node_instantiation.controller,
unit, extern_vlan_id AS tag, inner_tag,
bandwidth, mtu, cloud_account_id, cloud_connection_id
FROM circuit_edge_interface_membership AS circuit_ep
JOIN interface ON interface.interface_id=circuit_ep.interface_id
JOIN node ON node.node_id=interface.node_id
+ JOIN node_instantiation ON node.node_id=node_instantiation.node_id and node_instantiation.end_epoch=-1
LEFT JOIN cloud_connection_vrf_ep as cloud on cloud.circuit_ep_id=circuit_ep.circuit_edge_id
$where
AND circuit_ep.end_epoch = -1
@@ -210,12 +211,13 @@ sub fetch_all {
interface.interface_id, interface.name AS interface, interface.operational_state,
interface.description, interface.cloud_interconnect_id, interface.cloud_interconnect_type,
interface_acl.eval_position,
- node.node_id, node.name AS node,
+ node.node_id, node.name AS node, node_instantiation.controller,
unit, tag, inner_tag,
bandwidth, mtu, cloud_account_id, cloud_connection_id
FROM vrf_ep
JOIN interface ON interface.interface_id=vrf_ep.interface_id
JOIN node ON node.node_id=interface.node_id
+ JOIN node_instantiation ON node.node_id=node_instantiation.node_id and node_instantiation.end_epoch=-1
JOIN interface_acl ON interface_acl.interface_id=interface.interface_id
LEFT JOIN entity ON entity.entity_id=interface_acl.entity_id
LEFT JOIN cloud_connection_vrf_ep as cloud on cloud.vrf_ep_id=vrf_ep.vrf_ep_id
diff --git a/perl-lib/OESS/lib/OESS/DB/Interface.pm b/perl-lib/OESS/lib/OESS/DB/Interface.pm
index cac943d3d..9752a079c 100644
--- a/perl-lib/OESS/lib/OESS/DB/Interface.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Interface.pm
@@ -86,6 +86,14 @@ sub fetch{
push(@{$in_use},@{OESS::DB::Interface::circuit_vlans_in_use(db => $db, interface_id => $interface_id)});
+
+ my $provisionable_bandwidth;
+ if ($interface->{cloud_interconnect_type} eq 'azure-express-route'){
+ $provisionable_bandwidth = $interface->{bandwidth}*4;
+ } elsif (defined $interface->{cloud_interconnect_type}){
+ $provisionable_bandwidth = $interface->{bandwidth};
+ }
+
return {
interface_id => $interface->{'interface_id'},
cloud_interconnect_type => $interface->{'cloud_interconnect_type'},
@@ -101,6 +109,7 @@ sub fetch{
acls => $acls,
used_vlans => $in_use,
bandwidth => $interface->{bandwidth},
+ provisionable_bandwidth => $provisionable_bandwidth,
utilized_bandwidth => $l2_utilized_bandwidth + $l3_utilized_bandwidth,
mtu => $interface->{mtu},
admin_state => $interface->{admin_state},
diff --git a/perl-lib/OESS/lib/OESS/DB/Link.pm b/perl-lib/OESS/lib/OESS/DB/Link.pm
index 999dcf81f..02c625819 100644
--- a/perl-lib/OESS/lib/OESS/DB/Link.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Link.pm
@@ -13,7 +13,7 @@ use Data::Dumper;
=head2 create
- my $id = OESS::DB::Link::create(
+ my ($id, $err) = OESS::DB::Link::create(
db => $db,
model => {
name => 'node-a-to-node-b',
@@ -51,6 +51,10 @@ sub create {
VALUES (?,?,?,?,?,?,?,UNIX_TIMESTAMP(NOW()),-1)
";
+ my $q3 = "
+ UPDATE interface set role='trunk' WHERE interface_id=? or interface_id=?
+ ";
+
my $link_id = $args->{db}->execute_query($q1, [
$args->{model}->{name},
$args->{model}->{remote_urn},
@@ -74,6 +78,14 @@ sub create {
return (undef, $args->{db}->get_error);
}
+ my $ok = $args->{db}->execute_query($q3, [
+ $args->{model}->{interface_a_id},
+ $args->{model}->{interface_z_id}
+ ]);
+ if (!defined $ok) {
+ return (undef, $args->{db}->get_error);
+ }
+
return ($link_id, undef);
}
@@ -171,7 +183,7 @@ sub fetch_history {
=head2 fetch_all
- my $acl = OESS::DB::Link::fetch_all(
+ my ($links, $err) = OESS::DB::Link::fetch_all(
db => $conn,
link_id => 1, # Optional
name => 'a-to-b', # Optional
@@ -234,6 +246,9 @@ sub fetch_all {
push @$params, 'link_instantiation.end_epoch=?';
push @$values, -1;
+ push @$params, 'link_instantiation.link_state!=?';
+ push @$values, 'decom';
+
my $where = (@$params > 0) ? 'WHERE ' . join(' AND ', @$params) : '';
my $q = "
@@ -259,7 +274,7 @@ sub fetch_all {
return (undef, "Couldn't find Links: " . $args->{db}->get_error);
}
- return $links;
+ return ($links, undef);
}
=head2 update
@@ -334,7 +349,6 @@ sub update {
return (undef, $args->{db}->get_error);
}
-
my $q2 = "
INSERT INTO link_instantiation (
link_id, openflow, mpls, link_state, interface_a_id, ip_a,
@@ -357,6 +371,23 @@ sub update {
return (undef, $args->{db}->get_error);
}
+ # Set role of interfaces to 'unknown' whenever a link is
+ # decom'd. This allows the link's interfaces to be used for other
+ # purposes after removal.
+ if ($args->{link}->{link_state} eq 'decom') {
+ my $q3 = "
+ UPDATE interface set role='unknown' WHERE interface_id=? or interface_id=?
+ ";
+
+ my $ok = $args->{db}->execute_query($q3, [
+ $args->{model}->{interface_a_id},
+ $args->{model}->{interface_z_id}
+ ]);
+ if (!defined $ok) {
+ return (undef, $args->{db}->get_error);
+ }
+ }
+
return ($link_instantiation_id, undef);
}
diff --git a/perl-lib/OESS/lib/OESS/DB/Node.pm b/perl-lib/OESS/lib/OESS/DB/Node.pm
index 20294a920..d5b0201f7 100644
--- a/perl-lib/OESS/lib/OESS/DB/Node.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Node.pm
@@ -34,18 +34,35 @@ sub fetch{
return $node->[0];
}
+=head2 fetch_all
+
+=cut
+sub fetch_all {
+ my %params = @_;
+ my $db = $params{'db'};
+ my $controller = $params{'controller'} || 'netconf';
+
+ return $db->execute_query(
+ "select * from node join node_instantiation on node.node_id=node_instantiation.node_id where node_instantiation.end_epoch=-1 and node_instantiation.controller=?",
+ [$controller]
+ );
+}
+
=head2 get_node_interfaces
=cut
sub get_node_interfaces{
- my $db = shift;
- my $node_id = shift;
+ my $args = {
+ db => undef,
+ node_id => undef,
+ @_
+ };
- my $interfaces = $db->execute_query("select * from interface where node_id = ?",[$node_id]);
+ my $interfaces = $args->{'db'}->execute_query("select * from interface where node_id = ?",[$args->{'node_id'}]);
my @ints;
foreach my $interface (@$interfaces){
- push(@ints, OESS::Interface->new(db => $db, interface_id => $interface->{'interface_id'}));
+ push(@ints, OESS::Interface->new(db => $args->{'db'}, interface_id => $interface->{'interface_id'}));
}
return \@ints;
@@ -147,4 +164,163 @@ sub _process_tag_string{
return \@tags;
}
+=head2 update
+
+ my $err = OESS::DB::Node::update(
+ db => $db,
+ node => {
+ node_id => 1,
+ name => 'host.examle.com', # Optional
+ latitude => 1, # Optional
+ longitude => 1, # Optional
+ operational_state_mpls => 'up', # Optional
+ vlan_tag_range => '1-4095', # Optional
+ pending_diff => 1 # Optional
+ short_name => 'host', # Optional
+
+ admin_state => 'active', # Optional
+ vendor => 'juniper', # Optional
+ model => 'mx', # Optional
+ sw_version => '13.3R3', # Optional
+ mgmt_addr => '192.168.1.1', # Optional
+ loopback_address => '10.0.0.1', # Optional
+ tcp_port => 830 # Optional
+ }
+ );
+ die $err if defined $err;
+
+=cut
+sub update {
+ my $args = {
+ db => undef,
+ node => undef,
+ @_
+ };
+
+ return 'Required argument `db` is missing.' if !defined $args->{db};
+ return 'Required argument `node` is missing.' if !defined $args->{node};
+ return 'Required argument `node->node_id` is missing.' if !defined $args->{node}->{node_id};
+
+ my $params = [];
+ my $values = [];
+ if (exists $args->{node}->{name}) {
+ push @$params, 'name=?';
+ push @$values, $args->{node}->{name};
+ }
+ if (exists $args->{node}->{longitude}) {
+ push @$params, 'longitude=?';
+ push @$values, $args->{node}->{longitude};
+ }
+ if (exists $args->{node}->{latitude}) {
+ push @$params, 'latitude=?';
+ push @$values, $args->{node}->{latitude};
+ }
+ if (exists $args->{node}->{operational_state_mpls}) {
+ push @$params, 'operational_state_mpls=?';
+ push @$values, $args->{node}->{operational_state_mpls};
+ }
+ if (exists $args->{node}->{vlan_tag_range}) {
+ push @$params, 'vlan_tag_range=?';
+ push @$values, $args->{node}->{vlan_tag_range};
+ }
+ if (exists $args->{node}->{pending_diff}) {
+ push @$params, 'pending_diff=?';
+ push @$values, $args->{node}->{pending_diff};
+ }
+ if (exists $args->{node}->{short_name}) {
+ push @$params, 'short_name=?';
+ push @$values, $args->{node}->{short_name};
+ }
+ my $fields = join(', ', @$params);
+ push @$values, $args->{node}->{node_id};
+
+ if ($fields ne ""){
+ my $ok = $args->{db}->execute_query(
+ "UPDATE node SET $fields WHERE node_id=?",
+ $values
+ );
+ if (!defined $ok) {
+ return $args->{db}->get_error;
+ }
+ }
+
+ my $iparams = [];
+ my $ivalues = [];
+
+ my $node = $args->{db}->execute_query(
+ "select * from node_instantiation where end_epoch=-1 and node_id=?",
+ [ $args->{node}->{node_id} ]
+ );
+ return $args->{db}->get_error if !defined $node;
+ return "Couldn't find instantiation for node $args->{node}->{node_id}." if !defined $node->[0];
+ $node = $node->[0];
+
+ my $modified = 0;
+ if (exists $args->{node}->{admin_state} && $args->{node}->{admin_state} ne $node->{admin_state}) {
+ $modified = 1;
+ $node->{admin_state} = $args->{node}->{admin_state};
+ }
+ if (exists $args->{node}->{vendor} && $args->{node}->{vendor} ne $node->{vendor}) {
+ $modified = 1;
+ $node->{vendor} = $args->{node}->{vendor};
+ }
+ if (exists $args->{node}->{model} && $args->{node}->{model} ne $node->{model}) {
+ $modified = 1;
+ $node->{model} = $args->{node}->{model};
+ }
+ if (exists $args->{node}->{sw_version} && $args->{node}->{sw_version} ne $node->{sw_version}) {
+ $modified = 1;
+ $node->{sw_version} = $args->{node}->{sw_version};
+ }
+ if (exists $args->{node}->{mgmt_addr} && $args->{node}->{mgmt_addr} ne $node->{mgmt_addr}) {
+ $modified = 1;
+ $node->{mgmt_addr} = $args->{node}->{mgmt_addr};
+ }
+ if (exists $args->{node}->{loopback_address} && $args->{node}->{loopback_address} ne $node->{loopback_address}) {
+ $modified = 1;
+ $node->{loopback_address} = $args->{node}->{loopback_address};
+ }
+ if (exists $args->{node}->{tcp_port} && $args->{node}->{tcp_port} != $node->{tcp_port}) {
+ $modified = 1;
+ $node->{tcp_port} = $args->{node}->{tcp_port};
+ }
+
+ # No changes required to instantiation table
+ return if (!$modified);
+
+ my $inst_ok = $args->{db}->execute_query(
+ "UPDATE node_instantiation SET end_epoch=UNIX_TIMESTAMP(NOW()) WHERE node_id=? and end_epoch=-1",
+ [$args->{node}->{node_id}]
+ );
+ if (!defined $inst_ok) {
+ return $args->{db}->get_error;
+ }
+ $inst_ok = $args->{db}->execute_query("
+ INSERT INTO node_instantiation (
+ admin_state, vendor, model, sw_version, mgmt_addr,
+ loopback_address, tcp_port, node_id, openflow, mpls,
+ dpid, start_epoch, end_epoch
+ ) VALUES (?,?,?,?,?,?,?,?,?,?,?,UNIX_TIMESTAMP(NOW()),-1)
+ ",
+ [
+ $node->{admin_state},
+ $node->{vendor},
+ $node->{model},
+ $node->{sw_version},
+ $node->{mgmt_addr},
+ $node->{loopback_address},
+ $node->{tcp_port},
+ $args->{node}->{node_id},
+ $args->{node}->{openflow} || 0,
+ $args->{node}->{mpls} || 1,
+ $node->{dpid}
+ ]
+ );
+ if (!defined $inst_ok) {
+ return $args->{db}->get_error;
+ }
+
+ return;
+}
+
1;
diff --git a/perl-lib/OESS/lib/OESS/DB/Peer.pm b/perl-lib/OESS/lib/OESS/DB/Peer.pm
index 918030ff3..5416e6e0a 100644
--- a/perl-lib/OESS/lib/OESS/DB/Peer.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Peer.pm
@@ -200,6 +200,10 @@ sub update {
push @$params, 'bfd=?';
push @$values, $args->{peer}->{bfd};
}
+ if (defined $args->{peer}->{md5_key}) {
+ push @$params, 'md5_key=?';
+ push @$values, $args->{peer}->{md5_key};
+ }
my $fields = join(', ', @$params);
push @$values, $args->{peer}->{vrf_ep_peer_id};
diff --git a/perl-lib/OESS/lib/OESS/DB/User.pm b/perl-lib/OESS/lib/OESS/DB/User.pm
index 1f7fef100..56642a206 100644
--- a/perl-lib/OESS/lib/OESS/DB/User.pm
+++ b/perl-lib/OESS/lib/OESS/DB/User.pm
@@ -1,12 +1,14 @@
-#!/usr/bin/perl
-
use strict;
use warnings;
-use OESS::Workgroup;
-use OESS::DB::Workgroup;
package OESS::DB::User;
+use Data::Dumper;
+
+use OESS::DB::Circuit;
+use OESS::DB::Endpoint;
+use OESS::DB::Workgroup;
+
=head2 fetch
=cut
@@ -302,7 +304,7 @@ sub delete_user {
sub edit_user {
my %params = @_;
my $db = $params{'db'};
-
+
my $user_id = $params{'user_id'};
my $given_name = $params{'given_name'};
my $family_name = $params{'family_name'};
@@ -317,37 +319,50 @@ sub edit_user {
return (undef, 'Required argument `email` is missing.') if !defined $email;
return (undef, 'Required argument `auth_names` is missing.') if !defined $auth_names;
return (undef, 'Required argument `status` is missing.') if !defined $status;
-
+
if ($given_name =~ /^system$/ || $family_name =~ /^system$/) {
return(undef, "User 'system' is reserved.");
}
+ my $query = "UPDATE user SET email = ?, given_names = ?, family_name = ?, status = ? WHERE user_id = ?";
- my $query = "UPDATE user SET email = ?, given_names = ?, family_name = ?, status = ? WHERE user_id = $user_id";
-
- my $results = $db->execute_query($query, [$email, $given_name, $family_name, $status]);
-
+ my $results = $db->execute_query($query, [$email, $given_name, $family_name, $status, $user_id]);
if (!defined $user_id || $results == 0) {
return (undef, "Unable to edit user - does this user actually exist?");
}
- # TODO Blindly removing and adding remote_auth entries for a user
- # causes a lot of churn in database ids. Modify this logic to only
- # update the remote_auth table when required.
- $db->execute_query("DELETE FROM remote_auth WHERE user_id = ?", [$user_id]);
+ if (ref($auth_names) ne 'ARRAY') {
+ $auth_names = [$auth_names];
+ }
- if (ref($auth_names) eq 'ARRAY') {
- foreach my $name (@$auth_names){
- if (length $name >=1) {
- $query = "INSERT INTO remote_auth (auth_name, user_id) VALUES (?, ?)";
- $db->execute_query($query, [$name,$user_id]);
- }
+ my $uindex = {};
+ my $usernames = $db->execute_query("select * from remote_auth where user_id=?", [$user_id]);
+ if (!defined $usernames) {
+ warn "edit_user called on user without any known usernames.";
+ $usernames = [];
+ }
+ foreach my $u (@$usernames) {
+ $uindex->{$u->{auth_name}} = $u;
+ }
+
+ foreach my $name (@$auth_names) {
+ if (defined $uindex->{$name}) {
+ delete $uindex->{$name};
+ next;
}
- } else {
- return (undef, 'Auth_Names is required to be at least 1 character.') if length $auth_names <1;
- $query = "INSERT INTO remote_auth (auth_name, user_id) VALUES (?, ?)";
- $db->execute_query($query, [$auth_names, $user_id]);
- }
+
+ return (undef, 'auth_names is required to be at least 1 character.') if length $auth_names < 1;
+
+ my $ok = $db->execute_query("INSERT INTO remote_auth (auth_name, user_id) VALUES (?, ?)", [$name, $user_id]);
+ return (undef, $db->get_error) if !defined $ok;
+
+ delete $uindex->{$name};
+ }
+
+ foreach my $name (keys %$uindex) {
+ my $ok = $db->execute_query("delete from remote_auth where auth_name=?", [$name]);
+ return (undef, $db->get_error) if !defined $ok;
+ }
return (1,undef)
}
@@ -626,4 +641,149 @@ sub has_workgroup_access {
}
}
}
+
+=head2 has_circuit_permission
+
+=over
+
+=item db
+ Denotes the database we are checking for access
+
+=item user_id
+ Denotes the user_id of the user whose access we are checking
+
+=item username
+ Denotes the username of the user whose access we are checking
+
+=item circuit_id
+ Denotes the circuit_id of the circuit we checking the users permissions in
+
+=item permission
+ Denotes the level of access the user needs for a particular action. May be 'create', 'read', 'update', or 'delete'.
+
+=back
+
+ my $results = OESS::DB::User::has_circuit_permission(
+ db => $db,
+ user_id => $user_id,
+ circuit_id => $circuit_id,
+ permission => 'update'
+ );
+
+has_circuit_permission checks if the specified user has appropriate
+permission for that circuit. Permissions are determined by looking up
+circuit details, pairing those details against the user's workgroups,
+and then fetching the user's role within those workgroups.
+
+=cut
+sub has_circuit_permission {
+ my %params = @_;
+ my $db = $params{'db'};
+ my $user_id = $params{'user_id'};
+ my $username = $params{'username'};
+ my $circuit_id = $params{'circuit_id'};
+ my $permission = $params{'permission'};
+
+ return (0, "Required argument 'db' is missing.") if !defined $db;
+ return (0, "Required to pass either 'user_id' or 'username'.") if !defined $user_id && !defined $username;
+ return (0, "Required argument 'circuit_id' is missing.") if !defined $circuit_id;
+ return (0, "Required argument 'permission' is missing.") if !defined $permission;
+
+ my $permissions = {
+ create => undef,
+ read => undef,
+ update => undef,
+ delete => undef,
+ };
+ if (!exists $permissions->{$permission}) {
+ return (0, "Required argument 'permission' must be 'create', 'read', 'update', or 'delete'.");
+ }
+
+ my $user;
+ if (!defined $user_id) {
+ $user = OESS::DB::User::fetch(db => $db, username => $username);
+ } else {
+ $user = OESS::DB::User::fetch(db => $db, user_id => $user_id);
+ }
+ if (!defined $user || $user->{'status'} eq 'decom'){
+ return (0, "Invalid or decommissioned user specified.");
+ }
+
+ my $circuit = OESS::DB::Circuit::fetch_circuit(db => $db, circuit_id => $circuit_id)->[0];
+ if (!defined $circuit || $circuit->{'state'} eq 'decom') {
+ return (0, "Invalid or decommissioned circuit specified.");
+ }
+
+ # Permissions for admin users
+ my $admin_results = $db->execute_query(
+ "SELECT role
+ FROM user_workgroup_membership JOIN workgroup
+ ON user_workgroup_membership.workgroup_id=workgroup.workgroup_id
+ WHERE workgroup.type='admin' AND user_workgroup_membership.user_id=?",
+ [$user->{user_id}]
+ );
+ $admin_results = [] if !defined $admin_results;
+ foreach my $result (@$admin_results) {
+ if ($result->{role} eq 'admin' || $result->{role} eq 'normal') {
+ $permissions->{create} = 1;
+ $permissions->{read} = 1;
+ $permissions->{update} = 1;
+ $permissions->{delete} = 1;
+ } else {
+ $permissions->{read} = 1;
+ }
+ }
+
+ # Permissions for users in the circuit owner's workgroup
+ my $workgroup_results = $db->execute_query(
+ "SELECT role
+ FROM user_workgroup_membership
+ WHERE user_workgroup_membership.user_id=? and user_workgroup_membership.workgroup_id=?",
+ [$user->{user_id}, $circuit->{workgroup_id}]
+ );
+ $workgroup_results = [] if !defined $workgroup_results;
+ foreach my $result (@$workgroup_results) {
+ if ($result->{role} eq 'admin' || $result->{role} eq 'normal') {
+ $permissions->{create} = 1;
+ $permissions->{read} = 1;
+ $permissions->{update} = 1;
+ $permissions->{delete} = 1;
+ } else {
+ $permissions->{read} = 1;
+ }
+ }
+
+ # Permissions for users in the circuit's interfaces' owner workgroups
+ my $interface_results = $db->execute_query(
+ "SELECT user_workgroup_membership.role
+ FROM user_workgroup_membership JOIN interface
+ ON user_workgroup_membership.workgroup_id=interface.workgroup_id
+ JOIN circuit_edge_interface_membership AS circuit_ep
+ ON circuit_ep.interface_id=interface.interface_id AND circuit_ep.end_epoch=-1
+ WHERE user_workgroup_membership.user_id=? AND circuit_ep.circuit_id=?
+ ",
+ [$user->{user_id}, $circuit->{circuit_id}]
+ );
+ $interface_results = [] if !defined $interface_results;
+ foreach my $result (@$interface_results) {
+ if ($result->{role} eq 'admin' || $result->{role} eq 'normal') {
+ $permissions->{read} = 1;
+ # TODO Ideally interface owners may remove endpoints from
+ # any circuit which terminate on their interfaces,
+ # although is not supported at this time.
+ #
+ # $permissions->{update} = 1;
+ } else {
+ $permissions->{read} = 1;
+ }
+ }
+
+ if (!$permissions->{$permission}) {
+ return (0, "User $user->{username} doesn't have $permission permission for circuit $circuit_id.");
+ }
+ return (1, undef);
+}
+
+
+
1;
diff --git a/perl-lib/OESS/lib/OESS/DB/Workgroup.pm b/perl-lib/OESS/lib/OESS/DB/Workgroup.pm
index f56c87c12..4beaefc58 100644
--- a/perl-lib/OESS/lib/OESS/DB/Workgroup.pm
+++ b/perl-lib/OESS/lib/OESS/DB/Workgroup.pm
@@ -75,7 +75,7 @@ sub fetch_all {
@_
};
- my $res = $args->{db}->execute_query("select * from workgroup where status='active'", []);
+ my $res = $args->{db}->execute_query("select * from workgroup where status='active' order by name", []);
if (!defined $res) {
return (undef, $args->{db}->get_error);
}
diff --git a/perl-lib/OESS/lib/OESS/Database.pm b/perl-lib/OESS/lib/OESS/Database.pm
index 9052668d3..e8294ce13 100644
--- a/perl-lib/OESS/lib/OESS/Database.pm
+++ b/perl-lib/OESS/lib/OESS/Database.pm
@@ -31,11 +31,11 @@ OESS::Database - Database Interaction Module
=head1 VERSION
-Version 2.0.11
+Version 2.0.12
=cut
-our $VERSION = '2.0.11';
+our $VERSION = '2.0.12';
=head1 SYNOPSIS
@@ -83,7 +83,7 @@ use Data::Dumper;
use Socket qw( inet_aton inet_ntoa);
-use constant VERSION => '2.0.11';
+use constant VERSION => '2.0.12';
use constant MAX_VLAN_TAG => 4096;
use constant MIN_VLAN_TAG => 1;
use constant OESS_PW_FILE => "/etc/oess/.passwd.xml";
@@ -1122,9 +1122,9 @@ sub get_current_nodes{
my $type = $args{'type'};
if ($type eq 'mpls') {
- $nodes = $self->_execute_query("select node.*, node_instantiation.* from node,node_instantiation where node.node_id = node_instantiation.node_id and node_instantiation.end_epoch = -1 and node_instantiation.admin_state != 'decom' and node_instantiation.mpls = 1 order by node.name",[]);
+ $nodes = $self->_execute_query("select node.*, node_instantiation.* from node,node_instantiation where node.node_id = node_instantiation.node_id and node_instantiation.end_epoch = -1 and node_instantiation.admin_state != 'decom' and node_instantiation.controller = 'netconf' order by node.name",[]);
} elsif ($type eq 'openflow') {
- $nodes = $self->_execute_query("select node.*, node_instantiation.* from node,node_instantiation where node.node_id = node_instantiation.node_id and node_instantiation.end_epoch = -1 and node_instantiation.admin_state != 'decom' and node_instantiation.openflow = 1 order by node.name",[]);
+ $nodes = $self->_execute_query("select node.*, node_instantiation.* from node,node_instantiation where node.node_id = node_instantiation.node_id and node_instantiation.end_epoch = -1 and node_instantiation.admin_state != 'decom' and node_instantiation.controller = 'openflow' order by node.name",[]);
} else {
$nodes = $self->_execute_query("select node.*, node_instantiation.* from node,node_instantiation where node.node_id = node_instantiation.node_id and node_instantiation.end_epoch = -1 and node_instantiation.admin_state != 'decom' order by node.name",[]);
}
@@ -1486,6 +1486,7 @@ sub get_map_layers {
node.name as node_name,
node.node_id,
node.short_name,
+ node_instantiation.controller,
node_instantiation.openflow,
node_instantiation.mpls,
node_instantiation.vendor,
@@ -1555,12 +1556,13 @@ HERE
"node_id" => $row->{'node_id'},
"openflow" => $row->{'openflow'},
"mpls" => $row->{'mpls'},
- "short_name" => $row->{'short_name'},
- "vendor" => $row->{'vendor'},
- "model" => $row->{'model'},
- "sw_version" => $row->{'sw_version'},
- "mgmt_addr" => $row->{'mgmt_addr'},
- "tcp_port" => $row->{'tcp_port'},
+ "short_name" => $row->{'short_name'},
+ "controller" => $row->{'controller'},
+ "vendor" => $row->{'vendor'},
+ "model" => $row->{'model'},
+ "sw_version" => $row->{'sw_version'},
+ "mgmt_addr" => $row->{'mgmt_addr'},
+ "tcp_port" => $row->{'tcp_port'},
"vlan_range" => $row->{'vlan_tag_range'},
"default_drop" => $row->{'default_drop'},
"default_forward" => $row->{'default_forward'},
@@ -1582,7 +1584,9 @@ HERE
}
my $links = $self->get_current_links(type => 'openflow');
+warn Dumper($links);
my $mpls_links = $self->get_current_links(type => 'mpls');
+warn Dumper($mpls_links);
foreach my $link (@$mpls_links){
push(@$links, $link);
}
@@ -7983,6 +7987,7 @@ sub get_node_by_interface_id {
lat => $lat,
long => $long,
port => $port,
+ controller => $controller,
vendor => $vendor,
model => $model,
sw_ver => $sw_ver);
@@ -7993,13 +7998,9 @@ sub add_mpls_node{
my $self = shift;
my %args = @_;
- #TODO: PARAM CHECKS
-
- warn Data::Dumper::Dumper(%args);
-
$self->_start_transaction();
- my $query = "insert into node (name, short_name, latitude, longitude, operational_state_mpls,network_id) VALUES (?,?,?,?,?,?)";
+ my $query = "insert into node (name, short_name, latitude, longitude, operational_state_mpls, network_id) VALUES (?,?,?,?,?,?)";
my $res = $self->_execute_query($query, [$args{'name'},$args{'short_name'},$args{'lat'},$args{'long'},'unknown',1]);
warn "New Node: " . Data::Dumper::Dumper($res);
@@ -8014,6 +8015,7 @@ sub add_mpls_node{
openflow => 0,
mpls => 1,
admin_state => 'active',
+ controller => $args{'controller'} || 'netconf',
vendor => $args{'vendor'},
model => $args{'model'},
sw_version => $args{'sw_ver'},
@@ -8131,16 +8133,14 @@ sub create_node_instance{
$args{'dpid'} = unpack('N', $data);
}
- my $res = $self->_execute_query("insert into node_instantiation (node_id,end_epoch,start_epoch,mgmt_addr,admin_state,dpid,vendor,model,sw_version,mpls,openflow ) VALUES (?,?,?,?,?,?,?,?,?,?,?)",[$args{'node_id'},-1,time(),$args{'mgmt_addr'},$args{'admin_state'},$args{'dpid'},$args{'vendor'},$args{'model'},$args{'sw_version'},$args{'mpls'},$args{'openflow'}]);
+ my $res = $self->_execute_query("insert into node_instantiation (node_id,end_epoch,start_epoch,mgmt_addr,admin_state,dpid,controller,vendor,model,sw_version,mpls,openflow ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",[$args{'node_id'},-1,time(),$args{'mgmt_addr'},$args{'admin_state'},$args{'dpid'},$args{'controller'},$args{'vendor'},$args{'model'},$args{'sw_version'},$args{'mpls'},$args{'openflow'}]);
if(!defined($res)){
$self->_set_error("Unable to create new node instantiation");
return;
}
-
return 1;
-
}
=head2 update_node_operational_state
diff --git a/perl-lib/OESS/lib/OESS/Endpoint.pm b/perl-lib/OESS/lib/OESS/Endpoint.pm
index 4eebc4db1..63cfb7cde 100644
--- a/perl-lib/OESS/lib/OESS/Endpoint.pm
+++ b/perl-lib/OESS/lib/OESS/Endpoint.pm
@@ -112,61 +112,17 @@ sub new{
if ((defined($self->circuit_id()) && $self->circuit_id() != -1) ||
(defined($self->vrf_endpoint_id()) && $self->vrf_endpoint_id() != -1)){
- $self->_fetch_from_db();
- }else{
- $self->_build_from_model();
+ $self->{model} = $self->_fetch_from_db();
+ }
+ if (!defined $self->{model}) {
+ $self->{logger}->error("Couldn't load Endpoint object from database or model.");
+ return;
}
+ $self->from_hash($self->{model});
return $self;
}
-=head2 _build_from_model
-
-=cut
-sub _build_from_model{
- my $self = shift;
-
- $self->{'inner_tag'} = $self->{'model'}->{'inner_tag'};
- $self->{'tag'} = $self->{'model'}->{'tag'};
- $self->{'unit'} = $self->{'model'}->{'unit'};
- $self->{'bandwidth'} = $self->{'model'}->{'bandwidth'};
- $self->{cloud_account_id} = $self->{model}->{cloud_account_id};
- $self->{cloud_connection_id} = $self->{model}->{cloud_connection_id};
- $self->{cloud_interconnect_id} = $self->{model}->{cloud_interconnect_id};
- $self->{cloud_interconnect_type} = $self->{model}->{cloud_interconnect_type};
- $self->{mtu} = $self->{model}->{mtu};
-
- $self->{circuit_ep_id} = $self->{model}->{circuit_edge_id} || $self->{model}->{circuit_ep_id};
- $self->{vrf_endpoint_id} = $self->{model}->{vrf_endpoint_id} || $self->{model}->{vrf_ep_id};
-
- $self->{'type'} = $self->{'model'}->{'type'};
- $self->{'node'} = $self->{'model'}->{'node'};
- $self->{'node_id'} = $self->{'model'}->{'node_id'};
- $self->{'interface'} = $self->{'model'}->{'interface'};
- $self->{'interface_id'} = $self->{'model'}->{'interface_id'};
- $self->{'entity'} = $self->{'model'}->{'entity'};
- $self->{'entity_id'} = $self->{'model'}->{'entity_id'};
- $self->{'description'} = $self->{'model'}->{'description'};
- $self->{'operational_state'} = $self->{'model'}->{'operational_state'};
- # The default selection method is to find the first interface that
- # has supports C
and has C available.
-
- # As there is only one interface per AWS Entity there is no
- # special selection method.
-
- # Interface selection for a GCP Entity is based purely on the user
- # provided GCP pairing key.
-
- # Interface selection for an Azure Entity is somewhat
- # irrelevent. Each interface of the Azure port pair is configured
- # similarly with the only difference between the two being the
- # peer addresses assigned to each.
-
- $self->{circuit_id} = $self->{model}->{circuit_id};
- $self->{vrf_id} = $self->{model}->{vrf_id};
- $self->{start_epoch} = $self->{model}->{start_epoch};
-}
-
=head2 to_hash
=cut
@@ -179,6 +135,7 @@ sub to_hash{
$obj->{'interface_id'} = $self->{'interface_id'};
$obj->{'node'} = $self->{'node'};
$obj->{'node_id'} = $self->{'node_id'};
+ $obj->{'controller'} = $self->{'controller'};
$obj->{'description'} = $self->{'description'};
$obj->{'operational_state'} = $self->{'operational_state'};
$obj->{'inner_tag'} = $self->inner_tag();
@@ -211,7 +168,7 @@ sub to_hash{
} else {
$obj->{'circuit_id'} = $self->circuit_id();
$obj->{'circuit_ep_id'} = $self->circuit_ep_id();
- $obj->{'start_epoch'} = $self->start_epoch();
+ $obj->{'start_epoch'} = $self->{start_epoch};
}
return $obj;
@@ -219,6 +176,19 @@ sub to_hash{
=head2 from_hash
+The default selection method is to find the first interface that has
+supports C and has C available.
+
+As there is only one interface per AWS Entity there is no special
+selection method.
+
+Interface selection for a GCP Entity is based purely on the user
+provided GCP pairing key.
+
+Interface selection for an Azure Entity is somewhat irrelevent. Each
+interface of the Azure port pair is configured similarly with the only
+difference between the two being the peer addresses assigned to each.
+
=cut
sub from_hash{
my $self = shift;
@@ -229,6 +199,7 @@ sub from_hash{
$self->{'interface_id'} = $hash->{'interface_id'};
$self->{'node'} = $hash->{'node'};
$self->{'node_id'} = $hash->{'node_id'};
+ $self->{'controller'} = $hash->{'controller'};
$self->{'description'} = $hash->{'description'};
$self->{'operational_state'} = $hash->{'operational_state'};
$self->{'inner_tag'} = $hash->{'inner_tag'};
@@ -241,13 +212,20 @@ sub from_hash{
$self->{'mtu'} = $hash->{'mtu'};
$self->{'unit'} = $hash->{'unit'};
- if ($self->{'type'} eq 'vrf' || !defined $hash->{'circuit_ep_id'}) {
- $self->{'peers'} = $hash->{'peers'};
+ if ($self->{'type'} eq 'vrf' || (!defined $hash->{'circuit_edge_id'} && !defined $hash->{'circuit_ep_id'})) {
+ # $self->{'peers'} = $hash->{'peers'};
$self->{'vrf_id'} = $hash->{'vrf_id'};
$self->{'vrf_endpoint_id'} = $hash->{'vrf_endpoint_id'} || $hash->{'vrf_ep_id'};
+
+ # if (defined $hash->{peers}) {
+ # $self->{peers} = [];
+ # foreach my $peer (@{$hash->{peers}}) {
+ # push(@{$self->{peers}}, new OESS::Peer(db => $self->{db}, model => $peer));
+ # }
+ # }
} else {
$self->{'circuit_id'} = $hash->{'circuit_id'};
- $self->{'circuit_ep_id'} = $hash->{'circuit_ep_id'};
+ $self->{'circuit_ep_id'} = $hash->{'circuit_edge_id'} || $hash->{'circuit_ep_id'};
$self->{start_epoch} = $hash->{start_epoch};
}
@@ -286,7 +264,7 @@ sub _fetch_from_db{
}
}
- $self->from_hash($hash);
+ return $hash;
}
=head2 load_peers
@@ -494,6 +472,14 @@ sub interface_id{
return $self->{'interface_id'};
}
+=head2 controller
+
+=cut
+sub controller {
+ my $self = shift;
+ return $self->{'controller'};
+}
+
=head2 description
=cut
diff --git a/perl-lib/OESS/lib/OESS/Interface.pm b/perl-lib/OESS/lib/OESS/Interface.pm
index 467e33c75..ca01c4e0c 100644
--- a/perl-lib/OESS/lib/OESS/Interface.pm
+++ b/perl-lib/OESS/lib/OESS/Interface.pm
@@ -1,5 +1,3 @@
-#!/usr/bin/perl
-
use strict;
use warnings;
@@ -24,11 +22,10 @@ sub new{
my $that = shift;
my $class = ref($that) || $that;
- my $logger = Log::Log4perl->get_logger("OESS.Interface");
-
my %args = (
db => undef,
interface_id => undef,
+ logger => Log::Log4perl->get_logger("OESS.Interface"),
model => undef,
@_
);
@@ -36,9 +33,6 @@ sub new{
my $self = \%args;
bless $self, $class;
- $self->{'logger'} = $logger;
-
-
if (!defined $self->{'db'}) {
$self->{'logger'}->warn("No Database Object specified");
}
@@ -67,6 +61,7 @@ sub from_hash{
$self->{'name'} = $hash->{'name'};
$self->{'interface_id'} = $hash->{'interface_id'};
+ $self->{'node_id'} = $hash->{'node_id'};
$self->{'node'} = $hash->{'node'};
$self->{'cloud_interconnect_id'} = $hash->{'cloud_interconnect_id'};
$self->{'cloud_interconnect_type'} = $hash->{'cloud_interconnect_type'};
@@ -79,6 +74,7 @@ sub from_hash{
$self->{'workgroup_id'} = $hash->{'workgroup_id'};
$self->{'utilized_bandwidth'} = $hash->{'utilized_bandwidth'} || 0;
$self->{'bandwidth'} = $hash->{'bandwidth'} || 0;
+ $self->{'provisionable_bandwidth'} = $hash->{'provisionable_bandwidth'};
$self->{'mtu'} = $hash->{'mtu'} || 0;
return 1;
@@ -90,26 +86,33 @@ sub from_hash{
sub to_hash{
my $self = shift;
- my $acl_models = [];
- foreach my $acl (@{$self->acls()}) {
- push @$acl_models, $acl->to_hash();
- }
-
- my $res = { name => $self->name(),
- cloud_interconnect_id => $self->cloud_interconnect_id(),
- cloud_interconnect_type => $self->cloud_interconnect_type(),
- description => $self->description(),
- interface_id => $self->interface_id(),
- node_id => $self->node()->node_id(),
- node => $self->node()->name(),
- acls => $acl_models,
- admin_state => $self->{'admin_state'},
- operational_state => $self->{'operational_state'},
- workgroup_id => $self->workgroup_id(),
- utilized_bandwidth => $self->{'utilized_bandwidth'},
- bandwidth => $self->{'bandwidth'},
- mtu => $self->{'mtu'} };
+ my $res = {
+ name => $self->name(),
+ cloud_interconnect_id => $self->cloud_interconnect_id(),
+ cloud_interconnect_type => $self->cloud_interconnect_type(),
+ description => $self->description(),
+ interface_id => $self->interface_id(),
+ node_id => $self->{node_id},
+ admin_state => $self->{'admin_state'},
+ operational_state => $self->{'operational_state'},
+ workgroup_id => $self->workgroup_id(),
+ utilized_bandwidth => $self->{'utilized_bandwidth'},
+ bandwidth => $self->{'bandwidth'},
+ provisionable_bandwidth => $self->{'provisionable_bandwidth'},
+ mtu => $self->{'mtu'}
+ };
+ if (defined $self->{acls}) {
+ my $acl_models = [];
+ foreach my $acl (@{$self->{acls}}) {
+ push @$acl_models, $acl->to_hash;
+ }
+ $res->{acls} = $acl_models;
+ }
+ if (defined $self->{node}) {
+ $res->{node} = $self->node()->name();
+ $res->{node_id} = $self->node()->node_id();
+ }
return $res;
}
@@ -123,6 +126,7 @@ sub _fetch_from_db{
if (defined $self->{'name'} && defined $self->{'node'}) {
my $interface_id = OESS::DB::Interface::get_interface(db => $self->{'db'}, interface => $self->{'name'}, node => $self->{'node'});
if (!defined $interface_id) {
+ warn "Unable to fetch interface $self->{name} on $self->{node} from the db!";
$self->{'logger'}->error("Unable to fetch interface $self->{name} on $self->{node} from the db!");
return;
}
@@ -142,6 +146,38 @@ sub _fetch_from_db{
return $self->from_hash($info);
}
+=head2 create
+
+=cut
+sub create {
+ my $self = shift;
+ my $args = {
+ node_id => undef,
+ @_
+ };
+
+ if (!defined $self->{db}) {
+ $self->{logger}->error("Couldn't create Interface; DB handle is missing.");
+ return (undef, "Couldn't create Interface; DB handle is missing.");
+ }
+ if (!defined $args->{node_id}) {
+ $self->{logger}->error("Couldn't create Interface; node_id is missing.");
+ return (undef, "Couldn't create Interface; node_id is missing.");
+ }
+
+ my $model = $self->to_hash;
+ $model->{node_id} = $args->{node_id};
+
+ my ($id, $err) = OESS::DB::Interface::create(
+ db => $self->{db},
+ model => $model
+ );
+ return (undef, $err) if defined $err;
+
+ $self->{interface_id} = $id;
+ return ($id, undef);
+}
+
=head2 update_db
=cut
@@ -201,7 +237,22 @@ sub bandwidth{
if (defined $bandwidth) {
$self->{bandwidth} = $bandwidth;
}
- return $self->{'bandwidth'};
+
+ if($self->{'cloud_interconnect_type'} eq 'azure-express-route'){
+ return $self->{'bandwidth'} * 4;
+ }else{
+ return $self->{'bandwidth'};
+ }
+}
+
+=head2 provisionable_bandwidth
+
+=cut
+sub provisionable_bandwidth{
+ my $self = shift;
+ my $provisionable_bandwidth = shift;
+
+ return $self->{provisionable_bandwidth};
}
=head2 mtu
@@ -254,7 +305,12 @@ sub cloud_interconnect_type{
=cut
sub description{
my $self = shift;
- return $self->{'description'};
+ my $description = shift;
+
+ if (defined $description) {
+ $self->{description} = $description;
+ }
+ return $self->{description};
}
=head2 port_number
diff --git a/perl-lib/OESS/lib/OESS/L2Circuit.pm b/perl-lib/OESS/lib/OESS/L2Circuit.pm
index 75cfa54b5..41457b1b0 100644
--- a/perl-lib/OESS/lib/OESS/L2Circuit.pm
+++ b/perl-lib/OESS/lib/OESS/L2Circuit.pm
@@ -151,6 +151,19 @@ sub remote_url{
return $self->{'remote_url'};
}
+=head2 status
+
+=cut
+
+sub status{
+ my $self = shift;
+ my $status = shift;
+ if(defined($status)){
+ $self->{'status'} = $status;
+ }
+ return $self->{'status'};
+}
+
=head2 remote_requester
=cut
@@ -398,6 +411,7 @@ sub to_hash {
my $hash = {
remote_requester => $self->{remote_requester},
external_identifier => $self->{external_identifier},
+ status => $self->{status},
state => $self->{state},
remote_url => $self->{remote_url},
created_on => $self->{created_on},
@@ -485,7 +499,7 @@ sub _process_circuit_details{
my $hash = shift;
$self->{remote_requester} = $hash->{remote_requester};
-
+ $self->{status} = $hash->{status};
$self->{external_identifier} = $hash->{external_identifier};
$self->{state} = $hash->{state};
$self->{remote_url} = $hash->{remote_url};
@@ -517,32 +531,33 @@ sub _process_circuit_details{
$self->{'has_tertiary_path'} = (defined $hash->{'tertiary_links'} && @{$hash->{'tertiary_links'}} > 0) ? 1 : 0;
# TODO Load endpoints
-
- foreach my $endpoint (@{$hash->{'endpoints'}}){
- if (!defined $self->{endpoints}) {
- $self->{endpoints} = [];
+ if (defined $hash->{endpoints}) {
+ $self->{endpoints} = [];
+ foreach my $ep (@{$hash->{endpoints}}) {
+ push(@{$self->{endpoints}}, new OESS::Endpoint(db => $self->{db}, model => $ep));
}
+ }
- if ($endpoint->{'local'} == 0) {
- $self->{'interdomain'} = 1;
- }
+ # foreach my $endpoint (@{$hash->{'endpoints'}}){
+ # if (!defined $self->{endpoints}) {
+ # $self->{endpoints} = [];
+ # }
- my $entity = OESS::Entity->new(
- db => $self->{'db'},
- interface_id => $endpoint->{'interface_id'},
- vlan => $endpoint->{'tag'}
- );
- if (!defined $entity) {
- next;
- }
+ # if ($endpoint->{'local'} == 0) {
+ # $self->{'interdomain'} = 1;
+ # }
- push @{$self->{endpoints}}, $entity;
- # $endpoint->{'entity'} = $entity->to_hash();
- }
+ # my $entity = OESS::Entity->new(
+ # db => $self->{'db'},
+ # interface_id => $endpoint->{'interface_id'},
+ # vlan => $endpoint->{'tag'}
+ # );
+ # if (!defined $entity) {
+ # next;
+ # }
- # warn Dumper($self);
- # if (!$self->{'just_display'}) {
- # $self->_create_graph();
+ # push @{$self->{endpoints}}, $entity;
+ # # $endpoint->{'entity'} = $entity->to_hash();
# }
}
@@ -1005,6 +1020,15 @@ sub error{
sub load_endpoints {
my $self = shift;
+ if (!defined $self->{db}) {
+ $self->{'logger'}->warn('Optional argument `db` is missing. Cannot load Endpoints.');
+ return 1;
+ }
+ if (!defined $self->{circuit_id}) {
+ $self->{'logger'}->warn('Optional argument `circuit_id` is missing. Cannot load Endpoints.');
+ return 1;
+ }
+
my ($ep_datas, $error) = OESS::DB::Endpoint::fetch_all(
db => $self->{db},
circuit_id => $self->{circuit_id}
@@ -1184,4 +1208,108 @@ sub remove {
return $err;
}
+=head2 nso_diff
+
+Given an NSO Connection object: Return a hash of device-name to
+human-readable-diff containing the difference between this L2Circuit
+and the provided NSO Connection object.
+
+NSO L2Connection:
+
+ {
+ 'connection_id' => 3000,
+ 'endpoint' => [
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 1,
+ 'interface' => 'GigabitEthernet0/0',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ },
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 2,
+ 'interface' => 'GigabitEthernet0/1',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ }
+ ]
+ }
+
+=cut
+sub nso_diff {
+ my $self = shift;
+ my $nsoc = shift; # NSOConnection
+
+ my $diff = {};
+ my $ep_index = {};
+
+ # Handle case where connection has no endpoints or a connection
+ # created with an empty model.
+ my $endpoints = $self->endpoints || [];
+
+ foreach my $ep (@{$endpoints}) {
+ if (!defined $ep_index->{$ep->node}) {
+ $diff->{$ep->node} = "";
+ $ep_index->{$ep->node} = {};
+ }
+ $ep_index->{$ep->node}->{$ep->interface} = $ep;
+ }
+
+ foreach my $ep (@{$nsoc->{endpoint}}) {
+ if (!defined $ep_index->{$ep->{device}}->{$ep->{interface}}) {
+ $diff->{$ep->{device}} = "" if !defined $diff->{$ep->{device}};
+ $diff->{$ep->{device}} .= "- $ep->{interface}\n";
+ $diff->{$ep->{device}} .= "- Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->{device}} .= "- Tag: $ep->{tag}\n";
+ $diff->{$ep->{device}} .= "- Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+ next;
+ }
+ my $ref_ep = $ep_index->{$ep->{device}}->{$ep->{interface}};
+
+ # Compare endpoints
+ my $ok = 1;
+ $ok = 0 if $ep->{bandwidth} != $ref_ep->bandwidth;
+ $ok = 0 if $ep->{tag} != $ref_ep->tag;
+ $ok = 0 if $ep->{inner_tag} != $ref_ep->inner_tag;
+ if (!$ok) {
+ $diff->{$ep->{device}} = "" if !defined $diff->{$ep->{device}};
+ $diff->{$ep->{device}} .= " $ep->{interface}\n";
+ }
+
+ if ($ep->{bandwidth} != $ref_ep->bandwidth) {
+ $diff->{$ep->{device}} .= "- Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->{device}} .= "+ Bandwidth: $ref_ep->{bandwidth}\n";
+ }
+ if ($ep->{tag} != $ref_ep->tag) {
+ $diff->{$ep->{device}} .= "- Tag: $ep->{tag}\n";
+ $diff->{$ep->{device}} .= "+ Tag: $ref_ep->{tag}\n";
+ }
+ if ($ep->{inner_tag} != $ref_ep->inner_tag) {
+ $diff->{$ep->{device}} .= "- Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+ $diff->{$ep->{device}} .= "+ Inner Tag: $ref_ep->{inner_tag}\n" if defined $ref_ep->{inner_tag};
+ }
+
+ delete $ep_index->{$ep->{device}}->{$ep->{interface}};
+ }
+
+ foreach my $device_key (keys %{$ep_index}) {
+ foreach my $ep_key (keys %{$ep_index->{$device_key}}) {
+ my $ep = $ep_index->{$device_key}->{$ep_key};
+ $diff->{$ep->node} = "" if !defined $diff->{$ep->node};
+
+ $diff->{$ep->node} .= "+ $ep->{interface}\n";
+ $diff->{$ep->node} .= "+ Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->node} .= "+ Tag: $ep->{tag}\n";
+ $diff->{$ep->node} .= "+ Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+ }
+ }
+
+ foreach my $key (keys %$diff) {
+ delete $diff->{$key} if ($diff->{$key} eq '');
+ }
+
+ return $diff;
+}
+
1;
diff --git a/perl-lib/OESS/lib/OESS/Link.pm b/perl-lib/OESS/lib/OESS/Link.pm
index 38b6011d9..6b93f09e4 100644
--- a/perl-lib/OESS/lib/OESS/Link.pm
+++ b/perl-lib/OESS/lib/OESS/Link.pm
@@ -63,7 +63,7 @@ sub new {
if (defined $self->{db} && (defined $self->{link_id} || defined $self->{name})) {
eval {
- my $links = OESS::DB::Link::fetch_all(
+ my ($links, $err) = OESS::DB::Link::fetch_all(
db => $self->{db},
name => $self->{name},
link_id => $self->{link_id}
diff --git a/perl-lib/OESS/lib/OESS/MPLS/Device/Juniper/MX.pm b/perl-lib/OESS/lib/OESS/MPLS/Device/Juniper/MX.pm
index 411b1ea88..a6c2cdd33 100644
--- a/perl-lib/OESS/lib/OESS/MPLS/Device/Juniper/MX.pm
+++ b/perl-lib/OESS/lib/OESS/MPLS/Device/Juniper/MX.pm
@@ -587,7 +587,7 @@ sub get_interfaces{
if($self->{'jnx'}->has_error){
my $error = $self->{'jnx'}->get_first_error();
- $self->set_error($error->{'error_message'});
+ $self->set_error($error->{'error_message'});
$self->{'logger'}->error("Error fetching interface information: " . $error->{'error_message'});
return;
}
@@ -615,7 +615,7 @@ sub get_interfaces{
sub _process_interface{
my $self = shift;
my $int = shift;
-
+
my $obj = {};
my $xp = XML::LibXML::XPathContext->new( $int );
diff --git a/perl-lib/OESS/lib/OESS/MPLS/Discovery.pm b/perl-lib/OESS/lib/OESS/MPLS/Discovery.pm
index 4a45d8dff..84356337b 100644
--- a/perl-lib/OESS/lib/OESS/MPLS/Discovery.pm
+++ b/perl-lib/OESS/lib/OESS/MPLS/Discovery.pm
@@ -96,26 +96,27 @@ sub new{
bless $self, $class;
- my $config_filename = (defined $self->{'config'}) ? $self->{'config'} : '/etc/oess/database.xml';
- $self->{'config_filename'} = $config_filename;
- $self->{'config'} = new OESS::Config(config_filename => $config_filename);
+ # $self->{config} is assumed to be a str path
+ $self->{'config_filename'} = (defined $self->{'config'}) ? $self->{'config'} : '/etc/oess/database.xml';
+
+ if (!defined $self->{config_obj}) {
+ $self->{'config'} = new OESS::Config(config_filename => $self->{'config_filename'});
+ } else {
+ $self->{'config'} = $self->{config_obj};
+ $self->{'config_filename'} = $self->{config_obj}->filename;
+ }
if (!defined $self->{'test'}) {
$self->{'test'} = 0;
}
- $self->{'db'} = OESS::Database->new(config => $config_filename);
+ $self->{'db'} = OESS::Database->new(config => $self->{'config_filename'});
die if (!defined $self->{'db'});
-
$self->{'interface'} = OESS::MPLS::Discovery::Interface->new(
- db => new OESS::DB(config => $config_filename),
- lsp_processor => sub{ $self->lsp_handler(); }
+ db => new OESS::DB(config => $self->{'config_filename'}),
);
- die "Unable to create Interface processor\n" if !defined $self->{'interface'};
-
- $self->{'lsp'} = OESS::MPLS::Discovery::LSP->new(db => $self->{'db'});
- die "Unable to create LSP Processor\n" if !defined $self->{'lsp'};
+ die "Unable to create Interface processor\n" if !defined $self->{'interface'};
$self->{'isis'} = OESS::MPLS::Discovery::ISIS->new(db => $self->{'db'});
die "Unable to create ISIS Processor\n" if !defined $self->{'isis'};
@@ -139,7 +140,7 @@ sub new{
# Create the client for talking to our Discovery switch objects!
$self->{'rmq_client'} = OESS::RabbitMQ::Client->new(
- config => $config_filename,
+ config => $self->{'config_filename'},
timeout => 120,
topic => 'MPLS.Discovery'
);
@@ -162,8 +163,7 @@ sub new{
$self->{'vrf_stats_time'} = AnyEvent->timer( after => 20, interval => VRF_STATS_INTERVAL, cb => sub { $self->vrf_stats_handler(); });
# Only lookup LSPs and Paths when network type is vpn-mpls.
- if ($self->{'config'}->network_type eq 'vpn-mpls') {
- $self->{'lsp_timer'} = AnyEvent->timer( after => 70, interval => 200, cb => sub { $self->lsp_handler(); });
+ if ($self->{'config'}->network_type eq 'vpn-mpls' || $self->{'config'}->network_type eq 'nso+vpn-mpls') {
$self->{'path_timer'} = AnyEvent->timer( after => 40, interval => 300, cb => sub { $self->path_handler(); });
}
@@ -240,7 +240,6 @@ sub new_switch{
$self->{'logger'}->debug("Baby was created!");
sleep(5);
$self->int_handler();
- $self->lsp_handler();
&$success({status => 1});
}
@@ -310,13 +309,16 @@ sub int_handler{
my $self = shift;
foreach my $node (@{$self->{'db'}->get_current_nodes(type => 'mpls')}) {
+
+ $self->{logger}->info("Calling get_interfaces on $node->{name} $node->{mgmt_addr}.");
$self->{'rmq_client'}->{'topic'} = "MPLS.Discovery.Switch." . $node->{'mgmt_addr'};
+
my $start = [gettimeofday];
$self->{'rmq_client'}->get_interfaces(
async_callback => $self->handle_response(
cb => sub {
my $res = shift;
- $self->{'logger'}->debug("Total Time for get_interfaces " . $node->{'mgmt_addr'} . " call: " . tv_interval($start,[gettimeofday]));
+ $self->{'logger'}->info("Called get_interfaces on $node->{name} $node->{mgmt_addr}. Response recieved in " . tv_interval($start,[gettimeofday]) . "s.");
foreach my $int (@{$res->{'results'}}) {
foreach my $addr (@{$int->{'addresses'}}) {
@@ -405,45 +407,6 @@ sub path_handler {
$cv->end;
}
-=head2 lsp_handler
-
-=cut
-sub lsp_handler{
- my $self = shift;
-
- if ($self->{'config'}->network_type ne 'vpn-mpls') {
- # Only lookup LSPs when network type is set to vpn-mpls.
- return 1;
- }
-
- my %nodes;
-
- foreach my $node (@{$self->{'db'}->get_current_nodes(type => 'mpls')}) {
- $nodes{$node->{'name'}} = {'pending' => 1};
- $self->{'rmq_client'}->{'topic'} = "MPLS.Discovery.Switch." . $node->{'mgmt_addr'};
- my $start = [gettimeofday];
- $self->{'rmq_client'}->get_LSPs( async_callback => $self->handle_response( cb => sub { my $res = shift;
- $self->{'logger'}->debug("Total Time for get_LSPs " . $node->{'mgmt_addr'} . " call: " . tv_interval($start,[gettimeofday]));
- $nodes{$node->{'name'}} = $res;
- $nodes{$node->{'name'}}->{'pending'} = 0;
- my $no_pending = 1;
- foreach my $node (keys %nodes){
- if($nodes{$node}->{'pending'} == 1){
- #warn "Still have pending\n";
- $no_pending = 0;
- }
- }
-
- if($no_pending){
- #warn "No more pending\n";
- my $status = $self->{'lsp'}->process_results( lsp => \%nodes);
- }
- })
-
- );
- }
-}
-
=head2 isis_handler
=cut
@@ -484,17 +447,20 @@ sub device_handler {
my $self =shift;
foreach my $node (@{$self->{'db'}->get_current_nodes(type => 'mpls')}) {
+
+ $self->{logger}->info("Calling get_system_info on $node->{name} $node->{mgmt_addr}.");
$self->{'rmq_client'}->{'topic'} = "MPLS.Discovery.Switch." . $node->{'mgmt_addr'};
- my $start = [gettimeofday];
+ my $start = [gettimeofday];
$self->{'rmq_client'}->get_system_info(async_callback => sub {
my $response = shift;
+
+ $self->{'logger'}->info("Called get_system_info on $node->{name} $node->{mgmt_addr}. Response recieved in " . tv_interval($start, [gettimeofday]) . "s.");
if (defined $response->{'error'}) {
- $self->{'logger'}->error("Error calling get_system_info on $node->{'mgmt_addr'}: $response->{'error'}");
+ $self->{'logger'}->error("Error from get_system_info on $node->{name} $node->{mgmt_addr}: $response->{error}");
return;
}
- $self->{'logger'}->debug("Time calling get_system_info on $node->{'mgmt_addr'}: " . tv_interval($start, [gettimeofday]));
$self->handle_system_info(node => $node->{'node_id'}, info => $response->{'results'});
});
}
diff --git a/perl-lib/OESS/lib/OESS/MPLS/Discovery/Paths.pm b/perl-lib/OESS/lib/OESS/MPLS/Discovery/Paths.pm
index a1c3855ea..713affcc9 100644
--- a/perl-lib/OESS/lib/OESS/MPLS/Discovery/Paths.pm
+++ b/perl-lib/OESS/lib/OESS/MPLS/Discovery/Paths.pm
@@ -90,7 +90,7 @@ sub _process_paths{
my $ip_links = {}; # Map from IPAddress to Link
$self->{db2}->start_transaction;
- my $links_db = OESS::DB::Link::fetch_all(db => $self->{db2});
+ my ($links_db, $err) = OESS::DB::Link::fetch_all(db => $self->{db2});
foreach my $link (@{$links_db}){
$ip_links->{$link->{ip_a}} = new OESS::Link(db => $self->{db2}, model => $link);
$ip_links->{$link->{ip_z}} = new OESS::Link(db => $self->{db2}, model => $link);
@@ -120,6 +120,7 @@ sub _process_paths{
my @ckt_path = map { $links->{$_} } keys(%$links);
my $ckt = new OESS::L2Circuit(db => $self->{db2}, circuit_id => $circuit_id);
+ next if !defined $ckt;
$ckt->load_paths;
my $pri = $ckt->path(type => 'primary');
diff --git a/perl-lib/OESS/lib/OESS/MPLS/FWDCTL.pm b/perl-lib/OESS/lib/OESS/MPLS/FWDCTL.pm
index 85ae8385e..980398c42 100644
--- a/perl-lib/OESS/lib/OESS/MPLS/FWDCTL.pm
+++ b/perl-lib/OESS/lib/OESS/MPLS/FWDCTL.pm
@@ -54,6 +54,10 @@ use constant TIMEOUT => 3600;
use JSON::XS;
use GRNOC::WebService::Regex;
+=head1 OESS::MPLS::FWDCTL
+
+=cut
+
=head2 new
create a new OESS Master process
@@ -61,7 +65,6 @@ create a new OESS Master process
FWDCTL->new();
=cut
-
sub new {
my $class = shift;
my %params = @_;
@@ -70,11 +73,18 @@ sub new {
$self->{'logger'} = Log::Log4perl->get_logger('OESS.MPLS.FWDCTL.MASTER');
+ # $self->{config} is assumed to be a str path
my $config_filename = (defined $self->{'config'}) ? $self->{'config'} : '/etc/oess/database.xml';
- $self->{'config'} = new OESS::Config(config_filename => $config_filename);
- $self->{'db'} = OESS::Database->new( config_file => $config_filename );
- $self->{'db2'} = OESS::DB->new();
+ if (!defined $self->{config_obj}) {
+ $self->{'config'} = new OESS::Config(config_filename => $config_filename);
+ } else {
+ $self->{'config'} = $self->{config_obj};
+ $config_filename = $self->{config_obj}->filename;
+ }
+
+ $self->{'db'} = OESS::Database->new(config_file => $config_filename);
+ $self->{'db2'} = OESS::DB->new(config => $config_filename);
if (!$self->{object_only}) {
my $fwdctl_dispatcher = OESS::RabbitMQ::Dispatcher->new(
@@ -209,7 +219,7 @@ sub build_cache{
my $nodes = $db->get_current_nodes(type => 'mpls');
foreach my $node (@$nodes) {
my $details = $db->get_node_by_id(node_id => $node->{'node_id'});
- next if(!$details->{'mpls'});
+ next if ($details->{'controller'} ne 'netconf');
# TODO In addition to the previously removed unnecessary
# mappings. Remove this mapping.
@@ -687,7 +697,8 @@ sub update_cache {
if (defined $conn) {
# Targeted Cache Update
foreach my $ep (@{$conn->endpoints}) {
- my $addr = $self->{node_by_id}->{$ep->node_id}->{mgmt_addr};
+ my $addr = $self->{node_by_id}->{$ep->node_id}->{mgmt_addr};
+ next if !$addr;
$condvar->begin;
$self->{fwdctl_events}->{topic} = "MPLS.FWDCTL.Switch.$addr";
diff --git a/perl-lib/OESS/lib/OESS/NSI/Processor.pm b/perl-lib/OESS/lib/OESS/NSI/Processor.pm
index 8b0a9a3d3..6807dec6a 100644
--- a/perl-lib/OESS/lib/OESS/NSI/Processor.pm
+++ b/perl-lib/OESS/lib/OESS/NSI/Processor.pm
@@ -99,7 +99,7 @@ sub process_request {
log_info("Received method call: $request");
log_info(Dumper($request));
-
+ warn Dumper("REceived Method call: $request");
$data = decode_json $data;
log_info("Received method data: $data");
diff --git a/perl-lib/OESS/lib/OESS/NSI/Provisioning.pm b/perl-lib/OESS/lib/OESS/NSI/Provisioning.pm
index ed50448ff..843ba82c0 100644
--- a/perl-lib/OESS/lib/OESS/NSI/Provisioning.pm
+++ b/perl-lib/OESS/lib/OESS/NSI/Provisioning.pm
@@ -32,7 +32,7 @@ use Data::Dumper;
use GRNOC::Log;
use GRNOC::Config;
use GRNOC::WebService::Client;
-
+use JSON::XS;
use OESS::NSI::Constant;
use OESS::NSI::Utils;
@@ -149,11 +149,11 @@ sub _do_provisioning{
return;
}
- my $url = $self->{'websvc_location'} . "provisioning.cgi";
+ my $url = $self->{'websvc_location'} . "circuit.cgi";
$self->{'websvc'}->set_url($url);
- my $res = $self->{'websvc'}->provision_circuit(
- state => 'provisioned',
+ my $res = $self->{'websvc'}->provision(
+ status => 'provisioned',
circuit_id => $connection_id,
workgroup_id => $self->{'workgroup_id'},
description => $ckt->{'description'},
@@ -163,10 +163,9 @@ sub _do_provisioning{
bandwidth => $ckt->{'bandwidth'},
provision_time => -1,
remove_time => 1,
- node => $ckt->{'node'},
- interface => $ckt->{'interface'},
- tag => $ckt->{'tag'}
- );
+ endpoint => [JSON::to_json($ckt->{'endpoint'}->[0]), JSON::to_json($ckt->{'endpoint'}->[1])]);
+
+
if (!defined $res) {
log_error("Couldn't call provision_circuit using $url: Fatal webservice error occurred.");
push(@{$self->{'provisioning_queue'}}, {type => OESS::NSI::Constant::PROVISIONING_FAILED, args => $args});
@@ -180,7 +179,7 @@ sub _do_provisioning{
log_debug("results of provision circuit: " . Data::Dumper::Dumper($res));
- if (defined $res->{'results'}) {
+ if ($res->{'success'} == 1) {
push(@{$self->{'provisioning_queue'}}, {type => OESS::NSI::Constant::PROVISIONING_SUCCESS, args => $args});
return OESS::NSI::Constant::SUCCESS;
}
@@ -194,62 +193,39 @@ sub _get_circuit_details{
my $self = shift;
my $circuit_id = shift;
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "/data.cgi");
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "/circuit.cgi");
log_debug("fetching circuit details");
- my $circuit = $self->{'websvc'}->get_circuit_details(
- circuit_id => $circuit_id);
-
+ my $circuit = $self->{'websvc'}->get(
+ circuit_id => $circuit_id, workgroup_id => $self->{'workgroup_id'});
+
log_debug("Circuit Details: " . Data::Dumper::Dumper($circuit));
+ #ugh how to get this...
my $scheduled_actions = $self->{'websvc'}->get_circuit_scheduled_events(
- circuit_id => $circuit_id);
+ circuit_id => $circuit_id);
log_debug("Circuit scheduled events: " . Data::Dumper::Dumper($scheduled_actions));
-
+
if(!defined($circuit) && !defined($circuit->{'results'})){
log_error("circuit $circuit_id was not defined");
return OESS::NSI::Constant::ERROR;
}
- $circuit = $circuit->{'results'};
-
- my @links = ();
- foreach my $link (@{$circuit->{'links'}}){
- push(@links, $link->{'name'});
- }
-
- my @backup_links = ();
- foreach my $link (@{$circuit->{'backup_links'}}){
- push(@backup_links, $link->{'name'});
- }
-
- my @nodes = ();
- my @ints = ();
- my @tags = ();
-
- foreach my $ep (@{$circuit->{'endpoints'}}){
- push(@nodes,$ep->{'node'});
- push(@ints,$ep->{'interface'});
- push(@tags,$ep->{'tag'});
- }
+ $circuit = $circuit->{'results'}->[0];
- my $ckt = { state => $circuit->{'state'},
+ my $ckt = { status => $circuit->{'state'},
circuit_id => $circuit->{'circuit_id'},
workgroup_id => $circuit->{'workgroup'}->{'workgroup_id'},
description => $circuit->{'description'},
name => $circuit->{'name'},
remote_url => $circuit->{'remote_url'},
remote_requester => $circuit->{'remote_requester'},
- link => \@links,
- backup_link => \@backup_links,
bandwidth => $circuit->{'bandwidth'},
provision_time => $circuit->{'provision_time'},
remove_time => $circuit->{'remove_time'},
- node => \@nodes,
- interface => \@ints,
- tag => \@tags
+ endpoint => $circuit->{'endpoints'}
};
return $ckt;
@@ -281,14 +257,14 @@ sub _do_terminate{
my ($self, $args) = @_;
my $connection_id = $args->{'connectionId'};
- my $cgi = $self->{'websvc_location'} . "provisioning.cgi";
+ my $cgi = $self->{'websvc_location'} . "circuit.cgi";
log_debug("_do_terminate - url: $cgi circuit: $connection_id");
$self->{'websvc'}->set_url($cgi);
- my $res = $self->{'websvc'}->remove_circuit(circuit_id => $connection_id,
- workgroup_id => $self->{'workgroup_id'},
- remove_time => -1);
+ my $res = $self->{'websvc'}->remove(circuit_id => $connection_id,
+ workgroup_id => $self->{'workgroup_id'},
+ remove_time => -1);
log_debug("Results of remove_circuit: " . Data::Dumper::Dumper($res));
@@ -455,31 +431,27 @@ sub _do_release{
my $ckt = $self->_get_circuit_details($connection_id);
- if (!defined $ckt->{'provision_time'}) {
+ if (!defined $ckt->{'provision_time'} || $ckt->{'provision_time'} eq '') {
$ckt->{'provision_time'} = -1;
}
- if (!defined $ckt->{'remove_time'}) {
+ if (!defined $ckt->{'remove_time'} || $ckt->{'release_time'} eq '') {
$ckt->{'remove_time'} = -1;
}
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "/provisioning.cgi");
-
- my $res = $self->{'websvc'}->provision_circuit(
- state => 'reserved',
- circuit_id => $connection_id,
- workgroup_id => $self->{'workgroup_id'},
- description => $ckt->{'description'},
- name => $ckt->{'name'},
- link => $ckt->{'link'},
- backup_link => $ckt->{'backup_link'},
- bandwidth => $ckt->{'bandwidth'},
- provision_time => $ckt->{'provision_time'},
- remove_time => $ckt->{'remove_time'},
- node => $ckt->{'node'},
- interface => $ckt->{'interface'},
- tag => $ckt->{'tag'});
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "/circuit.cgi");
- if(defined($res) && defined($res->{'results'})){
+ my $res = $self->{'websvc'}->provision(
+ status => 'reserved',
+ circuit_id => $connection_id,
+ workgroup_id => $self->{'workgroup_id'},
+ description => $ckt->{'description'},
+ name => $ckt->{'name'},
+ bandwidth => $ckt->{'bandwidth'},
+ provision_time => $ckt->{'provision_time'},
+ remove_time => $ckt->{'remove_time'},
+ endpoint => [JSON::to_json($ckt->{'endpoint'}->[0]), JSON::to_json($ckt->{'endpoint'}->[1])]);
+
+ if(defined($res) && $res->{'success'} == 1){
log_info("Release connectionId: " . $args->{'connectionId'} . " success!");
push(@{$self->{'provisioning_queue'}}, {type => OESS::NSI::Constant::RELEASE_SUCCESS, args => $args});
return OESS::NSI::Constant::SUCCESS;
diff --git a/perl-lib/OESS/lib/OESS/NSI/Query.pm b/perl-lib/OESS/lib/OESS/NSI/Query.pm
index 5549f39d1..0e2b9bfdf 100644
--- a/perl-lib/OESS/lib/OESS/NSI/Query.pm
+++ b/perl-lib/OESS/lib/OESS/NSI/Query.pm
@@ -135,8 +135,8 @@ sub query_summary{
sub get_current_circuits{
my $self = shift;
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "data.cgi");
- my $current_circuits = $self->{'websvc'}->get_existing_circuits(workgroup_id => $self->{'workgroup_id'});
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "circuit.cgi");
+ my $current_circuits = $self->{'websvc'}->get(workgroup_id => $self->{'workgroup_id'});
if(defined($current_circuits) && defined($current_circuits->{'results'})){
return $current_circuits->{'results'};
@@ -155,8 +155,8 @@ sub do_query_summarysync{
my $self = shift;
my $args = shift;
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "data.cgi");
- my $current_circuits = $self->{'websvc'}->get_existing_circuits(workgroup_id => $self->{'workgroup_id'});
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "circuit.cgi");
+ my $current_circuits = $self->{'websvc'}->get(workgroup_id => $self->{'workgroup_id'});
my @ckts = ();
diff --git a/perl-lib/OESS/lib/OESS/NSI/Reservation.pm b/perl-lib/OESS/lib/OESS/NSI/Reservation.pm
index b0941105d..ee0c49b47 100644
--- a/perl-lib/OESS/lib/OESS/NSI/Reservation.pm
+++ b/perl-lib/OESS/lib/OESS/NSI/Reservation.pm
@@ -35,7 +35,7 @@ use OESS::NSI::Constant;
use OESS::NSI::Utils;
use DateTime;
use OESS::Database;
-
+use JSON::XS;
use Data::Dumper;
=head2 new
@@ -183,34 +183,36 @@ sub reserve {
#
# my $backup_path = $self->get_shortest_path($ep1, $ep2, $primary_path);
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "provisioning.cgi");
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "circuit.cgi");
+
+ #warn Dumper($ep1);
+ #warn Dumper($ep2);
- my $res = $self->{'websvc'}->provision_circuit(
- state => 'reserved',
- workgroup_id => $self->{'workgroup_id'},
- external_identifier => $gri,
- description => $description,
- bandwidth => $capacity,
- provision_time => $start_time,
- remove_time => $end_time,
-# link => $primary_path,
-# backup_link => $backup_path,
- remote_url => $args->{'header'}->{'replyTo'},
- remote_requester => $args->{'header'}->{'requesterNSA'},
- node => [$ep1->{'node'}, $ep2->{'node'}],
- interface => [$ep1->{'port'}, $ep2->{'port'}],
- tag => [$ep1->{'vlan'}, $ep2->{'vlan'}]);
+ my $endpoint1 = {'node' => $ep1->{'node'}, interface => $ep1->{'port'}, tag => $ep1->{'tags'}->[0]};
+ my $endpoint2 = {'node' => $ep2->{'node'}, interface => $ep2->{'port'}, tag => $ep2->{'tags'}->[0]};
- log_debug("Results of provision: " . Data::Dumper::Dumper($res));
+ my $res = $self->{'websvc'}->provision(
+ status => 'reserved',
+ workgroup_id => $self->{'workgroup_id'},
+ external_identifier => $gri,
+ description => $description,
+ bandwidth => $capacity,
+ provision_time => $start_time,
+ remove_time => $end_time,
+ remote_url => $args->{'header'}->{'replyTo'},
+ remote_requester => $args->{'header'}->{'requesterNSA'},
+ endpoint => [JSON::to_json($endpoint1), JSON::to_json($endpoint2)]);
+
+ log_error("Results of provision: " . Data::Dumper::Dumper($res));
- if(defined($res->{'results'}) && $res->{'results'}->{'success'} == 1){
- log_info("Successfully created reservation, connectionId: " . $res->{'results'}->{'circuit_id'});
- $args->{'connection_id'} = $res->{'results'}->{'circuit_id'};
+ if(defined($res->{'success'} == 1)){
+ log_info("Successfully created reservation, connectionId: " . $res->{'circuit_id'});
+ $args->{'connection_id'} = $res->{'circuit_id'};
$args->{'criteria'}->{'p2ps'}->{'sourceSTP'} = $self->build_stp($ep1);
$args->{'criteria'}->{'p2ps'}->{'destSTP'} = $self->build_stp($ep2);
- push(@{$self->{'reservation_queue'}}, {type => OESS::NSI::Constant::RESERVATION_SUCCESS, connection_id => $res->{'results'}->{'circuit_id'}, args => $args});
- push(@{$self->{'reservation_queue'}}, {type => OESS::NSI::Constant::RESERVATION_TIMEOUT, connection_id => $res->{'results'}->{'circuit_id'}, args => $args, time => time() + OESS::NSI::Constant::RESERVATION_TIMEOUT_SEC});
- return $res->{'results'}->{'circuit_id'};
+ push(@{$self->{'reservation_queue'}}, {type => OESS::NSI::Constant::RESERVATION_SUCCESS, connection_id => $res->{'circuit_id'}, args => $args});
+ push(@{$self->{'reservation_queue'}}, {type => OESS::NSI::Constant::RESERVATION_TIMEOUT, connection_id => $res->{'circuit_id'}, args => $args, time => time() + OESS::NSI::Constant::RESERVATION_TIMEOUT_SEC});
+ return $res->{'circuit_id'};
}else{
log_error("Unable to reserve circuit: " . $res->{'error'});
$args->{'fail_text'} = "Error creating reservation record: " . $res->{'error'};
@@ -243,8 +245,8 @@ sub _do_reserve_abort{
log_info("reservationAbort: connectionId: " . $connection_id);
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "/provisioning.cgi");
- my $res = $self->{'websvc'}->remove_circuit(
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "/circuit.cgi");
+ my $res = $self->{'websvc'}->remove(
circuit_id => $connection_id,
workgroup_id => $self->{'workgroup_id'},
remove_time => -1);
@@ -278,7 +280,7 @@ sub build_stp{
my $str = "urn:ogf:network:nsi.";
$str .= $self->{'db'}->get_local_domain_name();
- $str .= ":2013::" . $ep->{'node'} . ":" . $ep->{'port'} . ":" . $ep->{'link'} . "?vlan=" . $ep->{'vlan'};
+ $str .= ":2013::" . $ep->{'node'} . ":" . $ep->{'port'} . ":" . $ep->{'link'} . "?vlan=" . $ep->{'tags'}->[0];
return $str;
}
@@ -350,97 +352,42 @@ sub validate_endpoint{
my $ep = shift;
#need to verify this is part of our network and actually exists and that we have permission!
- $self->{'log'}->info("Checking validity of port $ep->{'port'} on $ep->{'node'}.");
+ $self->{'log'}->info("Checking validity of port $ep->{'port'} on $ep->{'node'}." . Dumper($ep));
- my $url = $self->{'websvc_location'} . "data.cgi";
+ my $url = $self->{'websvc_location'} . "interface.cgi";
$self->{'websvc'}->set_url($url);
- $self->{'log'}->debug("Requesting all resources for NSI workgroup from $url");
-
- my $res = $self->{'websvc'}->get_all_resources_for_workgroup(workgroup_id => $self->{'workgroup_id'});
- if (!defined $res) {
- $self->{'log'}->error("Couldn't get NSI workgroup resources from $url: Fatal webservice error occurred.");
- return 0;
- }
- if (defined $res->{'error'}) {
- $self->{'log'}->error("Couldn't get NSI workgroup resources from $url: $res->{'error'}");
- return 0;
- }
-
- if (defined $res->{'results'}) {
- $self->{'log'}->debug("Workgroup resources: " . Dumper($res->{'results'}));
-
- foreach my $resource (@{$res->{'results'}}) {
-
- if ($resource->{'node_name'} eq $ep->{'node'} && $resource->{'interface_name'} eq $ep->{'port'}) {
- $self->{'log'}->debug("Found interface for requested endpoint. Checking VLAN availability.");
-
- foreach my $tag (@{$ep->{'tags'}}) {
- my $valid_tag = $self->{'websvc'}->is_vlan_tag_available(
- interface => $ep->{'port'},
- node => $ep->{'node'},
- vlan => $tag,
- workgroup_id => $self->{'workgroup_id'}
- );
- if (!defined $valid_tag) {
- $self->{'log'}->error("Couldn't get VLAN tag availability from $url: Fatal webservice error occurred.");
- return 0;
- }
- if (defined $res->{'error'}) {
- $self->{'log'}->error("Couldn't get VLAN tag availability from $url: $res->{'error'}");
- return 0;
- }
-
- if (defined $valid_tag->{'results'}) {
- $self->{'log'}->debug("is_vlan_tag_available response: " . Data::Dumper::Dumper($valid_tag->{'results'}));
-
- if ($valid_tag->{'results'}->[0]->{'available'} == 1) {
- $ep->{'vlan'} = $tag;
- return 1;
- }
- } else {
- $self->{'log'}->error("Got unexpected webservice response: " . Data::Dumper::Dumper($valid_tag));
- return 0;
- }
- }
-
- # If we reach here we have a valid switch port, but the vlan is invalid or unavailable.
- return 0;
- }
- }
- } else {
- $self->{'log'}->error("Got unexpected webservice response: " . Data::Dumper::Dumper($res));
- return 0;
- }
-
- $self->{'log'}->error("not a valid endpoint, or not allowed via NSI workgroup: " . Dumper($res));
- return 0;
-}
-
-=head2 get_shortest_path
-
-=cut
+ #finding node and interface
+
+ $self->{'log'}->debug("Requesting all available VLANs for NSI workgroup for interface $ep->{'port'} from $url" . Dumper($ep));
-sub get_shortest_path{
- my $self = shift;
- my $ep1 = shift;
- my $ep2 = shift;
- my $links = shift;
-
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "data.cgi");
- my $shortest_path = $self->{'websvc'}->get_shortest_path(
- node => [$ep1->{'node'},$ep2->{'node'}],
- link => $links);
+ my $interface = $self->{'websvc'}->get_interfaces(node => $ep->{'node'}, name => $ep->{'port'});
+ $self->{'log'}->error(Dumper($interface));
- log_debug("Shortest path: " . Data::Dumper::Dumper($shortest_path));
- if(defined($shortest_path) && defined($shortest_path->{'results'})){
- my @links = ();
- foreach my $link (@{$shortest_path->{'results'}}){
- push(@links,$link->{'link'});
+ if(defined($interface)){
+ if(defined($interface->{'results'}) && defined($interface->{'results'}->[0])){
+ $self->{'log'}->error("Interface results: " . Dumper($interface));
+ $self->{'websvc'}->{'debug'} = 1;
+ foreach my $tag (@{$ep->{'tags'}}){
+ my $is_vlan_available = $self->{'websvc'}->is_vlan_available( interface_id => $interface->{'results'}->[0]->{'interface_id'}, workgroup_id => $self->{'workgroup_id'}, vlan => $tag);
+ $self->{'log'}->error("available: " . Dumper($is_vlan_available));
+ if(defined($is_vlan_available) && defined($is_vlan_available->{'results'})){
+ if(!$is_vlan_available->{'results'}->{'allowed'}){
+ return 0;
+ }
+ }else{
+ return 0;
+ }
+ }
+ return 1;
+ }else{
+ $self->{'log'}->error("Error fetching interface " . $ep->{'port'} . " on node: " . $ep->{'node'});
+ $self->{'log'}->error($interface->{'error'});
+ return 0;
}
- return \@links;
}
- log_error("unable to find path");
- return;
+
+ $self->{'log'}->error("not a valid endpoint, or not allowed via NSI workgroup: " . Dumper($interface));
+ return 0;
}
=head2 reserveCommit
@@ -479,7 +426,7 @@ sub process_queue {
while(my $message = shift(@{$self->{'reservation_queue'}})){
my $type = $message->{'type'};
- warn Data::Dumper::Dumper($message);
+ #warn Data::Dumper::Dumper($message);
#this is now a scheduler... skip the action if it has a time and we aren't past it yet
if(defined($message->{'time'}) && time() < $message->{'time'}){
#log_error("TIME: " . $message->{'time'} . " vs. " . time());
@@ -750,9 +697,9 @@ sub _release_confirmed{
sub _reserve_timeout{
my ($self, $data) = @_;
- $self->{'websvc'}->set_url($self->{'websvc_location'} . "provisioning.cgi");
+ $self->{'websvc'}->set_url($self->{'websvc_location'} . "circuit.cgi");
- my $res = $self->{'websvc'}->remove_circuit(
+ my $res = $self->{'websvc'}->remove(
circuit_id => $data->{'connection_id'},
workgroup_id => $self->{'workgroup_id'});
diff --git a/perl-lib/OESS/lib/OESS/NSO/Client.pm b/perl-lib/OESS/lib/OESS/NSO/Client.pm
new file mode 100644
index 000000000..8df6c180e
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/Client.pm
@@ -0,0 +1,906 @@
+package OESS::NSO::Client;
+
+use AnyEvent::HTTP;
+use Data::Dumper;
+use Encode;
+use HTTP::Request::Common;
+use JSON;
+use Log::Log4perl;
+use LWP::UserAgent;
+use MIME::Base64;
+use XML::LibXML;
+
+
+=head1 OESS::NSO::Client
+
+OESS::NSO::Client provides a perl interface to the NSO web api.
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = {
+ config_obj => undef,
+ config_filename => '/etc/oess/database.xml',
+ logger => Log::Log4perl->get_logger('OESS.NSO.Client'),
+ local_asn => undef,
+ @_
+ };
+ my $self = bless $args, $class;
+
+ if (!defined $self->{config_obj}) {
+ $self->{config_obj} = new OESS::Config(config_filename => $self->{config_filename});
+ }
+ $self->{local_asn} = $self->{config_obj}->local_as;
+
+ $self->{www} = new LWP::UserAgent;
+
+ # We replace the traditional $ua->credentials approach to basic #
+ # auth as it fails to work with self-signed certs.
+ my $username = $self->{config_obj}->nso_username;
+ my $password = $self->{config_obj}->nso_password;
+
+ my $userpass = "$username:$password";
+ $userpass = Encode::encode("UTF-8", "$username:$password");
+ my $credentials = MIME::Base64::encode($userpass, '');
+
+ $self->{www}->default_header('Authorization' => "Basic $credentials");
+ $self->{www}->default_header('www-authenticate' => 'Basic realm="restconf", charset="UTF-8"');
+ $self->{www}->ssl_opts(verify_hostname => 0);
+
+ return $self;
+}
+
+=head2 create_l2connection
+
+ my $err = create_l2connection($l2connection);
+
+=cut
+sub create_l2connection {
+ my $self = shift;
+ my $conn = shift; # OESS::L2Circuit
+
+ my $eps = [];
+ foreach my $ep (@{$conn->endpoints}) {
+ my $obj = {
+ endpoint_id => $ep->circuit_ep_id,
+ bandwidth => $ep->bandwidth,
+ device => $ep->node,
+ interface => $ep->interface,
+ unit => $ep->unit,
+ tag => $ep->tag
+ };
+ if (defined $ep->inner_tag) {
+ $obj->{inner_tag} = $ep->inner_tag;
+ }
+ push(@$eps, $obj);
+ }
+
+ my $payload = {
+ "oess-l2connection:oess-l2connection" => [
+ {
+ "connection_id" => $conn->circuit_id,
+ "endpoint" => $eps
+ }
+ ]
+ };
+
+ eval {
+ my $res = $self->{www}->post(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/?unhide=oess",
+ 'Content-type' => 'application/yang-data+json',
+ 'Content' => encode_json($payload)
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ warn $err;
+ return $err;
+ }
+ return;
+}
+
+=head2 delete_l2connection
+
+ my $err = delete_l2connection($l2connection_id);
+
+=cut
+sub delete_l2connection {
+ my $self = shift;
+ my $conn_id = shift; # OESS::L2Circuit->circuit_id
+
+ eval {
+ my $res = $self->{www}->delete(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l2connection:oess-l2connection=$conn_id?unhide=oess",
+ 'Content-type' => 'application/yang-data+json'
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ return $err;
+ }
+ return;
+}
+
+=head2 edit_l2connection
+
+ my $err = edit_l2connection($l2connection);
+
+=cut
+sub edit_l2connection {
+ my $self = shift;
+ my $conn = shift; # OESS::L2Circuit
+
+ my $eps = [];
+ foreach my $ep (@{$conn->endpoints}) {
+ my $obj = {
+ endpoint_id => $ep->circuit_ep_id,
+ bandwidth => $ep->bandwidth,
+ device => $ep->node,
+ interface => $ep->interface,
+ unit => $ep->unit,
+ tag => $ep->tag
+ };
+ if (defined $ep->inner_tag) {
+ $obj->{inner_tag} = $ep->inner_tag;
+ }
+ push(@$eps, $obj);
+ }
+
+ my $conn_id = $conn->circuit_id;
+ my $payload = {
+ "oess-l2connection:oess-l2connection" => [
+ {
+ "connection_id" => $conn_id,
+ "endpoint" => $eps
+ }
+ ]
+ };
+
+ eval {
+ my $res = $self->{www}->put(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l2connection:oess-l2connection=$conn_id?unhide=oess",
+ 'Content-type' => 'application/yang-data+json',
+ 'Content' => encode_json($payload)
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ warn $err;
+ return $err;
+ }
+ return;
+}
+
+=head2 get_l2connections
+
+ my ($connections, $err) = get_l2connections();
+
+=cut
+sub get_l2connections {
+ my $self = shift;
+
+ my $connections;
+ eval {
+ my $res = $self->{www}->get(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l2connection:oess-l2connection/?unhide=oess",
+ 'Content-type' => 'application/yang-data+json'
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ if ($res->content eq '') { # Empty payload indicates success
+ $connections = [];
+ } else {
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ $connections = $result->{"oess-l2connection:oess-l2connection"};
+ }
+ };
+ if ($@) {
+ my $err = $@;
+ return (undef, $err);
+ }
+ return ($connections, undef);
+}
+
+=head2 get_json_errors
+
+get_json_errors is a helper method to extract errors returned from nso's rest
+api.
+
+Response code:
+- 201 on success
+- 204 on success no content
+- 400 on error
+- 409 on error conflict
+
+Response body:
+
+ {
+ "errors": {
+ "error": [
+ {
+ "error-message": "object already exists: /oess-l2connection:oess-l2connection[oess-l2connection:connection_id='124']",
+ "error-path": "",
+ "error-tag": "data-exists",
+ "error-type": "application"
+ }
+ ]
+ }
+ }
+
+or
+
+ {
+ "ietf-restconf:errors": {
+ "error": [
+ {
+ "error-type": "application",
+ "error-tag": "invalid-value",
+ "error-message": "uri keypath not found"
+ }
+ ]
+ }
+ }
+
+=cut
+sub get_json_errors {
+ my $self = shift;
+ my $resp = shift;
+
+ my $errs;
+ if (defined $resp->{errors}) {
+ $errs = $resp->{errors};
+ }
+ if (defined $resp->{'ietf-restconf:errors'}) {
+ $errs = $resp->{'ietf-restconf:errors'};
+ }
+ return if !defined $errs;
+
+ my $errors = [];
+ foreach my $err (@{$errs->{error}}) {
+ push(@$errors, $err->{'error-message'});
+ }
+
+ my $r = join(". ", @$errors);
+ return $r;
+}
+
+=head2 create_l3connection
+
+=cut
+sub create_l3connection {
+ my $self = shift;
+ my $conn = shift; # OESS::VRF
+
+ my $eps = [];
+ foreach my $ep (@{$conn->endpoints}) {
+ my $obj = {
+ endpoint_id => $ep->vrf_endpoint_id,
+ bandwidth => $ep->bandwidth,
+ device => $ep->node,
+ interface => $ep->interface,
+ unit => $ep->unit,
+ tag => $ep->tag,
+ mtu => $ep->mtu,
+ peer => []
+ };
+ if (defined $ep->inner_tag) {
+ $obj->{inner_tag} = $ep->inner_tag;
+ }
+
+ foreach my $peer (@{$ep->peers}) {
+ my @peer_ip = split('/', $peer->peer_ip);
+
+ my $peer_obj = {
+ peer_id => $peer->vrf_ep_peer_id,
+ local_asn => $self->{local_asn},
+ local_ip => $peer->local_ip,
+ peer_asn => $peer->peer_asn,
+ peer_ip => $peer_ip[0],
+ bfd => $peer->bfd,
+ md5_key => $peer->md5_key,
+ ip_version => $peer->ip_version
+ };
+ push @{$obj->{peer}}, $peer_obj;
+ }
+
+ push(@$eps, $obj);
+ }
+
+ my $payload = {
+ "oess-l3connection:oess-l3connection" => [
+ {
+ "connection_id" => $conn->vrf_id,
+ "endpoint" => $eps
+ }
+ ]
+ };
+
+ eval {
+ my $res = $self->{www}->post(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/?unhide=oess",
+ 'Content-type' => 'application/yang-data+json',
+ 'Content' => encode_json($payload)
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ warn $err;
+ return $err;
+ }
+ return;
+}
+
+=head2 delete_l3connection
+
+ my $err = delete_l3connection($l3connection_id);
+
+=cut
+sub delete_l3connection {
+ my $self = shift;
+ my $conn_id = shift; # OESS::VRF->vrf_id
+
+ eval {
+ my $res = $self->{www}->delete(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l3connection:oess-l3connection=$conn_id?unhide=oess",
+ 'Content-type' => 'application/yang-data+json'
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ return $err;
+ }
+ return;
+}
+
+=head2 edit_l3connection
+
+ my $err = edit_l3connection($l3connection);
+
+=cut
+sub edit_l3connection {
+ my $self = shift;
+ my $conn = shift; # OESS::VRF
+
+ my $eps = [];
+ foreach my $ep (@{$conn->endpoints}) {
+ my $obj = {
+ endpoint_id => $ep->vrf_endpoint_id,
+ bandwidth => $ep->bandwidth,
+ device => $ep->node,
+ interface => $ep->interface,
+ unit => $ep->unit,
+ tag => $ep->tag,
+ mtu => $ep->mtu,
+ peer => []
+ };
+ if (defined $ep->inner_tag) {
+ $obj->{inner_tag} = $ep->inner_tag;
+ }
+
+ foreach my $peer (@{$ep->peers}) {
+ my @peer_ip = split('/', $peer->peer_ip);
+
+ my $peer_obj = {
+ peer_id => $peer->vrf_ep_peer_id,
+ local_asn => $self->{local_asn},
+ local_ip => $peer->local_ip,
+ peer_asn => $peer->peer_asn,
+ peer_ip => $peer_ip[0],
+ bfd => $peer->bfd,
+ md5_key => $peer->md5_key,
+ ip_version => $peer->ip_version
+ };
+ push @{$obj->{peer}}, $peer_obj;
+ }
+
+ push(@$eps, $obj);
+ }
+
+ my $conn_id = $conn->vrf_id;
+ my $payload = {
+ "oess-l3connection:oess-l3connection" => [
+ {
+ "connection_id" => $conn->vrf_id,
+ "endpoint" => $eps
+ }
+ ]
+ };
+
+ eval {
+ my $res = $self->{www}->put(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l3connection:oess-l3connection=$conn_id?unhide=oess",
+ 'Content-type' => 'application/yang-data+json',
+ 'Content' => encode_json($payload)
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ return if ($res->content eq ''); # Empty payload indicates success
+
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ };
+ if ($@) {
+ my $err = $@;
+ warn $err;
+ return $err;
+ }
+ return;
+}
+
+=head2 get_l3connections
+
+ my ($connections, $err) = get_l3connections();
+
+=cut
+sub get_l3connections {
+ my $self = shift;
+
+ my $connections;
+ eval {
+ my $res = $self->{www}->get(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/oess-l3connection:oess-l3connection/?unhide=oess",
+ 'Content-type' => 'application/yang-data+json'
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ if ($res->content eq '') { # Empty payload indicates success
+ $connections = [];
+ } else {
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ $connections = $result->{"oess-l3connection:oess-l3connection"};
+ }
+ };
+ if ($@) {
+ my $err = $@;
+ return (undef, $err);
+ }
+ return ($connections, undef);
+}
+
+=head2 get_backbones
+
+ my ($backbones, $err) = get_backbones();
+
+Returns:
+
+ [
+ {
+ "name": "POPA-POPB-00,
+ "pdp": [ { "name": "POPA-AAA-0" }, { "name": "POPB-AAA-0" },
+ "summary": {
+ "endpoint": [
+ "device": "xr0",
+ "if-full": "HundredGigE3/1",
+ ...
+ ],
+ ...
+ },
+ ...
+ }
+ ]
+
+=cut
+sub get_backbones {
+ my $self = shift;
+
+ my $backbones;
+ eval {
+ my $res = $self->{www}->get(
+ $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:services/backbone:backbone/",
+ 'Content-type' => 'application/yang-data+json'
+ );
+ if ($res->code >= 400) {
+ die "HTTP Code: " . $res->code . " HTTP Content: " . $res->content;
+ }
+ if ($res->content eq '') { # Empty payload indicates success
+ $backbones = [];
+ } else {
+ my $result = decode_json($res->content);
+ my $err = $self->get_json_errors($result);
+ die $err if defined $err;
+ $backbones = $result->{"backbone:backbone"};
+ }
+ };
+ if ($@) {
+ my $err = $@;
+ return (undef, $err);
+ }
+ return ($backbones, undef);
+}
+
+=head2 get_vrf_statistics
+
+ get_vrf_statistics('agg2.bldc', sub {
+ my ($stats, $err) = @_;
+
+ });
+
+Returns:
+
+ [
+ {
+ 'messages_received' => '0',
+ 'prefixes_synced' => '0',
+ 'prefixes_advertised' => '0',
+ 'remote_ip' => '192.168.2.2',
+ 'bytes_read' => '0',
+ 'vrf_id' => '6000',
+ 'connection_state' => 'BGP_ST_ACTIVE',
+ 'prefixes_denied' => '0',
+ 'bytes_written' => '0',
+ 'prefixes_suppressed' => '0',
+ 'vrf_name' => 'OESS-VRF-6000',
+ 'node' => 'agg2.bldc',
+ 'messages_sent' => '0',
+ 'prefixes_accepted' => '0',
+ 'remote_as' => '2'
+ },
+ {
+ 'messages_received' => '1873',
+ 'prefixes_synced' => '0',
+ 'prefixes_advertised' => '0',
+ 'remote_ip' => '192.168.70.2',
+ 'bytes_read' => '85769',
+ 'vrf_id' => '6000',
+ 'connection_state' => 'BGP_ST_ACTIVE',
+ 'prefixes_denied' => '0',
+ 'bytes_written' => '102456',
+ 'prefixes_suppressed' => '0',
+ 'vrf_name' => 'OESS-VRF-6000',
+ 'node' => 'agg2.bldc',
+ 'messages_sent' => '2846',
+ 'prefixes_accepted' => '0',
+ 'remote_as' => '4200000700'
+ }
+ ]
+
+=cut
+sub get_vrf_statistics {
+ my $self = shift;
+ my $node = shift;
+ my $sub = shift;
+
+ my $payload = {
+ "input" => {
+ "args" => "show operational BGP InstanceTable Instance/InstanceName=default InstanceActive VRFTable VRF/VRFName=* NeighborTable xml"
+ }
+ };
+
+ my $username = $self->{config_obj}->nso_username;
+ my $password = $self->{config_obj}->nso_password;
+
+ my $userpass = "$username:$password";
+ $userpass = Encode::encode("UTF-8", "$username:$password");
+
+ my $credentials = MIME::Base64::encode($userpass, '');
+
+ http_request(
+ POST => $self->{config_obj}->nso_host . "/restconf/operations/tailf-ncs:devices/device=$node/live-status/exec/any",
+ headers => {
+ 'content-type' => 'application/yang-data+json',
+ 'authorization' => "Basic $credentials",
+ 'www-authenticate' => 'Basic realm="restconf", charset="UTF-8"',
+ },
+ body => encode_json($payload),
+ sub {
+ my ($body, $hdr) = @_;
+
+ my $response = [];
+
+ # TODO add eval
+ my $result = decode_json($body);
+ my $err = $self->get_json_errors($result);
+ if (defined $err) {
+ &$sub($response, $err);
+ }
+
+ # Extract CLI payload from JSON response and strip leading
+ # xml tag and ending cli prompt. This results in an XML
+ # encoded string wrapped in the Response tag.
+ my $raw_response = $result->{"tailf-ned-cisco-ios-xr-stats:output"}->{"result"};
+ $raw_response =~ s/^.*.*\z/<\/Response>/s;
+
+ # Parse XMl string and extract statistics
+ my $dom = XML::LibXML->load_xml(string => $raw_response);
+
+ # Lookup Instance named 'default' and get VRFTable from inside
+ my $instances = $dom->findnodes('//Response/Get/Operational/BGP/InstanceTable/Instance');
+ my $instance = undef;
+ foreach my $context ($instances->get_nodelist) {
+
+ my $instance_name = $context->findvalue('//Instance/Naming/InstanceName');
+ $instance_name =~ s/\s+//g;
+ next if $instance_name ne 'default';
+
+ my $vrfs = $context->findnodes('//Instance/InstanceActive/VRFTable/VRF');
+ foreach my $context ($vrfs->get_nodelist) {
+ my $ok = $context->exists('./Naming/VRFName');
+
+ #
+ my $vrf_name = $context->findvalue('./Naming/VRFName');
+ $vrf_name =~ s/\s+//g;
+ next if $vrf_name !~ /^OESS-VRF/;
+
+ $vrf_name =~ /OESS-VRF-(\d+)/;
+ $vrf_id = $1;
+
+ my $peers = $context->findnodes('./NeighborTable/Neighbor');
+ foreach my $context ($peers->get_nodelist) {
+ my $stat = {
+ vrf_name => $vrf_name,
+ vrf_id => $vrf_id,
+ node => $node,
+ remote_ip => undef,
+ connection_state => undef,
+ bytes_read => 0,
+ bytes_written => 0,
+ messages_received => 0,
+ messages_sent => 0,
+ prefixes_accepted => 0,
+ prefixes_denied => 0,
+ prefixes_advertised => 0,
+ prefixes_suppressed => 0,
+ prefixes_synced => 0,
+ };
+
+ # Neighbor addresses to associate with stats.
+ #
+ #
+ my $ipv4 = $context->exists('./Naming/NeighborAddress/IPV4Address');
+ if ($ipv4) {
+ $stat->{remote_ip} = $context->findvalue('./Naming/NeighborAddress/IPV4Address');
+ } else {
+ $stat->{remote_ip} = $context->findvalue('./Naming/NeighborAddress/IPV6Address');
+ }
+ $stat->{remote_ip} =~ s/\s+//g;
+
+ #
+ $stat->{remote_as} = $context->findvalue('./RemoteASNumber');
+ $stat->{remote_as} =~ s/\s+//g;
+
+ # (BGP_ST_ACTIVE|BGP_ST_ESTAB|BGP_ST_IDLE)
+ $stat->{connection_state} = $context->findvalue('./ConnectionState');
+ $stat->{connection_state} =~ s/\s+//g;
+
+ #
+ $stat->{bytes_read} = $context->findvalue('./PerformanceStatistics/DataBytesRead');
+ $stat->{bytes_read} =~ s/\s+//g;
+
+ #
+ $stat->{bytes_written} = $context->findvalue('./PerformanceStatistics/DataBytesWritten');
+ $stat->{bytes_written} =~ s/\s+//g;
+
+ #
+ $stat->{messages_received} = $context->findvalue('./MessagesReceived');
+ $stat->{messages_received} =~ s/\s+//g;
+
+ #
+ $stat->{messages_sent} = $context->findvalue('./MessagesSent');
+ $stat->{messages_sent} =~ s/\s+//g;
+
+ my $afdatas = $context->findnodes('./AFData/Entry');
+ foreach my $context ($afdatas->get_nodelist) {
+ # I'm assuming one entry per-neighbor. Hopefully always the same type.
+ # IPv4
+ # IPv6
+ my $ip_version = $context->findvalue('./AFName');
+ $ip_version =~ s/\s+//g;
+
+ # Only record v4 peering stats if neighbor is using ipv4
+ # Only record v6 peering stats if neighbor is using ipv6
+ next if $ipv4 && $ip_version eq 'IPv6';
+ next if !$ipv4 && $ip_version eq 'IPv4';
+
+ #
+ #
+ #
+ #
+ #
+ $stat->{prefixes_accepted} = $context->findvalue('./PrefixesAccepted');
+ $stat->{prefixes_accepted} =~ s/\s+//g;
+ $stat->{prefixes_denied} = $context->findvalue('./PrefixesDenied');
+ $stat->{prefixes_denied} =~ s/\s+//g;
+ $stat->{prefixes_advertised} = $context->findvalue('./PrefixesAdvertised');
+ $stat->{prefixes_advertised} =~ s/\s+//g;
+ $stat->{prefixes_suppressed} = $context->findvalue('./PrefixesSuppressed');
+ $stat->{prefixes_suppressed} =~ s/\s+//g;
+ $stat->{prefixes_synced} = $context->findvalue('./PrefixesSynced');
+ $stat->{prefixes_synced} =~ s/\s+//g;
+ }
+
+ push @$response, $stat;
+ }
+ }
+ }
+
+ &$sub($response, $err);
+ }
+ );
+}
+
+=head2 get_platform
+
+ get_platform('agg2.bldc', sub {
+ my ($data, $err) = @_;
+
+ });
+
+Returns:
+
+ {
+ 'serial-number' => 'FOC22311UU1',
+ 'version' => '7.2.2',
+ 'model' => 'NCS-5500',
+ 'name' => 'ios-xr'
+ };
+
+=cut
+sub get_platform {
+ my $self = shift;
+ my $node = shift;
+ my $sub = shift;
+
+ my $username = $self->{config_obj}->nso_username;
+ my $password = $self->{config_obj}->nso_password;
+
+ my $userpass = "$username:$password";
+ $userpass = Encode::encode("UTF-8", "$username:$password");
+
+ my $credentials = MIME::Base64::encode($userpass, '');
+
+ http_request(
+ GET => $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:devices/device=$node/platform",
+ headers => {
+ 'content-type' => 'application/yang-data+json',
+ 'authorization' => "Basic $credentials",
+ 'www-authenticate' => 'Basic realm="restconf", charset="UTF-8"',
+ },
+ sub {
+ my ($body, $hdr) = @_;
+
+ my $response = [];
+
+ eval {
+ my $result = decode_json($body);
+ my $err = $self->get_json_errors($result);
+ if (defined $err) {
+ &$sub($result, $err);
+ }
+ &$sub($result->{'tailf-ncs:platform'}, $err);
+ };
+ if ($@) {
+ &$sub(undef, $@);
+ }
+ }
+ );
+}
+
+=head2 get_interfaces
+
+ get_interfaces('agg2.bldc', sub {
+ my ($data, $err) = @_;
+
+ });
+
+Returns:
+
+ {
+ 'TenGigE' => [
+ {
+ 'load-interval' => 30,
+ 'id' => '0/0/0/0/3',
+ 'description' => 'PDP WASH-PC1-12',
+ 'lldp' => {
+ 'enable' => [
+ undef
+ ]
+ }
+ },
+ {
+ 'id' => '0/0/0/0/0',
+ 'description' => 'MX960-2 xe-7/3/0'
+ },
+ {
+ 'shutdown' => [
+ undef
+ ],
+ 'id' => '0/0/0/1/0'
+ }
+ ]
+ }
+
+=cut
+sub get_interfaces {
+ my $self = shift;
+ my $node = shift;
+ my $sub = shift;
+
+ my $username = $self->{config_obj}->nso_username;
+ my $password = $self->{config_obj}->nso_password;
+
+ my $userpass = "$username:$password";
+ $userpass = Encode::encode("UTF-8", "$username:$password");
+
+ my $credentials = MIME::Base64::encode($userpass, '');
+
+ http_request(
+ GET => $self->{config_obj}->nso_host . "/restconf/data/tailf-ncs:devices/device=$node/config/tailf-ned-cisco-ios-xr:interface",
+ headers => {
+ 'content-type' => 'application/yang-data+json',
+ 'authorization' => "Basic $credentials",
+ 'www-authenticate' => 'Basic realm="restconf", charset="UTF-8"',
+ },
+ sub {
+ my ($body, $hdr) = @_;
+
+ my $response = [];
+
+ eval {
+ my $result = decode_json($body);
+ my $err = $self->get_json_errors($result);
+ if (defined $err) {
+ &$sub($result, $err);
+ }
+ &$sub($result->{'tailf-ned-cisco-ios-xr:interface'}, $err);
+ };
+ if ($@) {
+ &$sub(undef, $@);
+ }
+ }
+ );
+}
+
+1;
diff --git a/perl-lib/OESS/lib/OESS/NSO/ClientStub.pm b/perl-lib/OESS/lib/OESS/NSO/ClientStub.pm
new file mode 100644
index 000000000..b9f50c995
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/ClientStub.pm
@@ -0,0 +1,398 @@
+package OESS::NSO::ClientStub;
+
+use Data::Dumper;
+use HTTP::Request::Common;
+use JSON;
+use Log::Log4perl;
+use LWP::UserAgent;
+use XML::LibXML;
+
+=head1 OESS::NSO::Client
+
+OESS::NSO::Client provides a perl interface to the NSO web api.
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = {
+ @_
+ };
+ my $self = bless $args, $class;
+ return $self;
+}
+
+=head2 create_l2connection
+
+ my $err = create_l2connection($l2connection);
+
+=cut
+sub create_l2connection {
+ my $self = shift;
+ my $conn = shift; # OESS::L2Circuit
+ return;
+}
+
+=head2 delete_l2connection
+
+ my $err = delete_l2connection($l2connection_id);
+
+=cut
+sub delete_l2connection {
+ my $self = shift;
+ my $conn_id = shift; # OESS::L2Circuit->circuit_id
+ return;
+}
+
+=head2 edit_l2connection
+
+ my $err = edit_l2connection($l2connection);
+
+=cut
+sub edit_l2connection {
+ my $self = shift;
+ my $conn = shift; # OESS::L2Circuit
+ return;
+}
+
+=head2 get_l2connections
+
+ my ($connections, $err) = get_l2connections();
+
+=cut
+sub get_l2connections {
+ my $self = shift;
+
+ my $connections = [
+ {
+ 'connection_id' => 4081,
+ 'directly-modified' => {
+ 'services' => [
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'0\'][sdp:name=\'3000\']',
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'1\'][sdp:name=\'3000\']'
+ ],
+ 'devices' => [
+ 'xr0'
+ ]
+ },
+ 'endpoint' => [
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 1,
+ 'interface' => 'GigabitEthernet0/0',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ },
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 2,
+ 'interface' => 'GigabitEthernet0/1',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ }
+ ],
+ 'device-list' => [
+ 'xr0'
+ ],
+ 'modified' => {
+ 'services' => [
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'1\'][sdp:name=\'3000\']',
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'0\'][sdp:name=\'3000\']'
+ ],
+ 'devices' => [
+ 'xr0'
+ ]
+ }
+ }
+ ];
+ return ($connections, undef);
+}
+
+=head2 get_json_errors
+
+get_json_errors is a helper method to extract errors returned from nso's rest
+api.
+
+Response code:
+- 201 on success
+- 204 on success no content
+- 400 on error
+- 409 on error conflict
+
+Response body:
+
+ {
+ "errors": {
+ "error": [
+ {
+ "error-message": "object already exists: /oess-l2connection:oess-l2connection[oess-l2connection:connection_id='124']",
+ "error-path": "",
+ "error-tag": "data-exists",
+ "error-type": "application"
+ }
+ ]
+ }
+ }
+
+=cut
+sub get_json_errors {
+ my $self = shift;
+ my $errs = shift;
+
+ my $errors = [];
+ foreach my $err (@{$errs->{error}}) {
+ push(@$errors, $err->{'error-message'});
+ }
+
+ my $r = join(". ", @$errors);
+ return $r;
+}
+
+=head2 create_l3connection
+
+=cut
+sub create_l3connection {
+ my $self = shift;
+ my $conn = shift; # OESS::VRF
+ return;
+}
+
+=head2 delete_l3connection
+
+ my $err = delete_l3connection($l3connection_id);
+
+=cut
+sub delete_l3connection {
+ my $self = shift;
+ my $conn_id = shift; # OESS::VRF->vrf_id
+ return;
+}
+
+=head2 edit_l3connection
+
+ my $err = edit_l3connection($l3connection);
+
+=cut
+sub edit_l3connection {
+ my $self = shift;
+ return;
+}
+
+=head2 get_l3connections
+
+ my ($connections, $err) = get_l3connections();
+
+=cut
+sub get_l3connections {
+ my $self = shift;
+
+ my $connections = [
+ {
+ "connection_id" => 1,
+ "endpoint" => [
+ {
+ "endpoint_id" => 8,
+ "vars" => {
+ "pdp" => "CHIC-JJJ-0",
+ "ce_id" => 1,
+ "remote_ce_id" => 2
+ },
+ "device" => "Node 11",
+ "interface" => "e15/6",
+ "tag" => 300,
+ "bandwidth" => 200,
+ "peer" => [
+ {
+ "peer_id" => 1,
+ "local_asn" => 64600,
+ "local_ip" => "192.168.3.2/31",
+ "peer_asn" => 64001,
+ "peer_ip" => "192.168.3.3",
+ "bfd" => 1,
+ "ip_version" => "ipv4"
+ }
+ ]
+ },
+ {
+ "endpoint_id" => 2,
+ "vars" => {
+ "pdp" => "CHIC-JJJ-1",
+ "ce_id" => 2,
+ "remote_ce_id" => 1
+ },
+ "device" => "xr1",
+ "interface" => "GigabitEthernet0/1",
+ "tag" => 300,
+ "bandwidth" => 100,
+ "peer" => [
+ {
+ "peer_id" => 2,
+ "local_asn" => 64600,
+ "local_ip" => "192.168.2.2/31",
+ "peer_asn" => 64602,
+ "peer_ip" => "192.168.2.3",
+ "bfd" => 0,
+ "ip_version" => "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+ ];
+ return ($connections, undef);
+}
+
+=head2 get_backbones
+
+ my ($backbones, $err) = get_backbones();
+
+=cut
+sub get_backbones {
+ my $backbones = [
+ {
+ "name" => "ALBA-ASHB-00",
+ "modified" => {
+ "devices" => ["rr0", "rr1"],
+ "services" => ["/i2c:internal-services/pdp:sdp-attach[pdp:pdp='ASHB-JJJ-3'][pdp:name='ALBA-ASHB-00']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='ALBA-JJJ-3'][pdp:name='ALBA-ASHB-00']", "/ncs:services/pdp:pdp[pdp:name='ASHB-JJJ-3']", "/ncs:services/pdp:pdp[pdp:name='ALBA-JJJ-3']"]
+ },
+ "directly-modified" => {
+ "devices" => ["rr0", "rr1"],
+ "services" => ["/ncs:services/pdp:pdp[pdp:name='ALBA-JJJ-3']", "/ncs:services/pdp:pdp[pdp:name='ASHB-JJJ-3']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='ALBA-JJJ-3'][pdp:name='ALBA-ASHB-00']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='ASHB-JJJ-3'][pdp:name='ALBA-ASHB-00']"]
+ },
+ "device-list" => ["rr0", "rr1"],
+ "pdp" => [
+ {
+ "name" => "ALBA-JJJ-3"
+ },
+ {
+ "name" => "ASHB-JJJ-3"
+ }
+ ],
+ "metric-override" => 1,
+ "admin-state" => "in-service",
+ "summary" => {
+ "circuit-id" => "",
+ "endpoint" => [
+ {
+ "pdp" => "ALBA-JJJ-3",
+ "device" => "rr0",
+ "if-full" => "HundredGigE3/1",
+ "ipv4-address" => "192.0.2.2/31",
+ "ipv6-address" => "2001:db8::2/127"
+ },
+ {
+ "pdp" => "ASHB-JJJ-3",
+ "device" => "rr1",
+ "if-full" => "HundredGigE3/1",
+ "ipv4-address" => "192.0.2.3/31",
+ "ipv6-address" => "2001:db8::3/127"
+ }
+ ]
+ },
+ "vars" => {
+ "ipv4-prefix" => "192.0.2.2/31",
+ "ipv6-prefix" => "2001:db8::2/127",
+ "metric" => 1,
+ "endpoint" => [
+ {
+ "pdp" => "ALBA-JJJ-3",
+ "ipv4-address" => "192.0.2.2/31",
+ "ipv6-address" => "2001:db8::2/127",
+ "if-full" => "HundredGigE3/1"
+ },
+ {
+ "pdp" => "ASHB-JJJ-3",
+ "ipv4-address" => "192.0.2.3/31",
+ "ipv6-address" => "2001:db8::3/127",
+ "if-full" => "HundredGigE3/1"
+ }
+ ],
+ "sdp-description" => "BACKBONE: RR0-RR1"
+ }
+ },
+ {
+ "name" => "CHIC-EQCH-00",
+ "modified" => {
+ "devices" => ["xr0", "xr1"],
+ "services" => ["/i2c:internal-services/pdp:sdp-attach[pdp:pdp='EQCH-JJJ-2'][pdp:name='CHIC-EQCH-00']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='CHIC-JJJ-2'][pdp:name='CHIC-EQCH-00']", "/ncs:services/pdp:pdp[pdp:name='EQCH-JJJ-2']", "/ncs:services/pdp:pdp[pdp:name='CHIC-JJJ-2']"]
+ },
+ "directly-modified" => {
+ "devices" => ["xr0", "xr1"],
+ "services" => ["/ncs:services/pdp:pdp[pdp:name='CHIC-JJJ-2']", "/ncs:services/pdp:pdp[pdp:name='EQCH-JJJ-2']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='CHIC-JJJ-2'][pdp:name='CHIC-EQCH-00']", "/i2c:internal-services/pdp:sdp-attach[pdp:pdp='EQCH-JJJ-2'][pdp:name='CHIC-EQCH-00']"]
+ },
+ "device-list" => ["xr0", "xr1"],
+ "pdp" => [
+ {
+ "name" => "CHIC-JJJ-2"
+ },
+ {
+ "name" => "EQCH-JJJ-2"
+ }
+ ],
+ "admin-state" => "in-service",
+ "summary" => {
+ "circuit-id" => "",
+ "endpoint" => [
+ {
+ "pdp" => "CHIC-JJJ-2",
+ "device" => "xr0",
+ "if-full" => "HundredGigE3/0",
+ "ipv4-address" => "192.0.2.0/31",
+ "ipv6-address" => "2001:db8::/127"
+ },
+ {
+ "pdp" => "EQCH-JJJ-2",
+ "device" => "xr1",
+ "if-full" => "HundredGigE3/0",
+ "ipv4-address" => "192.0.2.1/31",
+ "ipv6-address" => "2001:db8::1/127"
+ }
+ ]
+ },
+ "vars" => {
+ "ipv4-prefix" => "192.0.2.0/31",
+ "ipv6-prefix" => "2001:db8::/127",
+ "metric" => 20,
+ "srlg-name" => ["SRLG06"],
+ "endpoint" => [
+ {
+ "pdp" => "CHIC-JJJ-2",
+ "ipv4-address" => "192.0.2.0/31",
+ "ipv6-address" => "2001:db8::/127",
+ "if-full" => "HundredGigE3/0"
+ },
+ {
+ "pdp" => "EQCH-JJJ-2",
+ "ipv4-address" => "192.0.2.1/31",
+ "ipv6-address" => "2001:db8::1/127",
+ "if-full" => "HundredGigE3/0"
+ }
+ ],
+ "sdp-description" => "BACKBONE: XR0-XR1"
+ }
+ }
+ ];
+ return ($backbones, undef);
+}
+
+=head2 get_platform
+
+=cut
+sub get_platform {
+ my $self = shift;
+ my $node = shift;
+ my $sub = shift;
+
+ my $result = {
+ 'serial-number' => 'FOC22311UU1',
+ 'version' => '7.2.2',
+ 'model' => 'NCS-5500',
+ 'name' => 'ios-xr'
+ };
+ &$sub($result, undef);
+}
+
+1;
diff --git a/perl-lib/OESS/lib/OESS/NSO/ConnectionCache.pm b/perl-lib/OESS/lib/OESS/NSO/ConnectionCache.pm
new file mode 100644
index 000000000..9ded72dff
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/ConnectionCache.pm
@@ -0,0 +1,156 @@
+package OESS::NSO::ConnectionCache;
+
+=head1 OESS::NSO::ConnectionCache
+
+An in memory connection cache:
+
+ {
+ "node-id-1": {
+ "conn-id-1": { "eps" : [ "node-id-1", "node-id-2" ] }
+ },
+ "node-id-2": {
+ "conn-id-1": { "eps" : [ "node-id-1", "node-id-2" ] }
+ }
+ }
+
+This implies that a connection is stored under each node. This allows us to
+query all connections associated with a single node. Additionally this helps us
+track large changes that may effect multiple connections on a single node.
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = { @_ };
+ my $self = bless $args, $class;
+
+ $self->{cache} = {};
+ $self->{l3_cache} = {};
+ $self->{flat_cache} = {};
+ $self->{l3_flat_cache} = {};
+
+ return $self;
+}
+
+=head2 clear
+
+=cut
+sub clear {
+ my $self = shift;
+
+ $self->{cache} = {};
+ $self->{l3_cache} = {};
+ $self->{flat_cache} = {};
+ $self->{l3_flat_cache} = {};
+
+ return 1;
+}
+
+=head2 get_included_nodes
+
+=cut
+sub get_included_nodes {
+ my $self = shift;
+
+ my $id_index = {};
+ foreach my $node_id (keys %{$self->{cache}}) {
+ $id_index->{$node_id} = 1;
+ }
+ foreach my $node_id (keys %{$self->{l3_cache}}) {
+ $id_index->{$node_id} = 1;
+ }
+
+ my @ids = keys %{$id_index};
+ return \@ids;
+}
+
+=head2 get_connections_by_node
+
+=cut
+sub get_connections_by_node {
+ my $self = shift;
+ my $node_id = shift;
+ my $type = shift;
+
+ my $cache = 'cache';
+ my $flat_cache = 'flat_cache';
+ if ($type eq 'l3') {
+ $cache = 'l3_cache';
+ $flat_cache = 'l3_flat_cache';
+ }
+
+ my $result = [];
+ foreach my $conn_id (keys %{$self->{$cache}->{$node_id}}) {
+ push @$result, $self->{$cache}->{$node_id}->{$conn_id};
+ }
+ return $result;
+};
+
+=head2 add_connection
+
+=cut
+sub add_connection {
+ my $self = shift;
+ my $conn = shift;
+ my $type = shift;
+
+ my $cache = 'cache';
+ my $conn_id = undef;
+ my $flat_cache = 'flat_cache';
+ if ($type eq 'l3') {
+ $cache = 'l3_cache';
+ $conn_id = $conn->vrf_id;
+ $flat_cache = 'l3_flat_cache';
+ } else {
+ $conn_id = $conn->circuit_id;
+ }
+
+ # Handle case where connection has no endpoints or a connection
+ # created with an empty model.
+ my $endpoints = $conn->endpoints || [];
+
+ foreach my $ep (@{$endpoints}) {
+ if (!defined $self->{$cache}->{$ep->node_id}) {
+ $self->{$cache}->{$ep->node_id} = {};
+ }
+ $self->{$cache}->{$ep->node_id}->{$conn_id} = $conn;
+ }
+ $self->{$flat_cache}->{$conn_id} = $conn;
+
+ return 1;
+}
+
+=head2 remove_connection
+
+=cut
+sub remove_connection {
+ my $self = shift;
+ my $conn = shift;
+ my $type = shift;
+
+ my $cache = 'cache';
+ my $conn_id = undef;
+ my $flat_cache = 'flat_cache';
+ if ($type eq 'l3') {
+ $cache = 'l3_cache';
+ $conn_id = $conn->vrf_id;
+ $flat_cache = 'l3_flat_cache';
+ } else {
+ $conn_id = $conn->circuit_id;
+ }
+
+ foreach my $ep (@{$conn->endpoints}) {
+ if (!defined $self->{$cache}->{$ep->node_id}) {
+ next;
+ }
+ delete $self->{$cache}->{$ep->node_id}->{$conn_id};
+ }
+ delete $self->{$flat_cache}->{$conn_id};
+
+ return 1;
+}
+
+return 1;
diff --git a/perl-lib/OESS/lib/OESS/NSO/Discovery.pm b/perl-lib/OESS/lib/OESS/NSO/Discovery.pm
new file mode 100644
index 000000000..84ab35acf
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/Discovery.pm
@@ -0,0 +1,656 @@
+use strict;
+use warnings;
+
+package OESS::NSO::Discovery;
+
+use AnyEvent;
+use Data::Dumper;
+use GRNOC::RabbitMQ::Method;
+use HTTP::Request::Common;
+use JSON;
+use Log::Log4perl;
+use LWP::UserAgent;
+use XML::LibXML;
+
+use OESS::Config;
+use OESS::DB;
+use OESS::DB::Interface;
+use OESS::DB::Node;
+use OESS::Node;
+use OESS::RabbitMQ::Dispatcher;
+
+use constant MAX_TSDS_MESSAGES => 30;
+use constant TSDS_RIB_TYPE => 'rib_table';
+use constant TSDS_PEER_TYPE => 'bgp_peer';
+use constant VRF_STATS_INTERVAL => 60;
+
+=head1 OESS::NSO::Discovery
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = {
+ config => '/etc/oess/database.xml',
+ config_obj => undef,
+ nso => undef, # OESS::NSO:Client or OESS::NSO::ClientStub
+ logger => Log::Log4perl->get_logger('OESS.NSO.Discovery'),
+ @_
+ };
+ my $self = bless $args, $class;
+
+ if (!defined $self->{config_obj}) {
+ $self->{config_obj} = new OESS::Config(config_filename => $self->{config});
+ }
+ $self->{db} = new OESS::DB(config => $self->{config_obj}->filename);
+ $self->{nodes} = {};
+
+ $self->{www} = new LWP::UserAgent;
+ my $host = $self->{config_obj}->nso_host;
+ $host =~ s/http(s){0,1}:\/\///g; # Strip http:// or https:// from string
+ $self->{www}->credentials($host, "restconf", $self->{config_obj}->nso_username, $self->{config_obj}->nso_password);
+
+ # When this process receives sigterm send an event to notify all
+ # children to exit cleanly.
+ $SIG{TERM} = sub {
+ $self->stop;
+ };
+
+ return $self;
+}
+
+=head2 connection_handler
+
+=cut
+sub connection_handler {
+ my $self = shift;
+
+ return 1;
+}
+
+=head2 fetch_platform
+
+=cut
+sub fetch_platform {
+ my $self = shift;
+
+ $self->{logger}->info("Calling fetch_platform.");
+
+ my $results = {};
+
+ my $cv = AnyEvent->condvar;
+ $cv->begin(
+ sub {
+ my $cv = shift;
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+ my $result = $results->{$node->{name}};
+ next if !defined $result;
+
+ $self->{db}->start_transaction;
+ my $device = new OESS::Node(db => $self->{db}, name => $node->{name});
+ if (!defined $device) {
+ warn "Couldn't find node $result->{name}.";
+ $self->{logger}->error("Couldn't find node $result->{name}.");
+ }
+
+ $device->model($result->{model});
+ $device->sw_version($result->{version});
+ $device->vendor('Cisco') if ($result->{name} eq 'ios-xr');
+ $device->update;
+ $self->{db}->commit;
+ }
+ $cv->send;
+ }
+ );
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+
+ $cv->begin;
+ $self->{nso}->get_platform(
+ $node->{name},
+ sub {
+ my ($result, $err) = @_;
+ if (defined $err) {
+ $self->{logger}->error("fetch_platform: $err");
+ $results->{$node->{name}} = undef;
+ } else {
+ $results->{$node->{name}} = $result;
+ }
+ $cv->end;
+ }
+ );
+ }
+ $cv->end;
+
+ $self->{logger}->info("Platform data fetched from NSO.");
+}
+
+=head2 fetch_interfaces
+
+fetch_interfaces queries each device for interface configuration and
+operational state.
+
+=cut
+sub fetch_interfaces {
+ my $self = shift;
+ $self->{logger}->info("Calling fetch_interfaces.");
+
+ my $results = {};
+
+ my $cv = AnyEvent->condvar;
+ $cv->begin(
+ sub {
+ my $cv = shift;
+
+ my $types = ["Bundle-Ether", "GigabitEthernet", "TenGigE", "FortyGigE", "HundredGigE", "FourHundredGigE"];
+ my $ports = [];
+
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+ my $result = $results->{$node->{name}};
+ next if !defined $result;
+
+ foreach my $type (@$types) {
+ next if !defined $result->{$type};
+
+ foreach my $port (@{$result->{$type}}) {
+ my $port_info = {
+ admin_state => (exists $port->{shutdown}) ? 'down' : 'up',
+ bandwidth => (exists $port->{speed}) ? $port->{speed} : 1000,
+ description => (exists $port->{description}) ? $port->{description} : '',
+ mtu => (exists $port->{mtu}) ? $port->{mtu} : 0,
+ name => $type . $port->{id},
+ node => $node->{name},
+ node_id => $node->{node_id}
+ };
+ push @$ports, $port_info;
+ }
+ }
+ }
+
+ $self->{db}->start_transaction;
+ foreach my $data (@$ports) {
+ my $port = new OESS::Interface(db => $self->{db}, node => $data->{node}, name => $data->{name});
+ if (defined $port) {
+ $port->admin_state($data->{admin_state});
+ $port->bandwidth($data->{bandwidth});
+ $port->description($data->{description});
+ $port->mtu($data->{mtu});
+ $port->update_db;
+ } else {
+ warn "Couldn't find interface $data->{node} $data->{name}; Creating interface.";
+ $self->{logger}->warn("Couldn't find interface $data->{node} $data->{name}; Creating interface.");
+
+ $port = new OESS::Interface(db => $self->{db}, model => {
+ admin_state => $data->{admin_state},
+ bandwidth => $data->{bandwidth},
+ description => $data->{description},
+ mtu => $data->{mtu},
+ name => $data->{name},
+ operational_state => $data->{admin_state} # Using admin_state as best guess for now
+ });
+
+ my ($port_id, $port_err) = $port->create(node_id => $data->{node_id});
+ if (defined $port_err) {
+ warn "Couldn't create interface $data->{node} $data->{name}.";
+ $self->{logger}->error("Couldn't create interface $data->{node} $data->{name}.")
+ }
+ }
+ }
+ $self->{db}->commit;
+
+ $cv->send;
+ }
+ );
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+
+ $cv->begin;
+ $self->{nso}->get_interfaces(
+ $node->{name},
+ sub {
+ my ($result, $err) = @_;
+ if (defined $err) {
+ $self->{logger}->error("fetch_interfaces: $err");
+ $results->{$node->{name}} = undef;
+ } else {
+ $results->{$node->{name}} = $result;
+ }
+ $cv->end;
+ }
+ );
+ }
+ $cv->end;
+
+ $self->{logger}->info("Interfaces fetched from NSO.");
+}
+
+=head2 link_handler
+
+=cut
+sub link_handler {
+ my $self = shift;
+
+ # lookup links name and put into index
+ my ($links, $links_err) = OESS::DB::Link::fetch_all(db => $self->{db});
+
+ my $links_index = {};
+ foreach my $link (@$links) {
+ $links_index->{$link->{name}} = $link;
+ }
+
+ # get links from nso
+ my ($backbones, $err) = $self->{nso}->get_backbones();
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return;
+ }
+
+ # lookup nso links in index
+ foreach my $bb (@$backbones) {
+
+ my $n = scalar @{$bb->{summary}->{endpoint}};
+ if ($n != 2) {
+ $self->{logger}->error("Couldn't process link $bb->{name}. Got $n endpoinds but only expected 2.");
+ next;
+ }
+
+ # Lookup interface ids of backbone edges
+ my $eps = [];
+ foreach my $ep (@{$bb->{summary}->{endpoint}}) {
+ my $id = OESS::DB::Interface::get_interface(
+ db => $self->{db},
+ interface => $ep->{'if-full'},
+ node => $ep->{'device'},
+ );
+ if (!defined $id) {
+ $self->{logger}->warn("Couldn't find interface for $ep->{'device'} - $ep->{'if-full'} in database.");
+ next;
+ }
+ push @$eps, { id => $id, ip => $ep->{'ipv4-address'} };
+ }
+ if (@$eps != 2) {
+ $self->{logger}->error("Couldn't sync link $bb->{name} due to interface lookup errors.");
+ next;
+ }
+
+ # We assume admin-state represents both status and
+ # link-state. This is likely a bad assumption.
+ if ($bb->{'admin-state'} eq 'in-service') {
+ $bb->{link_state} = 'active';
+ $bb->{status} = 'up';
+ } else {
+ $bb->{link_state} = 'available';
+ $bb->{status} = 'down';
+ }
+
+ # if !exists create
+ if (!defined $links_index->{$bb->{name}}) {
+ $self->{logger}->info("Creating link $bb->{name}.");
+
+ my ($link_id, $link_err) = OESS::DB::Link::create(
+ db => $self->{db},
+ model => {
+ name => $bb->{name},
+ status => $bb->{status},
+ metric => 1,
+ interface_a_id => $eps->[0]->{id},
+ ip_a => $eps->[0]->{ip},
+ interface_z_id => $eps->[1]->{id},
+ ip_z => $eps->[1]->{ip},
+ }
+ );
+ $self->{logger}->error($link_err) if defined $link_err;
+ }
+ # el update if interfaces changed
+ else {
+ my $link = $links_index->{$bb->{name}};
+
+ my $interfaces_changed = 1;
+ if ($eps->[0]->{id} == $link->{interface_a_id} && $eps->[1]->{id} == $link->{interface_z_id}) {
+ $interfaces_changed = 0;
+ }
+ if ($eps->[0]->{id} == $link->{interface_z_id} && $eps->[1]->{id} == $link->{interface_a_id}) {
+ $interfaces_changed = 0;
+ }
+ my $state_changed = ($bb->{link_state} ne $link->{link_state}) ? 1 : 0;
+ my $status_changed = ($bb->{status} ne $link->{status}) ? 1 : 0;
+
+ if ($interfaces_changed || $state_changed || $status_changed) {
+ my $msg = "Updating link $bb->{name}:";
+ $msg .= " interface changed." if $interfaces_changed;
+ $msg .= " state changed." if $state_changed;
+ $msg .= " status changed." if $status_changed;
+ $self->{logger}->info($msg);
+
+ my ($link_id, $link_err) = OESS::DB::Link::update(
+ db => $self->{db},
+ link => {
+ link_id => $link->{link_id},
+ link_state => $bb->{link_state},
+ status => $bb->{status},
+ interface_a_id => $eps->[0]->{id},
+ ip_a => $eps->[0]->{ip},
+ interface_z_id => $eps->[1]->{id},
+ ip_z => $eps->[1]->{ip},
+ }
+ );
+ $self->{logger}->error($link_err) if defined $link_err;
+ }
+
+ # remove link from index
+ delete $links_index->{$bb->{name}};
+ }
+
+ # decom all links still in index
+ foreach my $name (keys %$links_index) {
+ my $link = $links_index->{$name};
+ $self->{logger}->info("Decommissioning link $link->{name}.");
+
+ my ($link_id, $link_err) = OESS::DB::Link::update(
+ db => $self->{db},
+ link => {
+ link_id => $link->{link_id},
+ link_state => 'decom',
+ status => 'down',
+ interface_a_id => $link->{interface_a_id},
+ ip_a => $link->{ip_a},
+ interface_z_id => $link->{interface_z_id},
+ ip_z => $link->{ip_z},
+ }
+ );
+ $self->{logger}->error($link_err) if defined $link_err;
+ }
+ }
+
+ return 1;
+}
+
+=head2 new_switch
+
+=cut
+sub new_switch {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{'success_callback'};
+ my $error = $method->{'error_callback'};
+
+ if (defined $self->{nodes}->{$params->{node_id}{value}}) {
+ $self->{logger}->warn("Node $params->{node_id}{value} already registered with Discovery.");
+ return &$success({ status => 1 });
+ }
+
+ my $node = OESS::DB::Node::fetch(db => $self->{db}, node_id => $params->{node_id}{value});
+ if (!defined $node) {
+ my $err = "Couldn't lookup node $params->{node_id}{value}. Discovery will not properly complete on this node.";
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ $self->{nodes}->{$params->{node_id}{value}} = $node;
+
+ warn "Switch $node->{name} registered with NSO.Discovery.";
+ $self->{logger}->info("Switch $node->{name} registered with NSO.Discovery.");
+
+ # Make first invocation of polling subroutines
+ $self->fetch_platform;
+ $self->fetch_interfaces;
+
+ return &$success({ status => 1 });
+}
+
+=head2 start
+
+=cut
+sub start {
+ my $self = shift;
+
+ # Load devices from database
+ my $nodes = OESS::DB::Node::fetch_all(db => $self->{db}, controller => 'nso');
+ if (!defined $nodes) {
+ warn "Couldn't lookup nodes. Discovery will not collect data on any existing nodes.";
+ $self->{logger}->error("Couldn't lookup nodes. Discovery will not collect data on any existing nodes.");
+ }
+ foreach my $node (@$nodes) {
+ $self->{nodes}->{$node->{node_id}} = $node;
+ }
+
+ # Setup polling subroutines
+ $self->{connection_timer} = AnyEvent->timer(
+ after => 20,
+ interval => 60,
+ cb => sub { $self->connection_handler(@_); }
+ );
+ $self->{device_timer} = AnyEvent->timer(
+ after => 10,
+ interval => 60,
+ cb => sub { $self->fetch_platform(@_); }
+ );
+ $self->{interface_timer} = AnyEvent->timer(
+ after => 60,
+ interval => 120,
+ cb => sub { $self->fetch_interfaces(@_); }
+ );
+ $self->{link_timer} = AnyEvent->timer(
+ after => 90,
+ interval => 120,
+ cb => sub { $self->link_handler(@_); }
+ );
+ $self->{vrf_stats_time} = AnyEvent->timer(
+ after => 30,
+ interval => VRF_STATS_INTERVAL,
+ cb => sub { $self->vrf_stats_handler(@_); }
+ );
+
+
+ $self->{dispatcher} = new OESS::RabbitMQ::Dispatcher(
+ queue => 'NSO-Discovery',
+ topic => 'NSO.Discovery.RPC'
+ );
+
+ my $new_switch = new GRNOC::RabbitMQ::Method(
+ name => 'new_switch',
+ description => 'Add a new switch process to Discovery',
+ async => 1,
+ callback => sub { $self->new_switch(@_); }
+ );
+ $new_switch->add_input_parameter(
+ name => 'node_id',
+ description => 'Id of the new node',
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::NUMBER_ID
+ );
+ $self->{dispatcher}->register_method($new_switch);
+
+ my $is_online = new GRNOC::RabbitMQ::Method(
+ name => "is_online",
+ description => 'Return if this service is online',
+ async => 1,
+ callback => sub {
+ my $method = shift;
+ return $method->{success_callback}({ successful => 1 });
+ }
+ );
+ $self->{dispatcher}->register_method($is_online);
+
+ return 1;
+}
+
+
+=head2 vrf_stats_handler
+
+=cut
+sub vrf_stats_handler {
+ my $self = shift;
+ $self->{logger}->info("Calling vrf_stats_handler.");
+
+ my $results = {};
+
+ my $cv = AnyEvent->condvar;
+ $cv->begin(
+ sub {
+ my $cv = shift;
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+ next if !defined $results->{$node->{name}};
+
+ $self->handle_vrf_stats(node => $node->{name}, stats => $results->{$node->{name}});
+ }
+ $cv->send;
+ }
+ );
+ foreach my $key (keys %{$self->{nodes}}) {
+ my $node = $self->{nodes}->{$key};
+
+ $cv->begin;
+ $self->{nso}->get_vrf_statistics(
+ $node->{name},
+ sub {
+ my ($result, $err) = @_;
+ if (defined $err) {
+ $self->{logger}->error("vrf_stats_handler: $err");
+ $results->{$node->{name}} = [];
+ } else {
+ $results->{$node->{name}} = $result;
+ }
+ $cv->end;
+ }
+ );
+ }
+ $cv->end;
+
+ $self->{logger}->info("Statistics submitted to TSDS.");
+}
+
+=head2 handle_vrf_stats
+
+=cut
+sub handle_vrf_stats {
+ my $self = shift;
+ my %params = @_;
+
+ my $node = $params{'node'};
+ my $stats = $params{'stats'};
+
+ return if (!defined $stats || @$stats == 0);
+
+ my $time = time();
+ my $all_val = [];
+
+ while (@$stats > 0) {
+ my $stat = shift @$stats;
+
+ my $prev_stat = $self->{previous_peer}->{$stat->{node}}->{$stat->{vrf_name}}->{$stat->{remote_ip}};
+ if (!defined $prev_stat) {
+ $self->{logger}->warn("Previous stats unavailable for $stat->{node}. Collection will resume with the next datapoints.");
+ $self->{previous_peer}->{$stat->{node}}->{$stat->{vrf_name}}->{$stat->{remote_ip}} = $stat;
+ next;
+ }
+
+ # Most neighbor stats we collected from Juniper have no direct
+ # mapping to Cisco.
+ my $rib_data = {
+ total_prefix_count => 0,
+ received_prefix_count => 0,
+ accepted_prefix_count => $stat->{prefixes_accepted},
+ active_prefix_count => $stat->{prefixes_accepted},
+ suppressed_prefix_count => $stat->{prefixes_suppressed},
+ history_prefix_count => 0,
+ damped_prefix_count => 0,
+ pending_prefix_count => 0,
+ total_external_prefix_count => 0,
+ active_external_prefix_count => 0,
+ accepted_external_prefix_count => 0,
+ suppressed_external_prefix_count => 0,
+ total_internal_prefix_count => 0,
+ active_internal_prefix_count => 0,
+ accepted_internal_prefix_count => 0,
+ suppressed_internal_prefix_count => 0,
+ };
+ my $rib_metadata = {
+ routing_table => $stat->{vrf_name},
+ node => $stat->{node},
+ };
+ push @$all_val, {
+ type => TSDS_RIB_TYPE,
+ time => $time,
+ interval => VRF_STATS_INTERVAL,
+ values => $rib_data,
+ meta => $rib_metadata,
+ };
+
+ my $peer_data = {
+ output_messages => ($stat->{messages_sent} - $prev_stat->{messages_sent}) / VRF_STATS_INTERVAL,
+ input_messages => ($stat->{messages_received} - $prev_stat->{messages_received}) / VRF_STATS_INTERVAL,
+ route_queue_count => 0,
+ flap_count => 0,
+ state => ($stat->{connection_state} eq 'BGP_ST_ESTAB') ? 1 : 0,
+ };
+ my $peer_metadata = {
+ peer_address => $stat->{remote_ip},
+ vrf => $stat->{vrf_name},
+ as => $stat->{remote_as},
+ node => $stat->{node},
+ };
+ push @$all_val, {
+ type => TSDS_PEER_TYPE,
+ time => $time,
+ interval => VRF_STATS_INTERVAL,
+ values => $peer_data,
+ meta => $peer_metadata,
+ };
+
+ # Update previous stat to current stat; On the next iteration
+ # this stat will be the previous.
+ $self->{previous_peer}->{$stat->{node}}->{$stat->{vrf_name}}->{$stat->{remote_ip}} = $stat;
+
+ eval {
+ $self->{logger}->debug("Updating VRF $stat->{vrf_name} neighbor $stat->{remote_ip} with state $peer_data->{state}.");
+ my $q = "
+ update vrf_ep_peer set operational_state=? where peer_ip like ? and vrf_ep_id in (
+ select vrf_ep_id from vrf_ep where vrf_id=?
+ )
+ ";
+ $self->{db}->execute_query(
+ $q,
+ [ $peer_data->{state}, "$stat->{remote_ip}/%", $stat->{vrf_id} ]
+ );
+ };
+ if ($@) {
+ $self->{logger}->warn("Couldn't update VRF $stat->{vrf_name} neighbor with state $peer_data->{state}: $@");
+ }
+
+ if (@$all_val >= MAX_TSDS_MESSAGES || @$stats == 0) {
+ eval {
+ my $tsds_res = $self->{tsds}->add_data(data => encode_json($all_val));
+ if (!defined $tsds_res) {
+ die $self->{tsds}->get_error;
+ }
+ if (defined $tsds_res->{error}) {
+ die $tsds_res->{error_text};
+ }
+ };
+ if ($@) {
+ $self->{logger}->error("Error submitting statistics to TSDS: $@");
+ }
+ $all_val = [];
+ }
+ }
+}
+
+
+=head2 stop
+
+=cut
+sub stop {
+ my $self = shift;
+ $self->{logger}->info('Stopping OESS::NSO::Discovery.');
+ $self->{dispatcher}->stop_consuming;
+}
+
+1;
diff --git a/perl-lib/OESS/lib/OESS/NSO/FWDCTL.pm b/perl-lib/OESS/lib/OESS/NSO/FWDCTL.pm
new file mode 100644
index 000000000..b1f4e1738
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/FWDCTL.pm
@@ -0,0 +1,766 @@
+package OESS::NSO::FWDCTL;
+
+use AnyEvent;
+use Data::Dumper;
+use GRNOC::RabbitMQ::Method;
+use GRNOC::WebService::Regex;
+use HTTP::Request::Common;
+use JSON;
+use Log::Log4perl;
+use LWP::UserAgent;
+use XML::LibXML;
+
+use OESS::Config;
+use OESS::DB;
+use OESS::DB::Circuit;
+use OESS::DB::Node;
+use OESS::DB::VRF;
+use OESS::L2Circuit;
+use OESS::Node;
+use OESS::NSO::Client;
+use OESS::RabbitMQ::Dispatcher;
+use OESS::VRF;
+
+use constant FWDCTL_WAITING => 2;
+use constant FWDCTL_SUCCESS => 1;
+use constant FWDCTL_FAILURE => 0;
+use constant FWDCTL_UNKNOWN => 3;
+use constant FWDCTL_BLOCKED => 4;
+
+use constant PENDING_DIFF_NONE => 0;
+use constant PENDING_DIFF => 1;
+use constant PENDING_DIFF_ERROR => 2;
+use constant PENDING_DIFF_APPROVED => 3;
+
+=head1 OESS::NSO::FWDCTL
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = {
+ connection_cache => undef, # OESS::NSO::ConnectionCache
+ config => '/etc/oess/database.xml',
+ config_obj => undef, # OESS::Config
+ db => undef, # OESS::DB
+ nso => undef, # OESS::NSO::Client or OESS::NSO::ClientStub
+ logger => Log::Log4perl->get_logger('OESS.NSO.FWDCTL'),
+ @_
+ };
+ my $self = bless $args, $class;
+
+ if (!defined $self->{config_obj}) {
+ $self->{config_obj} = new OESS::Config(config_filename => $self->{config_filename});
+ }
+
+ $self->{pending_diff} = {};
+ $self->{nodes} = {};
+
+ return $self;
+}
+
+=head2 addVlan
+
+=cut
+sub addVlan {
+ my $self = shift;
+ my $args = {
+ circuit_id => undef,
+ @_
+ };
+
+ my $conn = new OESS::L2Circuit(
+ db => $self->{db},
+ circuit_id => $args->{circuit_id}
+ );
+ $conn->load_endpoints;
+
+ my $err = $self->{nso}->create_l2connection($conn);
+ return $err if (defined $err);
+
+ $self->{connection_cache}->add_connection($conn, 'l2');
+ return;
+}
+
+=head2 deleteVlan
+
+=cut
+sub deleteVlan {
+ my $self = shift;
+ my $args = {
+ circuit_id => undef,
+ @_
+ };
+
+ my $conn = new OESS::L2Circuit(
+ db => $self->{db},
+ circuit_id => $args->{circuit_id}
+ );
+ return "Couldn't find l3connection $args->{vrf_id}." if !defined $conn;
+ $conn->load_endpoints;
+
+ my $err = $self->{nso}->delete_l2connection($args->{circuit_id});
+ return $err if (defined $err);
+
+ $self->{connection_cache}->remove_connection($conn, 'l2');
+ return;
+}
+
+=head2 modifyVlan
+
+=cut
+sub modifyVlan {
+ my $self = shift;
+ my $args = {
+ pending => undef,
+ @_
+ };
+
+ my $pending_hash = decode_json($args->{pending});
+ my $pending_conn = new OESS::L2Circuit(db => $self->{db}, model => $pending_hash);
+
+ my $err = $self->{nso}->edit_l2connection($pending_conn);
+ return $err if (defined $err);
+
+ $self->{connection_cache}->add_connection($pending_conn, 'l2');
+ return;
+}
+
+=head2 addVrf
+
+=cut
+sub addVrf {
+ my $self = shift;
+ my $args = {
+ vrf_id => undef,
+ @_
+ };
+
+ my $conn = new OESS::VRF(
+ db => $self->{db},
+ vrf_id => $args->{vrf_id}
+ );
+ return "Couldn't find l3connection $args->{vrf_id}." if !defined $conn;
+
+ $conn->load_endpoints;
+ foreach my $ep (@{$conn->endpoints}) {
+ $ep->load_peers;
+ }
+
+ my $err = $self->{nso}->create_l3connection($conn);
+ return $err if (defined $err);
+
+ $self->{connection_cache}->add_connection($conn, 'l3');
+ return;
+}
+
+=head2 deleteVrf
+
+=cut
+sub deleteVrf {
+ my $self = shift;
+ my $args = {
+ vrf_id => undef,
+ @_
+ };
+
+ my $conn = new OESS::VRF(
+ db => $self->{db},
+ vrf_id => $args->{vrf_id}
+ );
+ return "Couldn't find l3connection $args->{vrf_id}." if !defined $conn;
+ $conn->load_endpoints;
+
+ my $err = $self->{nso}->delete_l3connection($args->{vrf_id});
+ return $err if (defined $err);
+
+ $self->{connection_cache}->remove_connection($conn, 'l3');
+ return;
+}
+
+=head2 modifyVrf
+
+=cut
+sub modifyVrf {
+ my $self = shift;
+ my $args = {
+ pending => undef,
+ @_
+ };
+
+ my $pending_hash = decode_json($args->{pending});
+ my $pending_conn = new OESS::VRF(db => $self->{db}, model => $pending_hash);
+ $pending_conn->{endpoints} = [];
+ foreach my $pending_ep_hash (@{$pending_hash->{endpoints}}) {
+ my $pending_ep = new OESS::Endpoint(db => $self->{db}, model => $pending_ep_hash);
+
+ $pending_ep->{peers} = [];
+ foreach my $pending_peer_hash (@{$pending_ep_hash->{peers}}) {
+ push @{$pending_ep->{peers}}, new OESS::Peer(db => $self->{db}, model => $pending_peer_hash);
+ }
+ push @{$pending_conn->{endpoints}}, $pending_ep;
+ }
+
+ my $err = $self->{nso}->edit_l3connection($pending_conn);
+ return $err if (defined $err);
+
+ $self->{connection_cache}->add_connection($pending_conn, 'l3');
+ return;
+}
+
+=head2 diff
+
+diff reads all connections from cache, loads all connections from nso,
+determines if a configuration change within nso is required, and if so, make
+the change.
+
+In the case of a large change (effects > N connections), the diff is put
+into a pending state. Diff states are tracked on a per-node basis.
+
+=cut
+sub diff {
+ my $self = shift;
+
+ my ($raw_l2connections, $err) = $self->{nso}->get_l2connections();
+ return $err if defined $err;
+
+ # After a connection has been sync'd to NSO we remove it from our hash of
+ # nso connections. Any connections left in this hash after syncing are not
+ # known by OESS and should be removed.
+ my $nso_l2connections = {};
+ foreach my $conn (@{$raw_l2connections}) {
+ $nso_l2connections->{$conn->{connection_id}} = $conn;
+ }
+
+ my ($raw_l3connections, $err) = $self->{nso}->get_l3connections();
+ return $err if defined $err;
+
+ my $nso_l3connections = {};
+ foreach my $conn (@{$raw_l3connections}) {
+ $nso_l3connections->{$conn->{connection_id}} = $conn;
+ }
+
+ my $network_diff = {};
+ my $changes = [];
+
+ # Connections are stored in-memory multiple times under each node they're
+ # associed with. Keep a record of connections as they're sync'd to prevent a
+ # connection from being sync'd more than once.
+ my $syncd_connections = {};
+
+ # Needed to ensure diff state may be set to PENDING_DIFF_NONE after approval
+ my $all_nodes = OESS::DB::Node::fetch_all(db => $self->{db}, controller => 'nso');
+ foreach my $node (@$all_nodes) {
+ $network_diff->{$node->{name}} = "";
+ }
+
+ foreach my $node_hash (@$all_nodes) {
+ my $node_id = $node_hash->{node_id};
+
+ foreach my $conn (@{$self->{connection_cache}->get_connections_by_node($node_id, 'l2')}) {
+ # Skip connections if they're already sync'd.
+ next if defined $syncd_connections->{$conn->circuit_id};
+ $syncd_connections->{$conn->circuit_id} = 1;
+
+ # Compare cached connection against NSO connection. If no difference
+ # continue with next connection, otherwise update NSO to align with
+ # cache.
+ my $diff_required = 0;
+
+ my $diff = $conn->nso_diff($nso_l2connections->{$conn->circuit_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ if (!defined $nso_l2connections->{$conn->circuit_id}) {
+ push(@$changes, { type => 'create-l2connection', value => $conn }) if $diff_required;
+ next;
+ }
+
+ push(@$changes, { type => 'edit-l2connection', value => $conn }) if $diff_required;
+ delete $nso_l2connections->{$conn->circuit_id};
+ }
+
+ foreach my $conn (@{$self->{connection_cache}->get_connections_by_node($node_id, 'l3')}) {
+ # Skip connections if they're already sync'd.
+ next if defined $syncd_connections->{$conn->vrf_id};
+ $syncd_connections->{$conn->vrf_id} = 1;
+
+ # Compare cached connection against NSO connection. If no difference
+ # continue with next connection, otherwise update NSO to align with
+ # cache.
+ my $diff_required = 0;
+
+ my $diff = $conn->nso_diff($nso_l3connections->{$conn->vrf_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ if (!defined $nso_l3connections->{$conn->vrf_id}) {
+ push(@$changes, { type => 'create-l3connection', value => $conn }) if $diff_required;
+ next;
+ }
+
+ push(@$changes, { type => 'edit-l3connection', value => $conn }) if $diff_required;
+ delete $nso_l3connections->{$conn->vrf_id};
+ }
+ }
+
+ my $empty_conn = new OESS::L2Circuit(db => $self->{db}, model => {});
+ foreach my $conn_id (keys %{$nso_l2connections}) {
+ my $diff = $empty_conn->nso_diff($nso_l2connections->{$conn_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ push @$changes, { type => 'delete-l2connection', value => $nso_l2connections->{$conn_id} };
+ }
+
+ my $empty_conn = new OESS::VRF(db => $self->{db}, model => {});
+ foreach my $conn_id (keys %{$nso_l3connections}) {
+ my $diff = $empty_conn->nso_diff($nso_l3connections->{$conn_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ push @$changes, { type => 'delete-l3connection', value => $nso_l3connections->{$conn_id} };
+ }
+
+ # TODO Retain manually approved diff state between diffs
+
+ # If the database asserts there is no diff pending but memory
+ # disagrees, then the pending state was modified by an admin. The
+ # pending diff may now proceed.
+ foreach my $node_name (keys %$network_diff) {
+ my $node = new OESS::Node(db => $self->{db}, name => $node_name);
+ my $diff_len = length $network_diff->{$node_name};
+
+ if ($diff_len < 30) {
+ $self->{pending_diff}->{$node_name} = PENDING_DIFF_NONE;
+ $node->pending_diff(PENDING_DIFF_NONE);
+ $node->update;
+ $self->{logger}->info("Applying network diff. No approved required for $node_name.");
+ } else {
+ if ($self->{pending_diff}->{$node_name} == PENDING_DIFF_NONE) {
+ $self->{pending_diff}->{$node_name} = PENDING_DIFF;
+ $node->pending_diff(PENDING_DIFF);
+ $node->update;
+ $self->{logger}->info("Not applying network diff. Manual approval required for $node_name.");
+ }
+
+ if ($self->{pending_diff}->{$node_name} == PENDING_DIFF && $node->pending_diff == PENDING_DIFF_NONE) {
+ $self->{pending_diff}->{$node_name} = PENDING_DIFF_APPROVED;
+ $self->{logger}->info("Applying network diff. Manual approval granted for $node_name.");
+ }
+ }
+
+ $self->{logger}->debug("Diff for $node_name with length of $diff_len:\n$network_diff->{$node_name}");
+ }
+ $self->{logger}->debug('Changes: ' . Dumper($changes));
+
+ foreach my $change (@$changes) {
+ if ($change->{type} eq 'create-l2connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->endpoints}) {
+ if ($self->{pending_diff}->{$ep->node} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ $self->{logger}->info("Not applying l2connection $conn->{circuit_id}. Manual approval required.");
+ next;
+ }
+
+ my $err = $self->{nso}->create_l2connection($conn);
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ $self->{logger}->info("Applied l2connection $conn->{circuit_id}.");
+ }
+ elsif ($change->{type} eq 'edit-l2connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->endpoints}) {
+ if ($self->{pending_diff}->{$ep->node} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ warn "Not syncing l2connection $conn->{circuit_id}. Diff approval required.";
+ next;
+ }
+
+ my $err = $self->{nso}->edit_l2connection($conn);
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ $self->{logger}->info("Sync'd l2connection $conn->{circuit_id}.");
+ }
+ elsif ($change->{type} eq 'delete-l2connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->{endpoint}}) {
+ if ($self->{pending_diff}->{$ep->{device}} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ warn "Not syncing l2connection $conn->{circuit_id}. Diff approval required.";
+ next;
+ }
+
+ my $err = $self->{nso}->delete_l2connection($conn->{connection_id});
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ }
+ elsif ($change->{type} eq 'create-l3connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->endpoints}) {
+ if ($self->{pending_diff}->{$ep->node} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ warn "Not syncing l3connection $conn->{vrf_id}. Diff approval required.";
+ next;
+ }
+
+ my $err = $self->{nso}->create_l3connection($conn);
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ $self->{logger}->info("Sync'd l3connection $conn->{vrf_id}.");
+ }
+ elsif ($change->{type} eq 'edit-l3connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->endpoints}) {
+ if ($self->{pending_diff}->{$ep->node} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ warn "Not syncing l3connection $conn->{vrf_id}. Diff approval required.";
+ next;
+ }
+
+ my $err = $self->{nso}->edit_l3connection($conn);
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ $self->{logger}->info("Sync'd l3connection $conn->{vrf_id}.");
+ }
+ elsif ($change->{type} eq 'delete-l3connection') {
+ my $conn = $change->{value};
+
+ # If conn endpoint on node with a blocked diff skip
+ my $diff_approval_required = 0;
+ foreach my $ep (@{$conn->{endpoint}}) {
+ if ($self->{pending_diff}->{$ep->{device}} == PENDING_DIFF) {
+ $diff_approval_required = 1;
+ last;
+ }
+ }
+ if ($diff_approval_required) {
+ warn "Not syncing l3connection $conn->{vrf_id}. Diff approval required.";
+ next;
+ }
+
+ my $err = $self->{nso}->delete_l3connection($conn->{connection_id});
+ if (defined $err) {
+ $self->{logger}->error($err);
+ }
+ }
+ else {
+ warn 'no idea what happened here';
+ }
+ }
+
+ return;
+}
+
+=head2 get_diff_text
+
+=cut
+sub get_diff_text {
+ my $self = shift;
+ my $args = {
+ node_id => undef,
+ node_name => undef,
+ @_
+ };
+
+ my $node_id = $args->{node_id};
+ my $node_name = "";
+
+ my ($l2_connections, $err1) = $self->{nso}->get_l2connections();
+ if (defined $err1) {
+ return (undef, $err1);
+ }
+ my ($l3_connections, $err2) = $self->{nso}->get_l3connections();
+ if (defined $err2) {
+ return (undef, $err2);
+ }
+
+ # After a connection has been sync'd to NSO we remove it from our hash of
+ # nso connections. Any connections left in this hash after syncing are not
+ # known by OESS and should be removed.
+ my $nso_l2connections = {};
+ foreach my $conn (@{$l2_connections}) {
+ $nso_l2connections->{$conn->{connection_id}} = $conn;
+ }
+ my $nso_l3connections = {};
+ foreach my $conn (@{$l3_connections}) {
+ $nso_l3connections->{$conn->{connection_id}} = $conn;
+ }
+
+ my $network_diff = {};
+ my $changes = [];
+
+ # Connections are stored in-memory multiple times under each node
+ # they're associed with. Keep a record of connections as they're
+ # sync'd to prevent a connection from being sync'd more than once.
+ my $syncd_l2connections = {};
+ my $syncd_l3connections = {};
+
+
+ # Ensure that requested node is represented in hash and that name
+ # is looked up. This is needed to ensure diff state may be set to
+ # PENDING_DIFF_NONE after approval
+ my $all_nodes = OESS::DB::Node::fetch_all(db => $self->{db}, controller => 'nso');
+ foreach my $node (@$all_nodes) {
+ if ($node->{node_id} eq $node_id) {
+ $node_name = $node->{name};
+ }
+ $network_diff->{$node->{name}} = "";
+ }
+
+ foreach my $node (@$all_nodes) {
+ my $node_id = $node->{node_id};
+
+ foreach my $conn (@{$self->{connection_cache}->get_connections_by_node($node_id, 'l2')}) {
+
+ # Skip connections if they're already sync'd.
+ next if defined $syncd_l2connections->{$conn->circuit_id};
+ $syncd_l2connections->{$conn->circuit_id} = 1;
+
+ # Compare cached connection against NSO connection. If no
+ # difference continue with next connection, otherwise
+ # update NSO to align with cache.
+ my $diff_required = 0;
+
+ my $diff = $conn->nso_diff($nso_l2connections->{$conn->circuit_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ if (!defined $nso_l2connections->{$conn->circuit_id}) {
+ push(@$changes, { type => 'create-l2connection', value => $conn }) if $diff_required;
+ next;
+ }
+
+ push(@$changes, { type => 'edit-l2connection', value => $conn->circuit_id }) if $diff_required;
+ delete $nso_l2connections->{$conn->circuit_id};
+ }
+
+ foreach my $conn (@{$self->{connection_cache}->get_connections_by_node($node_id, 'l3')}) {
+
+ # Skip connections if they're already sync'd.
+ next if defined $syncd_l3connections->{$conn->vrf_id};
+ $syncd_l3connections->{$conn->vrf_id} = 1;
+
+ # Compare cached connection against NSO connection. If no difference
+ # continue with next connection, otherwise update NSO to align with
+ # cache.
+ my $diff_required = 0;
+
+ my $diff = $conn->nso_diff($nso_l3connections->{$conn->vrf_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ if (!defined $nso_l3connections->{$conn->vrf_id}) {
+ push(@$changes, { type => 'create-l3connection', value => $conn }) if $diff_required;
+ next;
+ }
+
+ push(@$changes, { type => 'edit-l3connection', value => $conn->vrf_id }) if $diff_required;
+ delete $nso_l3connections->{$conn->vrf_id};
+ }
+ }
+
+ my $empty_conn1 = new OESS::L2Circuit(db => $self->{db}, model => {});
+ foreach my $conn_id (keys %{$nso_l2connections}) {
+ my $diff = $empty_conn1->nso_diff($nso_l2connections->{$conn_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ push @$changes, { type => 'delete-l2connection', value => $conn_id };
+ }
+
+ my $empty_conn2 = new OESS::VRF(db => $self->{db}, model => {});
+ foreach my $conn_id (keys %{$nso_l3connections}) {
+ my $diff = $empty_conn2->nso_diff($nso_l3connections->{$conn_id});
+ foreach my $node (keys %$diff) {
+ next if $diff->{$node} eq "";
+
+ $diff_required = 1;
+ $network_diff->{$node} .= $diff->{$node};
+ }
+
+ push @$changes, { type => 'delete-l2connection', value => $conn_id };
+ }
+
+ if (defined $args->{node_name}) {
+ $node_name = $args->{node_name};
+ }
+
+ $self->{logger}->debug('Requested diff text: ' . $network_diff->{$node_name});
+ return ($network_diff->{$node_name}, undef);
+}
+
+=head2 new_switch
+
+=cut
+sub new_switch {
+ my $self = shift;
+ my $args = {
+ node_id => undef,
+ @_
+ };
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{'success_callback'};
+ my $error = $method->{'error_callback'};
+
+ if (defined $self->{nodes}->{$args->{node_id}}) {
+ $self->{logger}->warn("Node $args->{node_id} already registered with FWDCTL.");
+ return;
+ }
+
+ my $node = OESS::DB::Node::fetch(db => $self->{db}, node_id => $args->{node_id});
+ if (!defined $node) {
+ return "Couldn't lookup node $args->{node_id}. FWDCTL will not properly provision on this node.";
+ }
+ $self->{nodes}->{$args->{node_id}} = $node;
+
+ warn "Switch $node->{name} registered with FWDCTL.";
+ $self->{logger}->info("Switch $node->{name} registered with FWDCTL.");
+
+ # Make first invocation of polling subroutines
+ $self->diff;
+ return;
+}
+
+=head2 update_cache
+
+update_cache reads all connections from the database and loads them
+into an in-memory cache.
+
+=cut
+sub update_cache {
+ my $self = shift;
+
+ $self->{connection_cache}->clear;
+
+ my $l2connections = OESS::DB::Circuit::fetch_circuits(
+ db => $self->{db},
+ state => 'active'
+ );
+ if (!defined $l2connections) {
+ $self->{logger}->error("Couldn't load l2connections in update_cache.");
+ return "Couldn't load l2connections in update_cache.";
+ }
+
+ foreach my $conn (@$l2connections) {
+ my $obj = new OESS::L2Circuit(db => $self->{db}, model => $conn);
+ $obj->load_endpoints;
+ $self->{connection_cache}->add_connection($obj, 'l2');
+ }
+
+ my $l3connection_ids = OESS::DB::VRF::get_vrfs(
+ db => $self->{db},
+ state => 'active'
+ );
+ if (!defined $l3connection_ids) {
+ $self->{logger}->error("Couldn't load l3connections in update_cache.");
+ return "Couldn't load l3connections in update_cache.";
+ }
+
+ foreach my $conn (@$l3connection_ids) {
+ my $obj = new OESS::VRF(db => $self->{db}, vrf_id => $conn->{vrf_id});
+ $obj->load_endpoints;
+
+ foreach my $ep (@{$obj->endpoints}) {
+ $ep->load_peers;
+ }
+ $self->{connection_cache}->add_connection($obj, 'l3');
+ }
+ return;
+}
+
+=head2 update_nodes
+
+update_nodes reads all nodes from the database and loads them into an
+in-memory cache similar to update_cache.
+
+=cut
+sub update_nodes {
+ my $self = shift;
+
+ my $nodes = OESS::DB::Node::fetch_all(db => $self->{db}, controller => 'nso');
+ if (!defined $nodes) {
+ return "Couldn't lookup nodes. FWDCTL will not provision on any existing nodes.";
+ }
+ foreach my $node (@$nodes) {
+ $self->{nodes}->{$node->{node_id}} = $node;
+ }
+
+ return;
+}
+
+1;
diff --git a/perl-lib/OESS/lib/OESS/NSO/FWDCTLService.pm b/perl-lib/OESS/lib/OESS/NSO/FWDCTLService.pm
new file mode 100644
index 000000000..3cf789040
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/NSO/FWDCTLService.pm
@@ -0,0 +1,526 @@
+package OESS::NSO::FWDCTLService;
+
+use AnyEvent;
+use Data::Dumper;
+use GRNOC::RabbitMQ::Method;
+use GRNOC::WebService::Regex;
+use HTTP::Request::Common;
+use JSON;
+use Log::Log4perl;
+use LWP::UserAgent;
+use XML::LibXML;
+
+use OESS::Config;
+use OESS::DB;
+use OESS::DB::Node;
+use OESS::L2Circuit;
+use OESS::Node;
+use OESS::NSO::Client;
+use OESS::NSO::ConnectionCache;
+use OESS::NSO::FWDCTL;
+use OESS::RabbitMQ::Dispatcher;
+use OESS::VRF;
+
+use constant FWDCTL_WAITING => 2;
+use constant FWDCTL_SUCCESS => 1;
+use constant FWDCTL_FAILURE => 0;
+use constant FWDCTL_UNKNOWN => 3;
+use constant FWDCTL_BLOCKED => 4;
+
+
+=head1 OESS::NSO::FWDCTLService
+
+=cut
+
+=head2 new
+
+=cut
+sub new {
+ my $class = shift;
+ my $args = {
+ config => '/etc/oess/database.xml',
+ config_obj => undef,
+ logger => Log::Log4perl->get_logger('OESS.NSO.FWDCTL'),
+ @_
+ };
+ my $self = bless $args, $class;
+
+ if (!defined $self->{config_obj}) {
+ $self->{config_obj} = new OESS::Config(config_filename => $self->{config_filename});
+ }
+
+ $self->{db} = new OESS::DB(config => $self->{config_obj}->filename);
+ $self->{nso} = new OESS::NSO::Client(config_obj => $self->{config_obj});
+
+ my $cache = new OESS::NSO::ConnectionCache();
+ $self->{fwdctl} = new OESS::NSO::FWDCTL(
+ connection_cache => $cache,
+ config_obj => $self->{config_obj},
+ db => $self->{db},
+ nso => $self->{nso}
+ );
+
+ # When this process receives sigterm send an event to notify all
+ # children to exit cleanly.
+ $SIG{TERM} = sub {
+ $self->stop;
+ };
+
+ return $self;
+}
+
+=head2 start
+
+start configures polling timers, loads in-memory cache of l2 and l3
+connections, and sets up a rabbitmq dispatcher for RCP calls into FWDCTL.
+
+=cut
+sub start {
+ my $self = shift;
+
+ my $node_err = $self->{fwdctl}->update_nodes;
+ if (defined $node_err) {
+ warn $node_err;
+ $self->{logger}->error($node_err);
+ }
+
+ my $cache_err = $self->{fwdctl}->update_cache;
+ if (defined $cache_err) {
+ warn $cache_err;
+ $self->{logger}->error($cache_err);
+ }
+
+ # Setup polling subroutines
+ $self->{connection_timer} = AnyEvent->timer(
+ after => 5,
+ interval => 30,
+ cb => sub { $self->diff(@_); }
+ );
+
+ $self->{dispatcher} = new OESS::RabbitMQ::Dispatcher(
+ queue => 'NSO-FWDCTL',
+ topic => 'NSO.FWDCTL.RPC'
+ );
+
+ my $add_vlan = GRNOC::RabbitMQ::Method->new(
+ name => "addVlan",
+ async => 1,
+ callback => sub { $self->addVlan(@_) },
+ description => "addVlan provisions a l2 connection"
+ );
+ $add_vlan->add_input_parameter(
+ name => "circuit_id",
+ description => "Id of the l2 connection to add",
+ required => 1,
+ attern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $self->{dispatcher}->register_method($add_vlan);
+
+ my $delete_vlan = GRNOC::RabbitMQ::Method->new(
+ name => "deleteVlan",
+ async => 1,
+ callback => sub { $self->deleteVlan(@_) },
+ description => "deleteVlan removes a l2 connection"
+ );
+ $delete_vlan->add_input_parameter(
+ name => "circuit_id",
+ description => "Id of the l2 connection to delete",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $self->{dispatcher}->register_method($delete_vlan);
+
+ my $modify_vlan = GRNOC::RabbitMQ::Method->new(
+ name => "modifyVlan",
+ async => 1,
+ callback => sub { $self->modifyVlan(@_) },
+ description => "modifyVlan modifies an existing l2 connection"
+ );
+ $modify_vlan->add_input_parameter(
+ name => "circuit_id",
+ description => "Id of l2 connection to be modified.",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $modify_vlan->add_input_parameter(
+ name => "previous",
+ description => "Previous version of the modified l2 connection.",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::TEXT
+ );
+ $modify_vlan->add_input_parameter(
+ name => "pending",
+ description => "Pending version of the modified l2 connection.",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::TEXT
+ );
+ $self->{dispatcher}->register_method($modify_vlan);
+
+ my $add_vrf = GRNOC::RabbitMQ::Method->new(
+ name => "addVrf",
+ async => 1,
+ callback => sub { $self->addVrf(@_) },
+ description => "addVrf provisions a l3 connection"
+ );
+ $add_vrf->add_input_parameter(
+ name => "vrf_id",
+ description => "Id of the l3 connection to add",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $self->{dispatcher}->register_method($add_vrf);
+
+ my $delete_vrf = GRNOC::RabbitMQ::Method->new(
+ name => "delVrf",
+ async => 1,
+ callback => sub { $self->deleteVrf(@_) },
+ description => "delVrf removes a l3 connection"
+ );
+ $delete_vrf->add_input_parameter(
+ name => "vrf_id",
+ description => "Id of the l3 connection to delete",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $self->{dispatcher}->register_method($delete_vrf);
+
+ my $modify_vrf = GRNOC::RabbitMQ::Method->new(
+ name => "modifyVrf",
+ async => 1,
+ callback => sub { $self->modifyVrf(@_) },
+ description => "modifyVrf modifies an existing l3 connection"
+ );
+ $modify_vrf->add_input_parameter(
+ name => "vrf_id",
+ description => "Id of l3 connection to be modified",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $modify_vrf->add_input_parameter(
+ name => "previous",
+ description => "Previous version of the modified l3 connection",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::TEXT
+ );
+ $modify_vrf->add_input_parameter(
+ name => "pending",
+ description => "Pending version of the modified l3 connection",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::TEXT
+ );
+ $self->{dispatcher}->register_method($modify_vrf);
+
+ # NOTE It's not expected that any children processes will exist in this
+ # version of FWDCTL. Result is hardcoded.
+ my $check_child_status = GRNOC::RabbitMQ::Method->new(
+ name => "check_child_status",
+ description => "check_child_status returns an event id which will return the final status of all children",
+ callback => sub {
+ my $method = shift;
+ return { status => 1, event_id => 1 };
+ }
+ );
+ $self->{dispatcher}->register_method($check_child_status);
+
+ # NOTE It's not expected that any children processes will exist in this
+ # version of FWDCTL. Result is hardcoded.
+ my $get_event_status = GRNOC::RabbitMQ::Method->new(
+ name => "get_event_status",
+ description => "get_event_status returns the current status of the event",
+ callback => sub {
+ my $method = shift;
+ return { status => 1 };
+ }
+ );
+ $get_event_status->add_input_parameter(
+ name => "event_id",
+ description => "the event id to fetch the current state of",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::NAME_ID
+ );
+ $self->{dispatcher}->register_method($get_event_status);
+
+ # TODO It's not clear if both is_online and echo are required; Please
+ # investigate.
+ my $echo = GRNOC::RabbitMQ::Method->new(
+ name => "echo",
+ description => "echo always returns 1",
+ callback => sub {
+ my $method = shift;
+ return { status => 1 };
+ }
+ );
+ $self->{dispatcher}->register_method($echo);
+
+ my $get_diff_text = GRNOC::RabbitMQ::Method->new(
+ name => 'get_diff_text',
+ async => 1,
+ callback => sub { $self->get_diff_text(@_); },
+ description => "Returns a human readable diff for node_id"
+ );
+ $get_diff_text->add_input_parameter(
+ name => "node_id",
+ description => "The node ID to lookup",
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::INTEGER
+ );
+ $self->{dispatcher}->register_method($get_diff_text);
+
+ # TODO It's not clear if both is_online and echo are required; Please
+ # investigate.
+ my $is_online = new GRNOC::RabbitMQ::Method(
+ name => "is_online",
+ description => 'is_online returns 1 if this service is available',
+ async => 1,
+ callback => sub {
+ my $method = shift;
+ return $method->{success_callback}({ successful => 1 });
+ }
+ );
+ $self->{dispatcher}->register_method($is_online);
+
+ my $new_switch = new GRNOC::RabbitMQ::Method(
+ name => 'new_switch',
+ description => 'new_switch adds a new switch to FWDCTL',
+ async => 1,
+ callback => sub { $self->new_switch(@_); }
+ );
+ $new_switch->add_input_parameter(
+ name => 'node_id',
+ description => 'Id of the new node',
+ required => 1,
+ pattern => $GRNOC::WebService::Regex::NUMBER_ID
+ );
+ $self->{dispatcher}->register_method($new_switch);
+
+ my $update_cache = GRNOC::RabbitMQ::Method->new(
+ name => 'update_cache',
+ async => 1,
+ callback => sub { $self->update_cache(@_) },
+ description => "Rewrites the connection cache file"
+ );
+ $self->{dispatcher}->register_method($update_cache);
+
+ return 1;
+}
+
+=head2 stop
+
+=cut
+sub stop {
+ my $self = shift;
+ $self->{logger}->info('Stopping OESS::NSO::FWDCTL.');
+ $self->{dispatcher}->stop_consuming;
+}
+
+=head2 addVlan
+
+=cut
+sub addVlan {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->addVlan(
+ circuit_id => $params->{circuit_id}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 deleteVlan
+
+=cut
+sub deleteVlan {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->deleteVlan(
+ circuit_id => $params->{circuit_id}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 modifyVlan
+
+=cut
+sub modifyVlan {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->modifyVlan(
+ pending => $params->{pending}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 addVrf
+
+=cut
+sub addVrf {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->addVrf(
+ vrf_id => $params->{vrf_id}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 deleteVrf
+
+=cut
+sub deleteVrf {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->deleteVrf(
+ vrf_id => $params->{vrf_id}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 modifyVrf
+
+=cut
+sub modifyVrf {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->modifyVrf(
+ pending => $params->{pending}{value}
+ );
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => FWDCTL_SUCCESS });
+}
+
+=head2 diff
+
+diff reads all connections from cache, loads all connections from nso,
+determines if a configuration change within nso is required, and if so, make
+the change.
+
+In the case of a large change (effects > N connections), the diff is put
+into a pending state. Diff states are tracked on a per-node basis.
+
+=cut
+sub diff {
+ my $self = shift;
+
+ my $err = $self->{fwdctl}->diff;
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return;
+ }
+ return 1;
+}
+
+=head2 get_diff_text
+
+=cut
+sub get_diff_text {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $node_id = $params->{node_id}{value};
+ my $node_name = "";
+
+ my ($diff, $err) = $self->{fwdctl}->get_diff_text(node_id => $node_id);
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success($diff);
+}
+
+=head2 new_switch
+
+=cut
+sub new_switch {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{'success_callback'};
+ my $error = $method->{'error_callback'};
+
+ my $err = $self->{fwdctl}->new_switch(node_id => $params->{node_id}{value});
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => 1 });
+}
+
+=head2 update_cache
+
+update_cache reads all connections from the database and loads them
+into an in-memory cache.
+
+=cut
+sub update_cache {
+ my $self = shift;
+ my $method = shift;
+ my $params = shift;
+
+ my $success = $method->{success_callback};
+ my $error = $method->{error_callback};
+
+ my $err = $self->{fwdctl}->update_cache;
+ if (defined $err) {
+ $self->{logger}->error($err);
+ return &$error($err);
+ }
+ return &$success({ status => 1 });
+}
+
+1;
diff --git a/perl-lib/OESS/lib/OESS/Node.pm b/perl-lib/OESS/lib/OESS/Node.pm
index 2bd15de17..0934769fa 100644
--- a/perl-lib/OESS/lib/OESS/Node.pm
+++ b/perl-lib/OESS/lib/OESS/Node.pm
@@ -14,21 +14,18 @@ sub new{
my $that = shift;
my $class = ref($that) || $that;
- my $logger = Log::Log4perl->get_logger("OESS.Node");
-
my %args = (
+ db => undef,
+ logger => Log::Log4perl->get_logger("OESS.Node"),
+ name => undef,
node_id => undef,
- db => undef,
@_
- );
-
+ );
my $self = \%args;
bless $self, $class;
- $self->{'logger'} = $logger;
-
- if(!defined($self->{'db'})){
+ if (!defined $self->{db}) {
$self->{'logger'}->error("No Database Object specified");
return;
}
@@ -41,27 +38,53 @@ sub new{
=head2 from_hash
=cut
-sub from_hash{
+sub from_hash {
my $self = shift;
my $hash = shift;
- $self->{'node_id'} = $hash->{'node_id'};
- $self->{'name'} = $hash->{'name'};
- $self->{'latitude'} = $hash->{'latitude'};
- $self->{'longitude'} = $hash->{'longitude'};
-
+ $self->{node_id} = $hash->{node_id};
+ $self->{controller} = $hash->{controller};
+ $self->{name} = $hash->{name};
+ $self->{latitude} = $hash->{latitude};
+ $self->{longitude} = $hash->{longitude};
+ $self->{vlan_tag_range} = $hash->{vlan_tag_range};
+ $self->{operational_state_mpls} = $hash->{operational_state_mpls} || 'up';
+ $self->{pending_diff} = $hash->{pending_diff} || 0;
+ $self->{admin_state} = $hash->{admin_state} || 'active';
+ $self->{short_name} = $hash->{short_name};
+ $self->{vendor} = $hash->{vendor};
+ $self->{model} = $hash->{model};
+ $self->{sw_version} = $hash->{sw_version};
+ $self->{mgmt_addr} = $hash->{mgmt_addr};
+ $self->{loopback_address} = $hash->{loopback_address};
+ $self->{tcp_port} = $self->{tcp_port} || 830;
+
+ return 1;
}
=head2 to_hash
=cut
-sub to_hash{
+sub to_hash {
my $self = shift;
- my $obj = { node_id => $self->{'node_id'},
- name => $self->{'name'},
- latitude => $self->{'latitude'},
- longitude => $self->{'longitude'}};
-
+ my $obj = {
+ node_id => $self->{'node_id'},
+ controller => $self->{'controller'},
+ name => $self->{'name'},
+ latitude => $self->{'latitude'},
+ longitude => $self->{'longitude'},
+ vlan_tag_range => $self->{vlan_tag_range},
+ operational_state_mpls => $self->{operational_state_mpls},
+ pending_diff => $self->{pending_diff},
+ admin_state => $self->{admin_state},
+ short_name => $self->{short_name},
+ vendor => $self->{vendor},
+ model => $self->{model},
+ sw_version => $self->{sw_version},
+ mgmt_addr => $self->{mgmt_addr},
+ loopback_address => $self->{loopback_address},
+ tcp_port => $self->{tcp_port}
+ };
return $obj;
}
@@ -71,30 +94,49 @@ sub to_hash{
sub _fetch_from_db{
my $self = shift;
my $db = $self->{'db'};
- my $hash = OESS::DB::Node::fetch(db => $db, node_id => $self->{'node_id'});
+ my $hash = OESS::DB::Node::fetch(
+ db => $db,
+ name => $self->{name},
+ node_id => $self->{node_id}
+ );
$self->from_hash($hash);
}
-=head2 node_id
+=head2 update
=cut
-sub node_id{
+sub update {
my $self = shift;
- return $self->{'node_id'};
+
+ if (!defined $self->{db}) {
+ $self->{'logger'}->error("Could not update Node: No database object specified.");
+ return;
+ }
+
+ my $err = OESS::DB::Node::update(
+ db => $self->{db},
+ node => $self->to_hash
+ );
+ if (defined $err) {
+ $self->{'logger'}->error("Could not update Node: $err");
+ return;
+ }
+
+ return 1;
}
-=head2 name
+=head2 node_id
=cut
-sub name{
+sub node_id {
my $self = shift;
- return $self->{'name'};
+ return $self->{'node_id'};
}
=head2 interfaces
=cut
-sub interfaces{
+sub interfaces {
my $self = shift;
my $interfaces = shift;
@@ -103,7 +145,7 @@ sub interfaces{
}else{
if(!defined($self->{'interfaces'})){
- my $interfaces = OESS::DB::Node::get_interfaces(db => $self->{'db'}, node_id => $self->{'node_id'});
+ my $interfaces = OESS::DB::Node::get_node_interfaces(db => $self->{'db'}, node_id => $self->{'node_id'});
$self->{'interfaces'} = $interfaces;
}
@@ -111,4 +153,186 @@ sub interfaces{
}
}
+=head2 controller
+
+=cut
+sub controller {
+ my $self = shift;
+ my $controller = shift;
+
+ if (defined $controller) {
+ $self->{controller} = $controller;
+ }
+ return $self->{controller};
+}
+
+=head2 latitude
+
+=cut
+sub latitude {
+ my $self = shift;
+ my $latitude = shift;
+
+ if (defined $latitude) {
+ $self->{latitude} = $latitude;
+ }
+ return $self->{latitude};
+}
+
+=head2 longitude
+
+=cut
+sub longitude {
+ my $self = shift;
+ my $longitude = shift;
+
+ if (defined $longitude) {
+ $self->{longitude} = $longitude;
+ }
+ return $self->{longitude};
+}
+
+=head2 mgmt_addr
+
+=cut
+sub mgmt_addr {
+ my $self = shift;
+ my $mgmt_addr = shift;
+
+ if (defined $mgmt_addr) {
+ $self->{mgmt_addr} = $mgmt_addr;
+ }
+ return $self->{mgmt_addr};
+}
+
+=head2 loopback_address
+
+=cut
+sub loopback_address {
+ my $self = shift;
+ my $loopback_address = shift;
+
+ if (defined $loopback_address) {
+ $self->{loopback_address} = $loopback_address;
+ }
+ return $self->{loopback_address};
+}
+
+=head2 model
+
+=cut
+sub model {
+ my $self = shift;
+ my $model = shift;
+
+ if (defined $model) {
+ $self->{model} = $model;
+ }
+ return $self->{model};
+}
+
+=head2 name
+
+=cut
+sub name {
+ my $self = shift;
+ my $name = shift;
+
+ if (defined $name) {
+ $self->{name} = $name;
+ }
+ return $self->{name};
+}
+
+=head2 pending_diff
+
+=cut
+sub pending_diff {
+ my $self = shift;
+ my $pending_diff = shift;
+
+ if (defined $pending_diff) {
+ $self->{pending_diff} = $pending_diff;
+ }
+ return $self->{pending_diff};
+}
+
+=head2 short_name
+
+=cut
+sub short_name {
+ my $self = shift;
+ my $short_name = shift;
+
+ if (defined $short_name) {
+ $self->{short_name} = $short_name;
+ }
+ return $self->{short_name};
+}
+
+=head2 sw_version
+
+=cut
+sub sw_version {
+ my $self = shift;
+ my $sw_version = shift;
+
+ if (defined $sw_version) {
+ $self->{sw_version} = $sw_version;
+ }
+ return $self->{sw_version};
+}
+
+=head2 tcp_port
+
+=cut
+sub tcp_port {
+ my $self = shift;
+ my $tcp_port = shift;
+
+ if (defined $tcp_port) {
+ $self->{tcp_port} = $tcp_port;
+ }
+ return $self->{tcp_port};
+}
+
+=head2 vendor
+
+=cut
+sub vendor {
+ my $self = shift;
+ my $vendor = shift;
+
+ if (defined $vendor) {
+ $self->{vendor} = $vendor;
+ }
+ return $self->{vendor};
+}
+
+=head2 vlan_tag_range
+
+=cut
+sub vlan_tag_range {
+ my $self = shift;
+ my $vlan_tag_range = shift;
+
+ if (defined $vlan_tag_range) {
+ $self->{vlan_tag_range} = $vlan_tag_range;
+ }
+ return $self->{vlan_tag_range};
+}
+
+=head2 operational_state_mpls
+
+=cut
+sub operational_state_mpls {
+ my $self = shift;
+ my $operational_state_mpls = shift;
+
+ if (defined $operational_state_mpls) {
+ $self->{operational_state_mpls} = $operational_state_mpls;
+ }
+ return $self->{operational_state_mpls};
+}
+
1;
diff --git a/perl-lib/OESS/lib/OESS/Peer.pm b/perl-lib/OESS/lib/OESS/Peer.pm
index f6a65ccfc..0bfefe52a 100644
--- a/perl-lib/OESS/lib/OESS/Peer.pm
+++ b/perl-lib/OESS/lib/OESS/Peer.pm
@@ -42,7 +42,7 @@ sub new{
my $class = ref($that) || $that;
my $self = {
- vrf_peer_id => undef,
+ vrf_ep_peer_id => undef,
db => undef,
model => undef,
logger => Log::Log4perl->get_logger("OESS.Peer"),
@@ -162,7 +162,11 @@ sub peer_asn{
=cut
sub md5_key{
my $self = shift;
- return $self->{'md5_key'};
+ my $md5_key = shift;
+ if (defined $md5_key) {
+ $self->{md5_key} = $md5_key;
+ }
+ return $self->{md5_key};
}
=head2 vrf_ep_id
diff --git a/perl-lib/OESS/lib/OESS/RabbitMQ/Topic.pm b/perl-lib/OESS/lib/OESS/RabbitMQ/Topic.pm
new file mode 100644
index 000000000..e83c3deea
--- /dev/null
+++ b/perl-lib/OESS/lib/OESS/RabbitMQ/Topic.pm
@@ -0,0 +1,118 @@
+package OESS::RabbitMQ::Topic;
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use Exporter qw(import);
+use Log::Log4perl;
+
+our @EXPORT = qw(discovery_topic_for_node fwdctl_topic_for_node fwdctl_topic_for_connection);
+
+=head1 OESS::RabbitMQ::Topic
+
+ use OESS::RabbitMQ::Topic qw(discovery_topic_for_node fwdctl_topic_for_node fwdctl_topic_for_connection);
+
+=cut
+
+=head2 fwdctl_topic_for_connection
+
+ my ($topic, $err) = fwdctl_topic_for_connection($conn->to_hash);
+
+fwdctl_topic_for_connection returns the topic which should be used for
+provisioning C<$conn>. The topic chosen is based on the controller
+associated with the node of each endpoint. The controller must be the
+same across all endpoints or an error is returned.
+
+=cut
+sub fwdctl_topic_for_connection {
+ my $conn = shift;
+
+ # Accessing variables directly vs using methods to allow for use
+ # of both connection objects and their hashes. This is primarily
+ # to accommodate circuit.cgi->update which has both a previous and
+ # pending hash. If the topic is different for the two then
+ # _send_update_cache needs to be called for both.
+
+ my $controller; # 'openflow','netconf','nso'
+ foreach my $ep (@{$conn->{endpoints}}) {
+ if (!defined $controller) {
+ $controller = $ep->{controller};
+ next;
+ }
+ if ($controller ne $ep->{controller}) {
+ return (undef, "Connection endpoints are not on the same controller.");
+ }
+ }
+
+ if ($controller eq 'openflow') {
+ return ('OF.FWDCTL.RPC', undef);
+ }
+ elsif ($controller eq 'netconf') {
+ return ('MPLS.FWDCTL.RPC', undef);
+ }
+ elsif ($controller eq 'nso') {
+ return ('NSO.FWDCTL.RPC', undef);
+ }
+ else {
+ return (undef, "Unexpected controller '$controller' found for connection endpoints.");
+ }
+}
+
+=head2 discovery_topic_for_node
+
+ my ($topic, $err) = discovery_topic_for_node($node);
+
+discovery_topic_for_node returns the topic which should be used for
+working with C<$node>. The topic chosen is based on the controller
+associated with the C<$node>.
+
+=cut
+sub discovery_topic_for_node {
+ my $node = shift;
+
+ my $controller = $node->controller;
+
+ if ($controller eq 'openflow') {
+ return ('OF.Discovery.RPC', undef);
+ }
+ elsif ($controller eq 'netconf') {
+ return ('MPLS.Discovery.RPC', undef);
+ }
+ elsif ($controller eq 'nso') {
+ return ('NSO.Discovery.RPC', undef);
+ }
+ else {
+ return (undef, "Unexpected controller '$controller' found for node.");
+ }
+}
+
+=head2 fwdctl_topic_for_node
+
+ my ($topic, $err) = fwdctl_topic_for_node($node);
+
+fwdctl_topic_for_node returns the topic which should be used for
+working with C<$node>. The topic chosen is based on the controller
+associated with the C<$node>.
+
+=cut
+sub fwdctl_topic_for_node {
+ my $node = shift;
+
+ my $controller = $node->controller;
+
+ if ($controller eq 'openflow') {
+ return ('OF.FWDCTL.RPC', undef);
+ }
+ elsif ($controller eq 'netconf') {
+ return ('MPLS.FWDCTL.RPC', undef);
+ }
+ elsif ($controller eq 'nso') {
+ return ('NSO.FWDCTL.RPC', undef);
+ }
+ else {
+ return (undef, "Unexpected controller '$controller' found for node.");
+ }
+}
+
+return 1;
diff --git a/perl-lib/OESS/lib/OESS/Topology.pm b/perl-lib/OESS/lib/OESS/Topology.pm
index 80407c329..e2b3a25bc 100644
--- a/perl-lib/OESS/lib/OESS/Topology.pm
+++ b/perl-lib/OESS/lib/OESS/Topology.pm
@@ -368,7 +368,6 @@ sub find_path {
#step1 (get nodes);
my @tmp = @{$db->get_current_nodes( type => $type )};
-
my @db_nodes;
foreach my $tmp_node (@tmp){
diff --git a/perl-lib/OESS/lib/OESS/VRF.pm b/perl-lib/OESS/lib/OESS/VRF.pm
index 1c418e0ee..c61940e5a 100644
--- a/perl-lib/OESS/lib/OESS/VRF.pm
+++ b/perl-lib/OESS/lib/OESS/VRF.pm
@@ -110,6 +110,13 @@ sub from_hash{
$self->{'vrf_id'} = $hash->{'vrf_id'};
$self->{'workgroup_id'} = $hash->{'workgroup_id'};
+ # if (defined $hash->{endpoints}) {
+ # $self->{endpoints} = [];
+ # foreach my $ep (@{$hash->{endpoints}}) {
+ # push(@{$self->{endpoints}}, new OESS::Endpoint(db => $self->{db}, model => $ep));
+ # }
+ # }
+
return 1;
}
@@ -171,6 +178,7 @@ sub load_endpoints {
db => $self->{db},
vrf_id => $self->{vrf_id}
);
+ $self->{logger}->warn($error) if defined $error;
$self->{endpoints} = [];
foreach my $data (@$ep_datas) {
@@ -568,4 +576,225 @@ sub operational_state{
}
}
+=head2 nso_diff
+
+Given an NSO Connection object: Return a hash of device-name to
+human-readable-diff containing the difference between this L2Circuit
+and the provided NSO Connection object.
+
+NSO L2Connection:
+
+ {
+ "connection_id" => 1,
+ "endpoint" => [
+ {
+ "endpoint_id" => 1,
+ "vars" => {
+ "pdp" => "CHIC-JJJ-0",
+ "ce_id" => 1,
+ "remote_ce_id" => 2
+ },
+ "device" => "xr0",
+ "interface" => "GigabitEthernet0/0",
+ "tag" => 300,
+ "bandwidth" => 100,
+ "peer" => [
+ {
+ "peer_id" => 1,
+ "local_asn" => 64600,
+ "local_ip" => "192.168.1.2/31",
+ "peer_asn" => 64001,
+ "peer_ip" => "192.168.1.3/31",
+ "bfd" => 0
+ }
+ ]
+ },
+ {
+ "endpoint_id" => 2,
+ "vars" => {
+ "pdp" => "CHIC-JJJ-1",
+ "ce_id" => 2,
+ "remote_ce_id" => 1
+ },
+ "device" => "xr1",
+ "interface" => "GigabitEthernet0/1",
+ "tag" => 300,
+ "bandwidth" => 100,
+ "peer" => [
+ {
+ "peer_id" => 2,
+ "local_asn" => 64600,
+ "local_ip" => "192.168.2.2/31",
+ "peer_asn" => 64602,
+ "peer_ip" => "192.168.2.3/31",
+ "bfd" => 0
+ }
+ ]
+ }
+ ]
+ }
+
+=cut
+sub nso_diff {
+ my $self = shift;
+ my $nsoc = shift; # NSOConnection
+
+ my $diff = {};
+ my $ep_index = {};
+
+ # Handle case where connection has no endpoints or a connection
+ # created with an empty model.
+ my $endpoints = $self->endpoints || [];
+
+ foreach my $ep (@{$endpoints}) {
+ if (!defined $ep_index->{$ep->node}) {
+ $diff->{$ep->node} = "";
+ $ep_index->{$ep->node} = {};
+ }
+ $ep_index->{$ep->node}->{$ep->interface} = $ep;
+ }
+
+ foreach my $ep (@{$nsoc->{endpoint}}) {
+ if (!defined $ep_index->{$ep->{device}}->{$ep->{interface}}) {
+ $diff->{$ep->{device}} = "" if !defined $diff->{$ep->{device}};
+ $diff->{$ep->{device}} .= "- $ep->{interface}\n";
+ $diff->{$ep->{device}} .= "- Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->{device}} .= "- Tag: $ep->{tag}\n";
+ $diff->{$ep->{device}} .= "- Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+
+ foreach my $peer (@{$ep->{peer}}) {
+ $diff->{$ep->{device}} .= "- Peer $peer->{peer_id}:\n";
+ $diff->{$ep->{device}} .= "- Local ASN: $peer->{local_asn}\n";
+ $diff->{$ep->{device}} .= "- Local IP: $peer->{local_ip}\n";
+ $diff->{$ep->{device}} .= "- Peer ASN: $peer->{peer_asn}\n";
+ $diff->{$ep->{device}} .= "- Peer IP: $peer->{peer_ip}\n";
+ $diff->{$ep->{device}} .= "- BFD: $peer->{bfd}\n";
+ }
+ next;
+ }
+ my $ref_ep = $ep_index->{$ep->{device}}->{$ep->{interface}};
+
+ # Compare endpoints
+ my $ok = 1;
+ $ok = 0 if $ep->{bandwidth} != $ref_ep->bandwidth;
+ $ok = 0 if $ep->{tag} != $ref_ep->tag;
+ $ok = 0 if $ep->{inner_tag} != $ref_ep->inner_tag;
+ if (!$ok) {
+ $diff->{$ep->{device}} = "" if !defined $diff->{$ep->{device}};
+ $diff->{$ep->{device}} .= " $ep->{interface}\n";
+ }
+
+ if ($ep->{bandwidth} != $ref_ep->bandwidth) {
+ $diff->{$ep->{device}} .= "- Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->{device}} .= "+ Bandwidth: $ref_ep->{bandwidth}\n";
+ }
+ if ($ep->{tag} != $ref_ep->tag) {
+ $diff->{$ep->{device}} .= "- Tag: $ep->{tag}\n";
+ $diff->{$ep->{device}} .= "+ Tag: $ref_ep->{tag}\n";
+ }
+ if ($ep->{inner_tag} != $ref_ep->inner_tag) {
+ $diff->{$ep->{device}} .= "- Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+ $diff->{$ep->{device}} .= "+ Inner Tag: $ref_ep->{inner_tag}\n" if defined $ref_ep->{inner_tag};
+ }
+
+ # Compare an Endpoint's Peers
+ my $peer_diff = "";
+ my $index = {};
+ foreach my $peer (@{$ref_ep->peers}) {
+ $index->{$peer->vrf_ep_peer_id} = $peer;
+ }
+
+ foreach my $pr (@{$ep->{peer}}) {
+ if (!defined $index->{$pr->{peer_id}}) {
+ # Peer should be removed
+ $peer_diff .= "- Peer $pr->{peer_id}\n";
+ $peer_diff .= "- Local ASN: $pr->{local_asn}\n";
+ $peer_diff .= "- Local IP: $pr->{local_ip}\n";
+ $peer_diff .= "- Peer ASN: $pr->{peer_asn}\n";
+ $peer_diff .= "- Peer IP: $pr->{peer_ip}\n";
+ $peer_diff .= "- BFD: $pr->{bfd}\n";
+ }
+
+ my $ref = $index->{$pr->{peer_id}};
+
+ # Peer should be compared
+ my $ok = 1;
+ $ok = 0 if $pr->{local_ip} ne $ref->local_ip;
+ $ok = 0 if $pr->{peer_asn} != $ref->peer_asn;
+ # Peer IP shouldn't have subnet included due to a quirk in
+ # thenetwork config.
+ my @ref_peer_ip = split('/', $ref->peer_ip);
+ $ok = 0 if $pr->{peer_ip} ne $ref_peer_ip[0];
+ if (!$ok) {
+ $peer_diff .= " Peer $pr->{peer_id}:\n";
+ }
+
+ if ($pr->{local_ip} ne $ref->local_ip) {
+ $peer_diff .= "- Local IP: $pr->{local_ip}\n";
+ $peer_diff .= "+ Local IP: $ref->{local_ip}\n";
+ }
+ if ($pr->{peer_asn} != $ref->peer_asn) {
+ $peer_diff .= "- Peer ASN: $pr->{peer_asn}\n";
+ $peer_diff .= "+ Peer ASN: $ref->{peer_asn}\n";
+ }
+ if ($pr->{peer_ip} ne $ref_peer_ip[0]) {
+ $peer_diff .= "- Peer IP: $pr->{peer_ip}\n";
+ $peer_diff .= "+ Peer IP: $ref_peer_ip[0]\n";
+ }
+ if ($pr->{bfd} != $ref->bfd) {
+ $peer_diff .= "- BFD: $pr->{bfd}\n";
+ $peer_diff .= "+ BFD: $ref->{bfd}\n";
+ }
+
+ delete $index->{$pr->{peer_id}};
+ }
+
+ foreach my $id (keys %{$index}) {
+ # Peer should be added
+ my $pr = $index->{$id};
+ my @ref_peer_ip = split('/', $pr->peer_ip);
+
+ $peer_diff .= "+ Peer $pr->{vrf_ep_peer_id}:\n";
+ $peer_diff .= "+ Local ASN: $pr->{local_asn}\n";
+ $peer_diff .= "+ Local IP: $pr->{local_ip}\n";
+ $peer_diff .= "+ Peer ASN: $pr->{peer_asn}\n";
+ $peer_diff .= "+ Peer IP: $ref_peer_ip[0]\n";
+ $peer_diff .= "+ BFD: $pr->{bfd}\n";
+ }
+ # End Compare an Endpoint's Peers
+ $diff->{$ep->{device}} .= $peer_diff;
+
+ delete $ep_index->{$ep->{device}}->{$ep->{interface}};
+ }
+
+ foreach my $device_key (keys %{$ep_index}) {
+ foreach my $ep_key (keys %{$ep_index->{$device_key}}) {
+ my $ep = $ep_index->{$device_key}->{$ep_key};
+ $diff->{$ep->node} = "" if !defined $diff->{$ep->node};
+
+ $diff->{$ep->node} .= "+ $ep->{interface}\n";
+ $diff->{$ep->node} .= "+ Bandwidth: $ep->{bandwidth}\n";
+ $diff->{$ep->node} .= "+ Tag: $ep->{tag}\n";
+ $diff->{$ep->node} .= "+ Inner Tag: $ep->{inner_tag}\n" if defined $ep->{inner_tag};
+
+ foreach my $peer (@{$ep->peers}) {
+ my @ref_peer_ip = split('/', $peer->{peer_ip});
+
+ $diff->{$ep->node} .= "+ Peer $peer->{vrf_ep_peer_id}:\n";
+ $diff->{$ep->node} .= "+ Local ASN: $self->{local_asn}\n";
+ $diff->{$ep->node} .= "+ Local IP: $peer->{local_ip}\n";
+ $diff->{$ep->node} .= "+ Peer ASN: $peer->{peer_asn}\n";
+ $diff->{$ep->node} .= "+ Peer IP: $ref_peer_ip[0]\n";
+ $diff->{$ep->node} .= "+ BFD: $peer->{bfd}\n";
+ }
+ }
+ }
+
+ foreach my $key (keys %$diff) {
+ delete $diff->{$key} if ($diff->{$key} eq '');
+ }
+
+ return $diff;
+}
+
1;
diff --git a/perl-lib/OESS/perl-OESS.spec b/perl-lib/OESS/perl-OESS.spec
index 4ea5d2b7d..41bd11ace 100644
--- a/perl-lib/OESS/perl-OESS.spec
+++ b/perl-lib/OESS/perl-OESS.spec
@@ -1,7 +1,7 @@
Summary: OESS Perl Libraries
Name: perl-OESS
-Version: 2.0.11
-Release: 3%{?dist}
+Version: 2.0.12
+Release: 1%{?dist}
License: APL 2.0
Group: Network
URL: http://globalnoc.iu.edu
@@ -38,12 +38,14 @@ Requires: perl
Requires: perl-NetAddr-IP
Requires: perl(AnyEvent)
Requires: perl(AnyEvent::Fork)
+Requires: perl(AnyEvent::HTTP)
Requires: perl(Array::Utils)
Requires: perl(Class::Accessor)
Requires: perl(Data::Dumper)
Requires: perl(Data::UUID)
Requires: perl(DateTime)
Requires: perl(DBI), perl(DBD::mysql)
+Requires: perl(Encode)
Requires: perl(English)
Requires: perl(Exporter)
Requires: perl(File::ShareDir)
@@ -65,6 +67,7 @@ Requires: perl(JSON::XS)
Requires: perl(List::Compare)
Requires: perl(List::MoreUtils)
Requires: perl(Log::Log4perl)
+Requires: perl(LWP::Protocol::https)
Requires: perl(MIME::Lite::TT::HTML)
Requires: perl(Net::DBus)
Requires: perl(Net::DBus::Exporter)
@@ -209,10 +212,17 @@ rm -rf $RPM_BUILD_ROOT
%doc %{_mandir}/man3/OESS::NSI::Utils.3pm.gz
%doc %{_mandir}/man3/OESS::RabbitMQ::Client.3pm.gz
%doc %{_mandir}/man3/OESS::RabbitMQ::Dispatcher.3pm.gz
+%doc %{_mandir}/man3/OESS::RabbitMQ::Topic.3pm.gz
%doc %{_mandir}/man3/OESS::Topology.3pm.gz
%doc %{_mandir}/man3/OESS::Traceroute.3pm.gz
%doc %{_mandir}/man3/OESS::Watchdog.3pm.gz
%doc %{_mandir}/man3/OESS::Webservice.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::Client.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::ClientStub.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::ConnectionCache.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::Discovery.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::FWDCTL.3pm.gz
+%doc %{_mandir}/man3/OESS::NSO::FWDCTLService.3pm.gz
%{template_dir}/notification_templates.tmpl
%{template_dir}/notification.tt.html
%{template_dir}/notification_vrf.tt.html
@@ -282,10 +292,17 @@ rm -rf $RPM_BUILD_ROOT
%{perl_vendorlib}/OESS/NSI/Utils.pm
%{perl_vendorlib}/OESS/RabbitMQ/Client.pm
%{perl_vendorlib}/OESS/RabbitMQ/Dispatcher.pm
+%{perl_vendorlib}/OESS/RabbitMQ/Topic.pm
%{perl_vendorlib}/OESS/Topology.pm
%{perl_vendorlib}/OESS/Traceroute.pm
%{perl_vendorlib}/OESS/Watchdog.pm
%{perl_vendorlib}/OESS/Webservice.pm
+%{perl_vendorlib}/OESS/NSO/Client.pm
+%{perl_vendorlib}/OESS/NSO/ClientStub.pm
+%{perl_vendorlib}/OESS/NSO/ConnectionCache.pm
+%{perl_vendorlib}/OESS/NSO/Discovery.pm
+%{perl_vendorlib}/OESS/NSO/FWDCTL.pm
+%{perl_vendorlib}/OESS/NSO/FWDCTLService.pm
%{docdir}/share/nddi.sql
%{docdir}/share/upgrade/*
%{docdir}/share/customer-templates/*
diff --git a/perl-lib/OESS/share/nddi.sql b/perl-lib/OESS/share/nddi.sql
index caa94476f..9d4d1fa4b 100755
--- a/perl-lib/OESS/share/nddi.sql
+++ b/perl-lib/OESS/share/nddi.sql
@@ -544,6 +544,8 @@ CREATE TABLE `network` (
UNIQUE KEY `network_idx` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `network` (`network_id`,`name`,`longitude`,`latitude`,`is_local`) VALUES (1,'oess',0,0,1);
+
--
-- Table structure for table `node`
--
@@ -606,6 +608,7 @@ CREATE TABLE `node_instantiation` (
`mgmt_addr` varchar(255) DEFAULT NULL,
`loopback_address` varchar(255) DEFAULT NULL,
`tcp_port` int(6) DEFAULT '830',
+ `controller` enum('openflow','netconf','nso') NOT NULL DEFAULT 'nso',
PRIMARY KEY (`node_id`,`end_epoch`),
UNIQUE KEY `node_instantiation_idx` (`end_epoch`,`dpid`),
CONSTRAINT `node_node_instantiation_fk` FOREIGN KEY (`node_id`) REFERENCES `node` (`node_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
@@ -663,7 +666,7 @@ CREATE TABLE `oess_version` (
LOCK TABLES `oess_version` WRITE;
/*!40000 ALTER TABLE `oess_version` DISABLE KEYS */;
-INSERT INTO `oess_version` VALUES ('2.0.11');
+INSERT INTO `oess_version` VALUES ('2.0.12');
/*!40000 ALTER TABLE `oess_version` ENABLE KEYS */;
UNLOCK TABLES;
@@ -768,7 +771,7 @@ CREATE TABLE `remote_auth` (
CONSTRAINT `user_auth_values_fk` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
-
+INSERT INTO `remote_auth` (`auth_name`,`user_id`) VALUES ('admin',1);
--
-- Dumping data for table `remote_auth`
--
@@ -881,6 +884,7 @@ CREATE TABLE `user` (
KEY `user_idx` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `user` (`user_id`,`email`,`given_names`,`family_name`,`is_admin`,`status`) VALUES (1,'admin@localhost','admin','admin',1,'active');
--
-- Table structure for table `user_entity_membership`
@@ -896,6 +900,7 @@ CREATE TABLE `user_entity_membership` (
KEY `user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `user_entity_membership` (`user_id`,`entity_id`) VALUES (1,1);
--
-- Table structure for table `user_workgroup_membership`
@@ -914,6 +919,7 @@ CREATE TABLE `user_workgroup_membership` (
CONSTRAINT `workgroups_user_workgroup_membership_fk` FOREIGN KEY (`workgroup_id`) REFERENCES `workgroup` (`workgroup_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `user_workgroup_membership` (`workgroup_id`,`user_id`,`role`) VALUES (1,1,'admin');
--
-- Table structure for table `vrf`
@@ -940,7 +946,7 @@ CREATE TABLE `vrf` (
CONSTRAINT `vrf_ibfk_3` FOREIGN KEY (`last_modified_by`) REFERENCES `user` (`user_id`),
CONSTRAINT `vrf_ibfk_1` FOREIGN KEY (`workgroup_id`) REFERENCES `workgroup` (`workgroup_id`),
CONSTRAINT `vrf_ibfk_2` FOREIGN KEY (`created_by`) REFERENCES `user` (`user_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB AUTO_INCREMENT=6000 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -1043,6 +1049,7 @@ CREATE TABLE `workgroup` (
UNIQUE KEY `workgroups_idx` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `workgroup` (`workgroup_id`,`description`,`name`,`type`) VALUES (1,'admin','admin','admin');
--
-- Dumping data for table `workgroup`
diff --git a/perl-lib/OESS/share/upgrade/oess-2.0.11-2.0.12 b/perl-lib/OESS/share/upgrade/oess-2.0.11-2.0.12
new file mode 100644
index 000000000..745441055
--- /dev/null
+++ b/perl-lib/OESS/share/upgrade/oess-2.0.11-2.0.12
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+#-------------------------------------------------------------------
+#----- OESS 2.0.11 - 2.0.12 upgrade module
+#-----
+#----- Copyright(C) 2010 The Trustees of Indiana University
+#--------------------------------------------------------------------
+#----- $HeadURL: $
+#----- $Id: $
+#-----
+#----- This is run when upgrading the database from
+#----- version 2.0.11 to version 2.0.12
+#--------------------------------------------------------------------
+
+use strict;
+use warnings;
+use OESS::Database;
+
+my $prev_version = "2.0.11";
+my $version = "2.0.12";
+
+sub main{
+ print "*******************************************************************\n";
+ print "********* OESS DB UPGRADE ************\n";
+ print "*******************************************************************\n";
+ print "********* This will upgrade from $prev_version to $version **********\n";
+ print "********* of the OESS DB any other version will not work ************\n";
+
+ continue_parameter("Do you wish to continue");
+
+ my $dbq = new OESS::Database();
+ my $current_version = $dbq->get_oess_schema_version();
+ if($current_version eq $prev_version){
+ eval {
+ $dbq->{'dbh'}->begin_work();
+ upgrade($dbq);
+ $dbq->{'dbh'}->commit();
+ };
+ if ($@) {
+ $dbq->{'dbh'}->rollback();
+ print "$@\n";
+ exit;
+ }
+ } else{
+ print "Wrong version of OESS DB\n";
+ print "This script only upgrades from version $prev_version to $version\n";
+ exit;
+ }
+
+ print STDERR "Upgrade Successful!!\n";
+}
+
+sub upgrade{
+ my $dbq = shift;
+ my $term = shift;
+ my $dbh = $dbq->{'dbh'};
+ my $str;
+ my $sth;
+
+ $sth = $dbh->prepare("ALTER TABLE node_instantiation ADD controller enum('openflow','netconf','nso') NOT NULL DEFAULT 'nso'");
+ $sth->execute() or die "Unable to add 'controller' to Table";
+
+ $sth = $dbh->prepare("UPDATE node_instantiation SET controller='openflow' WHERE node_instantiation.openflow=1");
+ $sth->execute() or die "Unable to update column 'controller' in node_instantiation table";
+
+ $sth = $dbh->prepare("UPDATE node_instantiation SET controller='netconf' WHERE node_instantiation.mpls=1");
+ $sth->execute() or die "Unable to update column 'controller' in node_instantiation table";
+
+ $str = "update oess_version set version = '$version'";
+ $sth = $dbh->prepare($str) or die "Unable to prepare version update \n";
+ $sth->execute() or die "Unable to update version\n";
+}
+
+main();
+
+sub continue_parameter {
+ my $name = shift;
+
+ print "$name [y/n]: ";
+ my $yes_or_no = <>;
+ chomp($yes_or_no);
+
+ exit(0) if ($yes_or_no !~ /y/i || $yes_or_no =~ /n/i);
+}
+
+sub required_parameter {
+ my $name = shift;
+
+ while (1) {
+ print "$name (required): ";
+ my $response = <>;
+ chomp($response);
+
+ return $response if ($response);
+
+ print "\nThis option is required!\n\n";
+ }
+}
diff --git a/perl-lib/OESS/t/00-load_base.t b/perl-lib/OESS/t/00-load_base.t
index 9f00e8958..e430d5a3f 100644
--- a/perl-lib/OESS/t/00-load_base.t
+++ b/perl-lib/OESS/t/00-load_base.t
@@ -1,25 +1,31 @@
#!perl -T
-use Test::More tests => 17;
+use Test::More tests => 23;
BEGIN {
- use_ok( 'OESS::Database' );
- use_ok( 'OESS::Topology' );
- use_ok( 'OESS::DBus' );
- use_ok( 'OESS::FlowRule' );
- use_ok( 'OESS::Circuit' );
- use_ok( 'OESS::Measurement' );
- use_ok( 'OESS::Notification' );
- use_ok( 'OESS::Traceroute');
- use_ok( 'OESS::MPLS::FWDCTL');
- use_ok( 'OESS::MPLS::Switch');
- use_ok( 'OESS::MPLS::Discovery');
- use_ok( 'OESS::MPLS::Device');
- use_ok( 'OESS::MPLS::Device::Juniper::MX');
- use_ok( 'OESS::MPLS::Discovery::Interface');
- use_ok( 'OESS::MPLS::Discovery::ISIS');
- use_ok( 'OESS::MPLS::Discovery::Paths');
- use_ok( 'OESS::MPLS::Topology');
+ use_ok( 'OESS::Database' );
+ use_ok( 'OESS::Topology' );
+ use_ok( 'OESS::DBus' );
+ use_ok( 'OESS::FlowRule' );
+ use_ok( 'OESS::Circuit' );
+ use_ok( 'OESS::Measurement' );
+ use_ok( 'OESS::Notification' );
+ use_ok( 'OESS::Traceroute');
+ use_ok( 'OESS::MPLS::FWDCTL');
+ use_ok( 'OESS::MPLS::Switch');
+ use_ok( 'OESS::MPLS::Discovery');
+ use_ok( 'OESS::MPLS::Device');
+ use_ok( 'OESS::MPLS::Device::Juniper::MX');
+ use_ok( 'OESS::MPLS::Discovery::Interface');
+ use_ok( 'OESS::MPLS::Discovery::ISIS');
+ use_ok( 'OESS::MPLS::Discovery::Paths');
+ use_ok( 'OESS::MPLS::Topology');
+ use_ok( 'OESS::NSO::Client' );
+ use_ok( 'OESS::NSO::ClientStub' );
+ use_ok( 'OESS::NSO::ConnectionCache' );
+ use_ok( 'OESS::NSO::Discovery' );
+ use_ok( 'OESS::NSO::FWDCTL' );
+ use_ok( 'OESS::NSO::FWDCTLService' );
}
diff --git a/perl-lib/OESS/t/circuit-loop.t b/perl-lib/OESS/t/circuit-loop.t
index 270fbc921..d10090423 100644
--- a/perl-lib/OESS/t/circuit-loop.t
+++ b/perl-lib/OESS/t/circuit-loop.t
@@ -25,6 +25,11 @@ Log::Log4perl::init_and_watch('t/conf/logging.conf',10);
my $db = OESS::Database->new( config => OESSDatabaseTester::getConfigFilePath() );
+
+# These tests expect use of the node type 'openflow'.
+$db->_execute_query("update node_instantiation set controller='openflow'", []);
+
+
my $ckt = OESS::Circuit->new( circuit_id => 4171, db => $db);
ok($ckt->has_backup_path(), "Circuit does have backup path");
diff --git a/perl-lib/OESS/t/conf/database.xml b/perl-lib/OESS/t/conf/database.xml
index b6324fd21..c491aae43 100644
--- a/perl-lib/OESS/t/conf/database.xml
+++ b/perl-lib/OESS/t/conf/database.xml
@@ -1,4 +1,6 @@
-
+
+
+
diff --git a/perl-lib/OESS/t/conf/interface-speed-config.xml b/perl-lib/OESS/t/conf/interface-speed-config.xml
index f7520c86d..c4c43d902 100644
--- a/perl-lib/OESS/t/conf/interface-speed-config.xml
+++ b/perl-lib/OESS/t/conf/interface-speed-config.xml
@@ -43,4 +43,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/perl-lib/OESS/t/conf/logging.conf b/perl-lib/OESS/t/conf/logging.conf
index 1df7e8177..aa32e0696 100644
--- a/perl-lib/OESS/t/conf/logging.conf
+++ b/perl-lib/OESS/t/conf/logging.conf
@@ -2,14 +2,24 @@
# A simple root logger with a Log::Log4perl::Appender::File
# file appender in Perl.
############################################################
-log4perl.rootLogger=ERROR, Screen
+log4perl.rootLogger=DEBUG, LOGFILE
+
+log4perl.logger.GRNOC = WARN, LOGFILE
+log4perl.logger.OESS.Circuit = INFO, LOGFILE
+log4perl.logger.OESS.Database = INFO, LOGFILE
+log4perl.logger.OESS.MPLS.Device = INFO, LOGFILE
+log4perl.logger.OESS.MPLS.Discovery = INFO, LOGFILE
+log4perl.logger.OESS.MPLS.FWDCTL.Switch = INFO, LOGFILE
+log4perl.logger.OESS.Notification = INFO, LOGFILE
+log4perl.logger.OESS.NSO.FWDCTL = DEBUG, LOGFILE
+
+log4perl.oneMessagePerAppender = 1
log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
-log4perl.appender.LOGFILE.filename=/var/log/myerrs.log
+log4perl.appender.LOGFILE.filename=/var/log/oess.log
log4perl.appender.LOGFILE.mode=append
-
log4perl.appender.LOGFILE.layout=PatternLayout
-log4perl.appender.LOGFILE.layout.ConversionPattern=[%r] %F %L %c - %m%n
+log4perl.appender.LOGFILE.layout.ConversionPattern=[%d] %p %c %F %L - %m%n
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.stderr = 0
diff --git a/perl-lib/OESS/t/conf/mpls/discovery.sql b/perl-lib/OESS/t/conf/mpls/discovery.sql
index 00a36dfc7..1ea133466 100644
--- a/perl-lib/OESS/t/conf/mpls/discovery.sql
+++ b/perl-lib/OESS/t/conf/mpls/discovery.sql
@@ -1,8 +1,8 @@
--- MySQL dump 10.14 Distrib 5.5.65-MariaDB, for Linux (x86_64)
+-- MySQL dump 10.16 Distrib 10.1.22-MariaDB, for Linux (x86_64)
--
-- Host: localhost Database: discovery
-- ------------------------------------------------------
--- Server version 5.5.65-MariaDB
+-- Server version 10.1.22-MariaDB
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -74,7 +74,7 @@ CREATE TABLE `circuit_edge_interface_membership` (
`inner_tag` int(10) DEFAULT NULL,
`circuit_edge_id` int(10) NOT NULL AUTO_INCREMENT,
`unit` int(11) NOT NULL,
- `bandwidth` int(10) DEFAULT NULL,
+ `bandwidth` int(10) DEFAULT '0',
`mtu` int(11) NOT NULL DEFAULT '9000',
PRIMARY KEY (`circuit_edge_id`),
UNIQUE KEY `interface_id` (`interface_id`,`circuit_id`,`end_epoch`,`extern_vlan_id`),
@@ -271,12 +271,14 @@ DROP TABLE IF EXISTS `entity`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `entity` (
`entity_id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) DEFAULT NULL,
+ `name` varchar(255),
`description` text,
`logo_url` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`entity_id`),
- UNIQUE KEY `name` (`name`)
+ UNIQUE KEY `name` (`name`),
+ UNIQUE KEY `name_2` (`name`),
+ UNIQUE KEY `name_3` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -658,6 +660,7 @@ CREATE TABLE `node_instantiation` (
`mgmt_addr` varchar(255) DEFAULT NULL,
`loopback_address` varchar(255) DEFAULT NULL,
`tcp_port` int(6) DEFAULT '830',
+ `controller` enum('openflow','netconf','nso') NOT NULL DEFAULT 'nso',
PRIMARY KEY (`node_id`,`end_epoch`),
UNIQUE KEY `node_instantiation_idx` (`end_epoch`,`dpid`),
CONSTRAINT `node_node_instantiation_fk` FOREIGN KEY (`node_id`) REFERENCES `node` (`node_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
@@ -670,7 +673,7 @@ CREATE TABLE `node_instantiation` (
LOCK TABLES `node_instantiation` WRITE;
/*!40000 ALTER TABLE `node_instantiation` DISABLE KEYS */;
-INSERT INTO `node_instantiation` VALUES (2,-1,1348237415,'active','00000002',0,1,'juniper','mx960','13.3R3','192.168.1.2','10.0.1.2',830),(3,-1,1348237415,'active','00000003',0,1,'juniper','mx960','13.3R3','192.168.1.3','10.0.1.3',830);
+INSERT INTO `node_instantiation` VALUES (2,-1,1348237415,'active','00000002',0,1,'juniper','mx960','13.3R3','192.168.1.2','10.0.1.2',830,'netconf'),(3,-1,1348237415,'active','00000003',0,1,'juniper','mx960','13.3R3','192.168.1.3','10.0.1.3',830,'netconf');
/*!40000 ALTER TABLE `node_instantiation` ENABLE KEYS */;
UNLOCK TABLES;
@@ -716,7 +719,7 @@ CREATE TABLE `oess_version` (
LOCK TABLES `oess_version` WRITE;
/*!40000 ALTER TABLE `oess_version` DISABLE KEYS */;
-INSERT INTO `oess_version` VALUES ('2.0.3');
+INSERT INTO `oess_version` VALUES ('2.0.12');
/*!40000 ALTER TABLE `oess_version` ENABLE KEYS */;
UNLOCK TABLES;
@@ -1043,7 +1046,7 @@ CREATE TABLE `vrf_ep` (
`vrf_ep_id` int(11) NOT NULL AUTO_INCREMENT,
`inner_tag` int(10) DEFAULT NULL,
`tag` int(10) DEFAULT NULL,
- `bandwidth` int(10) DEFAULT NULL,
+ `bandwidth` int(10) DEFAULT '0',
`vrf_id` int(10) DEFAULT NULL,
`interface_id` int(10) NOT NULL,
`state` enum('active','decom') DEFAULT NULL,
@@ -1075,13 +1078,15 @@ DROP TABLE IF EXISTS `vrf_ep_peer`;
CREATE TABLE `vrf_ep_peer` (
`vrf_ep_peer_id` int(10) NOT NULL AUTO_INCREMENT,
`peer_ip` varchar(255) NOT NULL,
- `peer_asn` int(10) NOT NULL,
+ `peer_asn` int(10) unsigned DEFAULT NULL,
`vrf_ep_id` int(11) DEFAULT NULL,
`operational_state` int(1) DEFAULT NULL,
`state` enum('active','decom') DEFAULT NULL,
`local_ip` varchar(255) DEFAULT NULL,
`md5_key` varchar(255) DEFAULT NULL,
`circuit_ep_id` int(11) DEFAULT NULL,
+ `bfd` int(1) NOT NULL DEFAULT '0',
+ `ip_version` enum('ipv4','ipv6') DEFAULT NULL,
PRIMARY KEY (`vrf_ep_peer_id`),
KEY `vrf_ep_id` (`vrf_ep_id`),
KEY `vrf_ep_peer_ibfk_2` (`circuit_ep_id`),
@@ -1111,7 +1116,7 @@ CREATE TABLE `workgroup` (
`description` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`external_id` varchar(255) DEFAULT NULL,
- `type` varchar(20) DEFAULT 'normal',
+ `type` enum('demo','normal','admin') NOT NULL DEFAULT 'normal',
`max_mac_address_per_end` int(10) DEFAULT '10',
`max_circuits` int(10) DEFAULT '20',
`max_circuit_endpoints` int(10) DEFAULT '10',
@@ -1165,4 +1170,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2020-06-24 15:25:54
+-- Dump completed on 2021-07-13 1:01:13
diff --git a/perl-lib/OESS/t/conf/oess_known_state.sql b/perl-lib/OESS/t/conf/oess_known_state.sql
index fae666d11..33a34ce9e 100644
--- a/perl-lib/OESS/t/conf/oess_known_state.sql
+++ b/perl-lib/OESS/t/conf/oess_known_state.sql
@@ -1,8 +1,8 @@
--- MySQL dump 10.14 Distrib 5.5.65-MariaDB, for Linux (x86_64)
+-- MySQL dump 10.16 Distrib 10.1.22-MariaDB, for Linux (x86_64)
--
-- Host: localhost Database: oess_test
-- ------------------------------------------------------
--- Server version 5.5.65-MariaDB
+-- Server version 10.1.22-MariaDB
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -75,7 +75,7 @@ CREATE TABLE `circuit_edge_interface_membership` (
`circuit_edge_id` int(10) NOT NULL AUTO_INCREMENT,
`inner_tag` int(10) DEFAULT NULL,
`unit` int(11) DEFAULT NULL,
- `bandwidth` int(10) DEFAULT NULL,
+ `bandwidth` int(10) DEFAULT '0',
`mtu` int(11) NOT NULL DEFAULT '9000',
PRIMARY KEY (`circuit_edge_id`),
UNIQUE KEY `interface_id` (`interface_id`,`circuit_id`,`end_epoch`,`extern_vlan_id`),
@@ -91,7 +91,7 @@ CREATE TABLE `circuit_edge_interface_membership` (
LOCK TABLES `circuit_edge_interface_membership` WRITE;
/*!40000 ALTER TABLE `circuit_edge_interface_membership` DISABLE KEYS */;
-INSERT INTO `circuit_edge_interface_membership` VALUES (261,401,1352404946,1350575652,2090,1,NULL,2090,NULL,9000),(261,541,1352409782,1351187296,2495,11,NULL,2495,NULL,9000),(261,541,1355752805,1352409782,2495,21,NULL,2495,NULL,9000),(261,701,-1,1352402411,211,31,NULL,211,NULL,9000),(261,711,-1,1352405331,2063,41,NULL,2063,NULL,9000),(261,721,-1,1352405455,2048,51,NULL,2048,NULL,9000),(261,971,1353518153,1352500865,3001,61,NULL,3001,NULL,9000),(261,981,1352844422,1352500991,3002,71,NULL,3002,NULL,9000),(261,981,1352844591,1352844422,3002,81,NULL,3002,NULL,9000),(261,981,1353518168,1352844591,3002,91,NULL,3002,NULL,9000),(261,991,1352844667,1352501086,3003,101,NULL,3003,NULL,9000),(261,991,1353518490,1352844667,3003,111,NULL,3003,NULL,9000),(261,1001,1353518184,1352501128,3004,121,NULL,3004,NULL,9000),(261,1701,-1,1355752877,2495,131,NULL,2495,NULL,9000),(261,1711,-1,1355776962,2000,141,NULL,2000,NULL,9000),(261,1711,1355763396,1355763066,2000,151,NULL,2000,NULL,9000),(261,1711,1355766268,1355763396,2000,161,NULL,2000,NULL,9000),(261,1711,1355776962,1355766268,2000,171,NULL,2000,NULL,9000),(261,2231,1357849505,1357828819,114,181,NULL,114,NULL,9000),(261,2241,1358969497,1357849764,114,191,NULL,114,NULL,9000),(261,2241,1358969804,1358969497,114,201,NULL,114,NULL,9000),(261,2241,1358970629,1358969804,114,211,NULL,114,NULL,9000),(261,2241,1358974748,1358970629,-1,221,NULL,-1,NULL,9000),(261,3761,1361992060,1361811066,1234,231,NULL,1234,NULL,9000),(261,3811,-1,1361992120,3117,241,NULL,3117,NULL,9000),(261,3861,-1,1361992438,2507,251,NULL,2507,NULL,9000),(261,3891,-1,1361992748,3114,261,NULL,3114,NULL,9000),(261,3901,-1,1362144424,3113,271,NULL,3113,NULL,9000),(261,3901,1362144424,1361992795,3113,281,NULL,3113,NULL,9000),(261,3911,-1,1361992881,3112,291,NULL,3112,NULL,9000),(261,3921,-1,1361992947,3115,301,NULL,3115,NULL,9000),(261,3931,-1,1361993029,3111,311,NULL,3111,NULL,9000),(261,3941,-1,1361993115,3110,321,NULL,3110,NULL,9000),(261,3981,-1,1361993442,2501,331,NULL,2501,NULL,9000),(261,4021,-1,1361993940,2502,341,NULL,2502,NULL,9000),(261,4091,-1,1361994403,2056,351,NULL,2056,NULL,9000),(261,4131,-1,1361994603,2503,361,NULL,2503,NULL,9000),(261,4141,-1,1361994643,2505,371,NULL,2505,NULL,9000),(261,4151,-1,1362144220,2504,381,NULL,2504,NULL,9000),(261,4151,1362144220,1361994688,2504,391,NULL,2504,NULL,9000),(321,1261,1352697466,1352696879,3107,401,NULL,3107,NULL,9000),(321,1261,1353518964,1352697466,3107,411,NULL,3107,NULL,9000),(321,1491,-1,1361929111,201,421,NULL,201,NULL,9000),(321,1491,1360125490,1354649958,201,431,NULL,201,NULL,9000),(321,1491,1360125530,1360125490,201,441,NULL,201,NULL,9000),(321,1491,1360125558,1360125530,201,451,NULL,201,NULL,9000),(321,1491,1360125823,1360125558,201,461,NULL,201,NULL,9000),(321,1491,1361929111,1360125823,201,471,NULL,201,NULL,9000),(321,1581,1354891957,1354891574,3005,481,NULL,3005,NULL,9000),(321,2261,-1,1361931308,3107,491,NULL,3107,NULL,9000),(321,2261,1361931308,1357918922,3107,501,NULL,3107,NULL,9000),(321,2271,-1,1358196664,642,511,NULL,642,NULL,9000),(331,291,1349112329,1349112223,10,521,NULL,10,NULL,9000),(331,301,1349112881,1349112858,400,531,NULL,400,NULL,9000),(331,321,-1,1361930245,101,541,NULL,101,NULL,9000),(331,321,1361930245,1349115872,101,551,NULL,101,NULL,9000),(331,361,1349271255,1349269025,2001,561,NULL,2001,NULL,9000),(331,361,1349271454,1349271255,2001,571,NULL,2001,NULL,9000),(331,361,1349271885,1349271454,2001,581,NULL,2001,NULL,9000),(331,361,1352405011,1349271885,2001,591,NULL,2001,NULL,9000),(331,371,-1,1361930477,444,601,NULL,444,NULL,9000),(331,371,1349277633,1349272370,444,611,NULL,444,NULL,9000),(331,371,1349283588,1349277633,444,621,NULL,444,NULL,9000),(331,371,1349284670,1349283588,444,631,NULL,444,NULL,9000),(331,371,1349286925,1349284670,444,641,NULL,444,NULL,9000),(331,371,1349287611,1349286925,444,651,NULL,444,NULL,9000),(331,371,1361930477,1349287611,444,661,NULL,444,NULL,9000),(331,2471,1361458338,1360848531,443,671,NULL,443,NULL,9000),(331,3721,-1,1361459445,445,681,NULL,445,NULL,9000),(371,2021,-1,1360006189,1008,691,NULL,1008,NULL,9000),(371,2021,1359554761,1356977686,1008,701,NULL,1008,NULL,9000),(371,2021,1359570016,1359556515,1008,711,NULL,1008,NULL,9000),(371,2021,1359571455,1359570016,1008,721,NULL,1008,NULL,9000),(371,2021,1360002360,1359571455,1008,731,NULL,1008,NULL,9000),(371,2021,1360002398,1360002360,1008,741,NULL,1008,NULL,9000),(371,2021,1360004101,1360002398,1008,751,NULL,1008,NULL,9000),(371,2031,-1,1356977758,1009,761,NULL,1009,NULL,9000),(371,2041,-1,1360005139,1108,771,NULL,1108,NULL,9000),(371,2041,1356977919,1356977816,1108,781,NULL,1108,NULL,9000),(371,2041,1360005139,1356977919,1108,791,NULL,1108,NULL,9000),(371,2051,-1,1356977991,1109,801,NULL,1109,NULL,9000),(371,2061,-1,1356978636,1110,811,NULL,1110,NULL,9000),(371,2251,-1,1358969894,3717,821,NULL,3717,NULL,9000),(371,2251,1358969413,1357856197,3717,831,NULL,3717,NULL,9000),(371,2251,1358969894,1358969413,3717,841,NULL,3717,NULL,9000),(371,4171,-1,1362091612,3711,851,NULL,3711,NULL,9000),(381,191,-1,1348968376,114,861,NULL,114,NULL,9000),(381,211,-1,1348968857,116,871,NULL,116,NULL,9000),(381,2141,1357324428,1357324107,3717,881,NULL,3717,NULL,9000),(381,2141,1357333400,1357324428,3717,891,NULL,3717,NULL,9000),(381,2481,1360910657,1360908287,100,901,NULL,100,NULL,9000),(381,2491,1360917452,1360912217,80,911,NULL,80,NULL,9000),(381,2501,1360917454,1360912302,81,921,NULL,81,NULL,9000),(381,2511,1360917456,1360912393,83,931,NULL,83,NULL,9000),(381,2521,1360917459,1360912484,84,941,NULL,84,NULL,9000),(381,2531,1360917461,1360912584,85,951,NULL,85,NULL,9000),(381,2541,1360917463,1360912651,87,961,NULL,87,NULL,9000),(381,2551,1360917465,1360912753,88,971,NULL,88,NULL,9000),(381,2561,1360917467,1360912830,90,981,NULL,90,NULL,9000),(381,2571,1360915847,1360912904,100,991,NULL,100,NULL,9000),(381,2601,1360917474,1360915772,0,1001,NULL,0,NULL,9000),(381,2621,1360917478,1360915938,1,1011,NULL,1,NULL,9000),(381,2631,1360917480,1360915940,2,1021,NULL,2,NULL,9000),(381,2641,1360917482,1360915942,3,1031,NULL,3,NULL,9000),(381,2651,1360917484,1360915944,4,1041,NULL,4,NULL,9000),(381,2661,1360917486,1360915946,5,1051,NULL,5,NULL,9000),(381,2671,1360917488,1360915948,6,1061,NULL,6,NULL,9000),(381,2681,1360917490,1360915951,7,1071,NULL,7,NULL,9000),(381,2691,1360917492,1360915953,8,1081,NULL,8,NULL,9000),(381,2701,1360917495,1360915955,9,1091,NULL,9,NULL,9000),(381,2711,1360917497,1360915957,10,1101,NULL,10,NULL,9000),(381,2721,1360917498,1360915959,11,1111,NULL,11,NULL,9000),(381,2731,1360917501,1360915961,12,1121,NULL,12,NULL,9000),(381,2741,1360917503,1360915964,13,1131,NULL,13,NULL,9000),(381,2751,1360917505,1360915966,14,1141,NULL,14,NULL,9000),(381,2761,1360917507,1360915968,15,1151,NULL,15,NULL,9000),(381,2771,1360917509,1360915970,16,1161,NULL,16,NULL,9000),(381,2781,1360917511,1360915972,17,1171,NULL,17,NULL,9000),(381,2791,1360917513,1360915974,18,1181,NULL,18,NULL,9000),(381,2801,1360917515,1360915977,19,1191,NULL,19,NULL,9000),(381,2811,1360917517,1360915979,20,1201,NULL,20,NULL,9000),(381,2821,1360917520,1360915982,21,1211,NULL,21,NULL,9000),(381,2831,1360917522,1360915984,22,1221,NULL,22,NULL,9000),(381,2841,1360917524,1360915986,23,1231,NULL,23,NULL,9000),(381,2851,1360917526,1360915988,24,1241,NULL,24,NULL,9000),(381,2861,1360917528,1360915990,25,1251,NULL,25,NULL,9000),(381,2871,1360917531,1360915992,26,1261,NULL,26,NULL,9000),(381,2881,1360917533,1360915995,27,1271,NULL,27,NULL,9000),(381,2891,1360917535,1360915997,28,1281,NULL,28,NULL,9000),(381,2901,1360917537,1360915999,29,1291,NULL,29,NULL,9000),(381,2911,1360917539,1360916001,30,1301,NULL,30,NULL,9000),(381,2921,1360917541,1360916003,31,1311,NULL,31,NULL,9000),(381,2931,1360917543,1360916005,32,1321,NULL,32,NULL,9000),(381,2941,1360917545,1360916007,33,1331,NULL,33,NULL,9000),(381,2951,1360917547,1360916009,34,1341,NULL,34,NULL,9000),(381,2961,1360917549,1360916011,35,1351,NULL,35,NULL,9000),(381,2971,1360917552,1360916013,36,1361,NULL,36,NULL,9000),(381,2981,1360917554,1360916016,37,1371,NULL,37,NULL,9000),(381,2991,1360917556,1360916018,38,1381,NULL,38,NULL,9000),(381,3001,1360917558,1360916020,39,1391,NULL,39,NULL,9000),(381,3011,1360917560,1360916022,40,1401,NULL,40,NULL,9000),(381,3021,1360917562,1360916024,41,1411,NULL,41,NULL,9000),(381,3031,1360917564,1360916026,42,1421,NULL,42,NULL,9000),(381,3041,1360917567,1360916028,43,1431,NULL,43,NULL,9000),(381,3051,1360917569,1360916031,44,1441,NULL,44,NULL,9000),(381,3061,1360917571,1360916033,45,1451,NULL,45,NULL,9000),(381,3071,1360917573,1360916035,46,1461,NULL,46,NULL,9000),(381,3081,1360917575,1360916037,47,1471,NULL,47,NULL,9000),(381,3091,1360917578,1360916039,48,1481,NULL,48,NULL,9000),(381,3101,1360917580,1360916041,49,1491,NULL,49,NULL,9000),(381,3111,1360917582,1360916043,50,1501,NULL,50,NULL,9000),(381,3121,1360917584,1360916046,51,1511,NULL,51,NULL,9000),(381,3131,1360917586,1360916048,52,1521,NULL,52,NULL,9000),(381,3141,1360917588,1360916050,53,1531,NULL,53,NULL,9000),(381,3151,1360917591,1360916052,54,1541,NULL,54,NULL,9000),(381,3161,1360917593,1360916055,55,1551,NULL,55,NULL,9000),(381,3171,1360917595,1360916057,56,1561,NULL,56,NULL,9000),(381,3181,1360917597,1360916060,57,1571,NULL,57,NULL,9000),(381,3191,1360917599,1360916062,58,1581,NULL,58,NULL,9000),(381,3201,1360917601,1360916064,59,1591,NULL,59,NULL,9000),(381,3211,1360917604,1360916066,60,1601,NULL,60,NULL,9000),(381,3221,1360917606,1360916069,61,1611,NULL,61,NULL,9000),(381,3231,1360917608,1360916071,62,1621,NULL,62,NULL,9000),(381,3241,1360917610,1360916073,63,1631,NULL,63,NULL,9000),(381,3251,1360917612,1360916075,64,1641,NULL,64,NULL,9000),(381,3261,1360917614,1360916077,65,1651,NULL,65,NULL,9000),(381,3271,1360917617,1360916080,66,1661,NULL,66,NULL,9000),(381,3281,1360917618,1360916082,67,1671,NULL,67,NULL,9000),(381,3291,1360917621,1360916085,68,1681,NULL,68,NULL,9000),(381,3301,1360917623,1360916087,69,1691,NULL,69,NULL,9000),(381,3311,1360917625,1360916090,70,1701,NULL,70,NULL,9000),(381,3321,1360917627,1360916092,71,1711,NULL,71,NULL,9000),(381,3331,1360917629,1360916095,72,1721,NULL,72,NULL,9000),(381,3341,1360917631,1360916097,73,1731,NULL,73,NULL,9000),(381,3351,1360917633,1360916100,74,1741,NULL,74,NULL,9000),(381,3361,1360917635,1360916102,75,1751,NULL,75,NULL,9000),(381,3371,1360917637,1360916105,76,1761,NULL,76,NULL,9000),(381,3381,1360917639,1360916107,77,1771,NULL,77,NULL,9000),(381,3391,1360917642,1360916110,78,1781,NULL,78,NULL,9000),(381,3401,1360917644,1360916112,79,1791,NULL,79,NULL,9000),(381,3521,1360917664,1360916133,91,1801,NULL,91,NULL,9000),(381,3531,1360917666,1360916135,92,1811,NULL,92,NULL,9000),(381,3541,1360917668,1360916137,93,1821,NULL,93,NULL,9000),(381,3551,1360917670,1360916140,94,1831,NULL,94,NULL,9000),(381,3561,1360917672,1360916142,95,1841,NULL,95,NULL,9000),(381,3571,1360917674,1360916145,96,1851,NULL,96,NULL,9000),(381,3581,1360917677,1360916147,97,1861,NULL,97,NULL,9000),(381,3591,1360917679,1360916150,98,1871,NULL,98,NULL,9000),(381,3611,1360917682,1360916154,100,1881,NULL,100,NULL,9000),(381,3621,1360917685,1360916156,101,1891,NULL,101,NULL,9000),(381,3631,1360917687,1360916158,102,1901,NULL,102,NULL,9000),(381,3641,1360917688,1360916160,103,1911,NULL,103,NULL,9000),(381,3651,1360917691,1360916162,104,1921,NULL,104,NULL,9000),(381,3661,1360917693,1360916165,105,1931,NULL,105,NULL,9000),(381,3671,1360917695,1360916167,106,1941,NULL,106,NULL,9000),(381,3681,1360917697,1360916170,107,1951,NULL,107,NULL,9000),(381,3691,1361770800,1360916172,108,1961,NULL,108,NULL,9000),(391,1861,-1,1356020829,4013,1971,NULL,4013,NULL,9000),(391,2281,1358447202,1358446319,601,1981,NULL,601,NULL,9000),(401,151,-1,1348967392,110,1991,NULL,110,NULL,9000),(401,181,-1,1348968098,113,2001,NULL,113,NULL,9000),(401,191,-1,1348968376,114,2011,NULL,114,NULL,9000),(401,251,1349114627,1349112733,100,2021,NULL,100,NULL,9000),(401,311,-1,1349121932,100,2031,NULL,100,NULL,9000),(401,311,1349115092,1349114669,100,2041,NULL,100,NULL,9000),(401,311,1349115533,1349115092,100,2051,NULL,100,NULL,9000),(401,311,1349115553,1349115533,100,2061,NULL,100,NULL,9000),(401,311,1349115740,1349115553,100,2071,NULL,100,NULL,9000),(401,311,1349121316,1349115740,100,2081,NULL,100,NULL,9000),(401,311,1349121833,1349121316,100,2091,NULL,100,NULL,9000),(401,311,1349121886,1349121833,100,2101,NULL,100,NULL,9000),(401,311,1349121932,1349121886,100,2111,NULL,100,NULL,9000),(401,1841,-1,1355978227,504,2121,NULL,504,NULL,9000),(401,1861,1356020379,1356019162,4013,2131,NULL,4013,NULL,9000),(401,1861,1356020829,1356020379,4013,2141,NULL,4013,NULL,9000),(401,1961,-1,1356373807,601,2151,NULL,601,NULL,9000),(401,1961,1356373807,1356372905,601,2161,NULL,601,NULL,9000),(401,2011,-1,1356721874,505,2171,NULL,505,NULL,9000),(401,2071,1356990120,1356989625,511,2181,NULL,511,NULL,9000),(401,2081,1356994731,1356994599,1500,2191,NULL,1500,NULL,9000),(401,2201,1357680119,1357679580,3015,2201,NULL,3015,NULL,9000),(401,2201,1357680636,1357680119,3015,2211,NULL,3015,NULL,9000),(401,2201,1357682848,1357681824,3015,2221,NULL,3015,NULL,9000),(401,2281,-1,1358447202,602,2231,NULL,602,NULL,9000),(401,2291,-1,1358450728,603,2241,NULL,603,NULL,9000),(401,2291,1358450728,1358448498,603,2251,NULL,603,NULL,9000),(401,2301,1358540237,1358453660,3015,2261,NULL,3015,NULL,9000),(401,2301,1358541418,1358540237,3015,2271,NULL,3015,NULL,9000),(401,2301,1358542066,1358541418,3015,2281,NULL,3015,NULL,9000),(401,2301,1358543826,1358542066,3015,2291,NULL,3015,NULL,9000),(401,2481,1360910657,1360908287,101,2301,NULL,101,NULL,9000),(401,2491,1360917452,1360912217,81,2311,NULL,81,NULL,9000),(401,2501,1360917454,1360912302,82,2321,NULL,82,NULL,9000),(401,2511,1360917456,1360912393,83,2331,NULL,83,NULL,9000),(401,2521,1360917459,1360912484,84,2341,NULL,84,NULL,9000),(401,2531,1360917461,1360912584,85,2351,NULL,85,NULL,9000),(401,2541,1360917463,1360912651,87,2361,NULL,87,NULL,9000),(401,2551,1360917465,1360912753,88,2371,NULL,88,NULL,9000),(401,2561,1360917467,1360912830,90,2381,NULL,90,NULL,9000),(401,2571,1360915847,1360912904,101,2391,NULL,101,NULL,9000),(401,2601,1360917474,1360915772,1,2401,NULL,1,NULL,9000),(401,2621,1360917478,1360915938,2,2411,NULL,2,NULL,9000),(401,2631,1360917480,1360915940,3,2421,NULL,3,NULL,9000),(401,2641,1360917482,1360915942,4,2431,NULL,4,NULL,9000),(401,2651,1360917484,1360915944,5,2441,NULL,5,NULL,9000),(401,2661,1360917486,1360915946,6,2451,NULL,6,NULL,9000),(401,2671,1360917488,1360915948,7,2461,NULL,7,NULL,9000),(401,2681,1360917490,1360915951,8,2471,NULL,8,NULL,9000),(401,2691,1360917492,1360915953,9,2481,NULL,9,NULL,9000),(401,2701,1360917495,1360915955,10,2491,NULL,10,NULL,9000),(401,2711,1360917497,1360915957,11,2501,NULL,11,NULL,9000),(401,2721,1360917498,1360915959,12,2511,NULL,12,NULL,9000),(401,2731,1360917501,1360915961,13,2521,NULL,13,NULL,9000),(401,2741,1360917503,1360915964,14,2531,NULL,14,NULL,9000),(401,2751,1360917505,1360915966,15,2541,NULL,15,NULL,9000),(401,2761,1360917507,1360915968,16,2551,NULL,16,NULL,9000),(401,2771,1360917509,1360915970,17,2561,NULL,17,NULL,9000),(401,2781,1360917511,1360915972,18,2571,NULL,18,NULL,9000),(401,2791,1360917513,1360915974,19,2581,NULL,19,NULL,9000),(401,2801,1360917515,1360915977,20,2591,NULL,20,NULL,9000),(401,2811,1360917517,1360915979,21,2601,NULL,21,NULL,9000),(401,2821,1360917520,1360915982,22,2611,NULL,22,NULL,9000),(401,2831,1360917522,1360915984,23,2621,NULL,23,NULL,9000),(401,2841,1360917524,1360915986,24,2631,NULL,24,NULL,9000),(401,2851,1360917526,1360915988,25,2641,NULL,25,NULL,9000),(401,2861,1360917528,1360915990,26,2651,NULL,26,NULL,9000),(401,2871,1360917531,1360915992,27,2661,NULL,27,NULL,9000),(401,2881,1360917533,1360915995,28,2671,NULL,28,NULL,9000),(401,2891,1360917535,1360915997,29,2681,NULL,29,NULL,9000),(401,2901,1360917537,1360915999,30,2691,NULL,30,NULL,9000),(401,2911,1360917539,1360916001,31,2701,NULL,31,NULL,9000),(401,2921,1360917541,1360916003,32,2711,NULL,32,NULL,9000),(401,2931,1360917543,1360916005,33,2721,NULL,33,NULL,9000),(401,2941,1360917545,1360916007,34,2731,NULL,34,NULL,9000),(401,2951,1360917547,1360916009,35,2741,NULL,35,NULL,9000),(401,2961,1360917549,1360916011,36,2751,NULL,36,NULL,9000),(401,2971,1360917552,1360916013,37,2761,NULL,37,NULL,9000),(401,2981,1360917554,1360916016,38,2771,NULL,38,NULL,9000),(401,2991,1360917556,1360916018,39,2781,NULL,39,NULL,9000),(401,3001,1360917558,1360916020,40,2791,NULL,40,NULL,9000),(401,3011,1360917560,1360916022,41,2801,NULL,41,NULL,9000),(401,3021,1360917562,1360916024,42,2811,NULL,42,NULL,9000),(401,3031,1360917564,1360916026,43,2821,NULL,43,NULL,9000),(401,3041,1360917567,1360916028,44,2831,NULL,44,NULL,9000),(401,3051,1360917569,1360916031,45,2841,NULL,45,NULL,9000),(401,3061,1360917571,1360916033,46,2851,NULL,46,NULL,9000),(401,3071,1360917573,1360916035,47,2861,NULL,47,NULL,9000),(401,3081,1360917575,1360916037,48,2871,NULL,48,NULL,9000),(401,3091,1360917578,1360916039,49,2881,NULL,49,NULL,9000),(401,3101,1360917580,1360916041,50,2891,NULL,50,NULL,9000),(401,3111,1360917582,1360916043,51,2901,NULL,51,NULL,9000),(401,3121,1360917584,1360916046,52,2911,NULL,52,NULL,9000),(401,3131,1360917586,1360916048,53,2921,NULL,53,NULL,9000),(401,3141,1360917588,1360916050,54,2931,NULL,54,NULL,9000),(401,3151,1360917591,1360916052,55,2941,NULL,55,NULL,9000),(401,3161,1360917593,1360916055,56,2951,NULL,56,NULL,9000),(401,3171,1360917595,1360916057,57,2961,NULL,57,NULL,9000),(401,3181,1360917597,1360916060,58,2971,NULL,58,NULL,9000),(401,3191,1360917599,1360916062,59,2981,NULL,59,NULL,9000),(401,3201,1360917601,1360916064,60,2991,NULL,60,NULL,9000),(401,3211,1360917604,1360916066,61,3001,NULL,61,NULL,9000),(401,3221,1360917606,1360916069,62,3011,NULL,62,NULL,9000),(401,3231,1360917608,1360916071,63,3021,NULL,63,NULL,9000),(401,3241,1360917610,1360916073,64,3031,NULL,64,NULL,9000),(401,3251,1360917612,1360916075,65,3041,NULL,65,NULL,9000),(401,3261,1360917614,1360916077,66,3051,NULL,66,NULL,9000),(401,3271,1360917617,1360916080,67,3061,NULL,67,NULL,9000),(401,3281,1360917618,1360916082,68,3071,NULL,68,NULL,9000),(401,3291,1360917621,1360916085,69,3081,NULL,69,NULL,9000),(401,3301,1360917623,1360916087,70,3091,NULL,70,NULL,9000),(401,3311,1360917625,1360916090,71,3101,NULL,71,NULL,9000),(401,3321,1360917627,1360916092,72,3111,NULL,72,NULL,9000),(401,3331,1360917629,1360916095,73,3121,NULL,73,NULL,9000),(401,3341,1360917631,1360916097,74,3131,NULL,74,NULL,9000),(401,3351,1360917633,1360916100,75,3141,NULL,75,NULL,9000),(401,3361,1360917635,1360916102,76,3151,NULL,76,NULL,9000),(401,3371,1360917637,1360916105,77,3161,NULL,77,NULL,9000),(401,3381,1360917639,1360916107,78,3171,NULL,78,NULL,9000),(401,3391,1360917642,1360916110,79,3181,NULL,79,NULL,9000),(401,3401,1360917644,1360916112,80,3191,NULL,80,NULL,9000),(401,3521,1360917664,1360916133,92,3201,NULL,92,NULL,9000),(401,3531,1360917666,1360916135,93,3211,NULL,93,NULL,9000),(401,3541,1360917668,1360916137,94,3221,NULL,94,NULL,9000),(401,3551,1360917670,1360916140,95,3231,NULL,95,NULL,9000),(401,3561,1360917672,1360916142,96,3241,NULL,96,NULL,9000),(401,3571,1360917674,1360916145,97,3251,NULL,97,NULL,9000),(401,3581,1360917677,1360916147,98,3261,NULL,98,NULL,9000),(401,3591,1360917679,1360916150,99,3271,NULL,99,NULL,9000),(401,3611,1360917682,1360916154,101,3281,NULL,101,NULL,9000),(401,3621,1360917685,1360916156,102,3291,NULL,102,NULL,9000),(401,3631,1360917687,1360916158,103,3301,NULL,103,NULL,9000),(401,3641,1360917688,1360916160,104,3311,NULL,104,NULL,9000),(401,3651,1360917691,1360916162,105,3321,NULL,105,NULL,9000),(401,3661,1360917693,1360916165,106,3331,NULL,106,NULL,9000),(401,3671,1360917695,1360916167,107,3341,NULL,107,NULL,9000),(401,3681,1360917697,1360916170,108,3351,NULL,108,NULL,9000),(401,3691,1361770800,1360916172,109,3361,NULL,109,NULL,9000),(401,3771,1361937883,1361937805,1001,3371,NULL,1001,NULL,9000),(401,3771,1361937910,1361937883,1001,3381,NULL,1001,NULL,9000),(401,3781,1361938050,1361937962,1001,3391,NULL,1001,NULL,9000),(401,3781,1361939674,1361938050,1001,3401,NULL,1001,NULL,9000),(401,3791,-1,1361939875,1001,3411,NULL,1001,NULL,9000),(401,3791,1361939875,1361939710,1001,3421,NULL,1001,NULL,9000),(401,4031,-1,1361993985,1002,3431,NULL,1002,NULL,9000),(411,391,1349788962,1349788421,123,3441,NULL,123,NULL,9000),(411,391,1349789186,1349788962,123,3451,NULL,123,NULL,9000),(411,391,1349789778,1349789186,123,3461,NULL,123,NULL,9000),(411,411,1351006185,1351001842,1010,3471,NULL,1010,NULL,9000),(411,421,-1,1351006847,1010,3481,NULL,1010,NULL,9000),(411,661,1352340629,1352338352,1000,3491,NULL,1000,NULL,9000),(411,2111,1357315632,1357314408,3717,3501,NULL,3717,NULL,9000),(411,2121,1357315946,1357315718,3717,3511,NULL,3717,NULL,9000),(411,2121,1357316161,1357315946,3717,3521,NULL,3717,NULL,9000),(411,2141,1357323016,1357322608,3717,3531,NULL,3717,NULL,9000),(411,2141,1357323278,1357323016,3717,3541,NULL,3717,NULL,9000),(411,2141,1357323485,1357323278,3717,3551,NULL,3717,NULL,9000),(411,2141,1357333400,1357324428,3717,3561,NULL,3717,NULL,9000),(421,11,-1,1348856534,-1,3571,NULL,-1,NULL,9000),(421,11,1348856534,1348855217,100,3581,NULL,100,NULL,9000),(421,1971,-1,1356374029,602,3591,NULL,602,NULL,9000),(421,1981,-1,1356374146,603,3601,NULL,603,NULL,9000),(421,2201,1357681175,1357680636,3015,3611,NULL,3015,NULL,9000),(421,2201,1357681824,1357681175,3015,3621,NULL,3015,NULL,9000),(421,2201,1357683366,1357682848,3015,3631,NULL,3015,NULL,9000),(421,2211,1357703817,1357701950,3015,3641,NULL,3015,NULL,9000),(431,121,-1,1348966552,107,3651,NULL,107,NULL,9000),(431,131,-1,1348966879,108,3661,NULL,108,NULL,9000),(441,1831,-1,1355974722,503,3671,NULL,503,NULL,9000),(441,1841,-1,1355978227,504,3681,NULL,504,NULL,9000),(441,1861,-1,1356020829,4013,3691,NULL,4013,NULL,9000),(441,2011,-1,1356721874,505,3701,NULL,505,NULL,9000),(451,141,-1,1348967155,109,3711,NULL,109,NULL,9000),(451,151,-1,1348967392,110,3721,NULL,110,NULL,9000),(451,1861,1356020829,1356020379,4013,3731,NULL,4013,NULL,9000),(451,2141,1357323485,1357323278,3717,3741,NULL,3717,NULL,9000),(451,2141,1357324107,1357323485,3717,3751,NULL,3717,NULL,9000),(451,2331,1359127127,1359126955,3768,3761,NULL,3768,NULL,9000),(451,2381,1359133883,1359133342,3771,3771,NULL,3771,NULL,9000),(451,2391,1359133758,1359133726,3772,3781,NULL,3772,NULL,9000),(451,2451,1360352587,1360352183,3882,3791,NULL,3882,NULL,9000),(461,3721,-1,1361459445,445,3801,NULL,445,NULL,9000),(471,11,-1,1348856534,-1,3811,NULL,-1,NULL,9000),(471,11,1348856534,1348855217,100,3821,NULL,100,NULL,9000),(471,91,-1,1348965318,104,3831,NULL,104,NULL,9000),(471,121,-1,1348966552,107,3841,NULL,107,NULL,9000),(471,171,-1,1348967880,112,3851,NULL,112,NULL,9000),(471,1731,1355775161,1355774221,4012,3861,NULL,4012,NULL,9000),(471,1981,-1,1356374146,603,3871,NULL,603,NULL,9000),(471,1991,-1,1356374296,604,3881,NULL,604,NULL,9000),(471,2201,1357680636,1357680119,3015,3891,NULL,3015,NULL,9000),(471,2201,1357681175,1357680636,3015,3901,NULL,3015,NULL,9000),(471,2201,1357683366,1357682848,3015,3911,NULL,3015,NULL,9000),(471,2301,1358540237,1358453660,3015,3921,NULL,3015,NULL,9000),(471,2461,1360458995,1360458902,508,3931,NULL,508,NULL,9000),(481,2431,1360331552,1360331540,550,3941,NULL,550,NULL,9000),(501,161,-1,1348967606,111,3951,NULL,111,NULL,9000),(501,171,-1,1348967880,112,3961,NULL,112,NULL,9000),(501,371,1349284670,1349283588,500,3971,NULL,500,NULL,9000),(501,371,1349286925,1349284670,500,3981,NULL,500,NULL,9000),(501,371,1349287611,1349286925,500,3991,NULL,500,NULL,9000),(501,571,1351889721,1351888102,200,4001,NULL,200,NULL,9000),(501,571,1351897096,1351889721,200,4011,NULL,200,NULL,9000),(501,571,1351899961,1351897096,200,4021,NULL,200,NULL,9000),(501,571,1351900878,1351899961,200,4031,NULL,200,NULL,9000),(501,571,1352312647,1351900878,200,4041,NULL,200,NULL,9000),(511,1811,-1,1361930963,502,4051,NULL,502,NULL,9000),(511,1811,1361930963,1355886113,502,4061,NULL,502,NULL,9000),(511,1831,-1,1355974722,503,4071,NULL,503,NULL,9000),(521,51,-1,1361931032,100,4081,NULL,100,NULL,9000),(521,51,1361931032,1348963869,100,4091,NULL,100,NULL,9000),(521,141,-1,1348967155,109,4101,NULL,109,NULL,9000),(521,161,-1,1348967606,111,4111,NULL,111,NULL,9000),(531,301,1349112881,1349112858,66,4121,NULL,66,NULL,9000),(531,321,-1,1361930245,101,4131,NULL,101,NULL,9000),(531,321,1361930245,1349115872,101,4141,NULL,101,NULL,9000),(531,2271,-1,1358196664,642,4151,NULL,642,NULL,9000),(551,361,1349271255,1349269025,101,4161,NULL,101,NULL,9000),(551,361,1349271454,1349271255,101,4171,NULL,101,NULL,9000),(551,361,1349271885,1349271454,101,4181,NULL,101,NULL,9000),(551,361,1352405011,1349271885,101,4191,NULL,101,NULL,9000),(551,371,-1,1361930477,444,4201,NULL,444,NULL,9000),(551,371,1349277633,1349272370,102,4211,NULL,102,NULL,9000),(551,371,1349283588,1349277633,102,4221,NULL,102,NULL,9000),(551,371,1349284670,1349283588,102,4231,NULL,102,NULL,9000),(551,371,1349286925,1349284670,102,4241,NULL,102,NULL,9000),(551,371,1349287611,1349286925,444,4251,NULL,444,NULL,9000),(551,371,1361930477,1349287611,444,4261,NULL,444,NULL,9000),(551,381,1349378032,1349359139,103,4271,NULL,103,NULL,9000),(551,401,1352404946,1350575652,102,4281,NULL,102,NULL,9000),(551,541,1352409782,1351187296,103,4291,NULL,103,NULL,9000),(551,541,1355752805,1352409782,103,4301,NULL,103,NULL,9000),(551,701,-1,1352402411,211,4311,NULL,211,NULL,9000),(551,711,-1,1352405331,101,4321,NULL,101,NULL,9000),(551,721,-1,1352405455,102,4331,NULL,102,NULL,9000),(551,1011,1352502421,1352501566,3109,4341,NULL,3109,NULL,9000),(551,1701,-1,1355752877,103,4351,NULL,103,NULL,9000),(551,1711,-1,1355776962,2000,4361,NULL,2000,NULL,9000),(551,1711,1355763396,1355763066,2000,4371,NULL,2000,NULL,9000),(551,1711,1355766268,1355763396,2000,4381,NULL,2000,NULL,9000),(551,1711,1355776962,1355766268,2000,4391,NULL,2000,NULL,9000),(551,2471,1361458338,1360848531,443,4401,NULL,443,NULL,9000),(551,3731,-1,1361556086,104,4411,NULL,104,NULL,9000),(561,221,1349098689,1349098624,100,4421,NULL,100,NULL,9000),(561,221,1349101402,1349098689,100,4431,NULL,100,NULL,9000),(571,41,1348962908,1348961591,-1,4441,NULL,-1,NULL,9000),(571,81,-1,1349108611,103,4451,NULL,103,NULL,9000),(571,81,1349108611,1348965005,103,4461,NULL,103,NULL,9000),(571,91,-1,1348965318,104,4471,NULL,104,NULL,9000),(571,281,-1,1349109657,117,4481,NULL,117,NULL,9000),(571,291,1349112329,1349112223,30,4491,NULL,30,NULL,9000),(571,371,1349286925,1349284670,500,4501,NULL,500,NULL,9000),(571,371,1349287611,1349286925,500,4511,NULL,500,NULL,9000),(571,1011,1352502421,1352501566,3109,4521,NULL,3109,NULL,9000),(571,1711,1355766268,1355763396,100,4531,NULL,100,NULL,9000),(571,1721,-1,1355764551,200,4541,NULL,200,NULL,9000),(571,1991,-1,1356374296,604,4551,NULL,604,NULL,9000),(571,2001,-1,1356377554,605,4561,NULL,605,NULL,9000),(571,2071,1356990120,1356989625,511,4571,NULL,511,NULL,9000),(571,2081,1356994731,1356994599,1500,4581,NULL,1500,NULL,9000),(571,2421,1360127704,1360127612,505,4591,NULL,505,NULL,9000),(571,4031,-1,1361993985,201,4601,NULL,201,NULL,9000),(581,981,1352844591,1352844422,500,4611,NULL,500,NULL,9000),(581,991,1353518490,1352844667,500,4621,NULL,500,NULL,9000),(591,1,1348877078,1348842871,100,4631,NULL,100,NULL,9000),(591,1,1348877098,1348877078,100,4641,NULL,100,NULL,9000),(591,31,1348877301,1348877239,100,4651,NULL,100,NULL,9000),(591,31,1348877315,1348877301,100,4661,NULL,100,NULL,9000),(591,61,-1,1348964241,101,4671,NULL,101,NULL,9000),(591,281,-1,1349109657,117,4681,NULL,117,NULL,9000),(591,341,1349265546,1349265509,111,4691,NULL,111,NULL,9000),(591,1711,1355776962,1355766268,102,4701,NULL,102,NULL,9000),(591,1721,-1,1355764551,100,4711,NULL,100,NULL,9000),(591,1731,1355775161,1355774221,4012,4721,NULL,4012,NULL,9000),(591,2461,1360458995,1360458902,508,4731,NULL,508,NULL,9000),(601,341,1349265546,1349265509,3434,4741,NULL,3434,NULL,9000),(611,1,1348877078,1348842871,100,4751,NULL,100,NULL,9000),(611,1,1348877098,1348877078,100,4761,NULL,100,NULL,9000),(611,31,1348877301,1348877239,100,4771,NULL,100,NULL,9000),(611,31,1348877315,1348877301,100,4781,NULL,100,NULL,9000),(611,61,-1,1348964241,101,4791,NULL,101,NULL,9000),(611,101,-1,1348965714,105,4801,NULL,105,NULL,9000),(611,111,-1,1348965931,106,4811,NULL,106,NULL,9000),(611,1661,1355723578,1355723536,3005,4821,NULL,3005,NULL,9000),(611,1681,1355723732,1355723636,3005,4831,NULL,3005,NULL,9000),(611,1691,1355723985,1355723789,4012,4841,NULL,4012,NULL,9000),(621,491,1351022464,1351022071,1010,4851,NULL,1010,NULL,9000),(621,501,1351022680,1351022566,1010,4861,NULL,1010,NULL,9000),(621,511,1351023075,1351022874,1010,4871,NULL,1010,NULL,9000),(621,521,1351027009,1351026394,1010,4881,NULL,1010,NULL,9000),(621,531,1352295257,1351027609,1010,4891,NULL,1010,NULL,9000),(621,611,-1,1361659666,1010,4901,NULL,1010,NULL,9000),(621,611,1361659665,1352299135,1010,4911,NULL,1010,NULL,9000),(621,2021,1359556515,1359554761,1008,4921,NULL,1008,NULL,9000),(621,2021,1359571455,1359570016,1008,4931,NULL,1008,NULL,9000),(621,2021,1360006189,1360004101,1008,4941,NULL,1008,NULL,9000),(621,2311,-1,1358960571,1434,4951,NULL,1434,NULL,9000),(621,2431,1360331552,1360331540,540,4961,NULL,540,NULL,9000),(621,3801,-1,1361988667,1702,4971,NULL,1702,NULL,9000),(631,21,1349101364,1348857517,-1,4981,NULL,-1,NULL,9000),(631,231,1349106919,1349106722,100,4991,NULL,100,NULL,9000),(641,21,1349101364,1348857517,-1,5001,NULL,-1,NULL,9000),(641,101,-1,1348965714,105,5011,NULL,105,NULL,9000),(641,201,-1,1348968647,115,5021,NULL,115,NULL,9000),(641,311,1349115092,1349114669,100,5031,NULL,100,NULL,9000),(641,571,1351900878,1351899961,201,5041,NULL,201,NULL,9000),(641,571,1352312647,1351900878,201,5051,NULL,201,NULL,9000),(641,1631,-1,1354911700,202,5061,NULL,202,NULL,9000),(641,2421,1360127704,1360127612,505,5071,NULL,505,NULL,9000),(651,251,1349112733,1349106993,100,5081,NULL,100,NULL,9000),(651,251,1349114627,1349112733,100,5091,NULL,100,NULL,9000),(651,311,-1,1349121932,100,5101,NULL,100,NULL,9000),(651,311,1349115533,1349115092,100,5111,NULL,100,NULL,9000),(651,311,1349115553,1349115533,100,5121,NULL,100,NULL,9000),(651,311,1349115740,1349115553,100,5131,NULL,100,NULL,9000),(651,311,1349121316,1349115740,100,5141,NULL,100,NULL,9000),(651,311,1349121833,1349121316,100,5151,NULL,100,NULL,9000),(651,311,1349121886,1349121833,100,5161,NULL,100,NULL,9000),(651,311,1349121932,1349121886,100,5171,NULL,100,NULL,9000),(661,1031,1352508259,1352508221,1000,5181,NULL,1000,NULL,9000),(661,3801,-1,1361988667,1702,5191,NULL,1702,NULL,9000),(671,1931,1356024756,1356024108,3963,5201,NULL,3963,NULL,9000),(671,2331,1359127127,1359126955,3768,5211,NULL,3768,NULL,9000),(671,2381,1359133883,1359133342,3771,5221,NULL,3771,NULL,9000),(671,2391,1359133758,1359133726,3772,5231,NULL,3772,NULL,9000),(671,2451,1360352587,1360352183,3882,5241,NULL,3882,NULL,9000),(681,381,1349378032,1349359139,103,5251,NULL,103,NULL,9000),(681,571,1351889721,1351888102,3003,5261,NULL,3003,NULL,9000),(681,571,1351897096,1351889721,200,5271,NULL,200,NULL,9000),(681,571,1351899961,1351897096,201,5281,NULL,201,NULL,9000),(681,571,1352312647,1351900878,201,5291,NULL,201,NULL,9000),(681,581,1352731859,1352139235,3006,5301,NULL,3006,NULL,9000),(681,941,1352500095,1352499237,3007,5311,NULL,3007,NULL,9000),(681,1351,1352746047,1352744467,3006,5321,NULL,3006,NULL,9000),(681,1431,1353519052,1352772913,609,5331,NULL,609,NULL,9000),(681,1481,1354647601,1354638445,1000,5341,NULL,1000,NULL,9000),(681,1491,-1,1361929111,201,5351,NULL,201,NULL,9000),(681,1491,1360125490,1354649958,201,5361,NULL,201,NULL,9000),(681,1491,1360125530,1360125490,201,5371,NULL,201,NULL,9000),(681,1491,1360125558,1360125530,201,5381,NULL,201,NULL,9000),(681,1491,1360125823,1360125558,201,5391,NULL,201,NULL,9000),(681,1491,1361929111,1360125823,201,5401,NULL,201,NULL,9000),(681,1501,1354810417,1354809681,1000,5411,NULL,1000,NULL,9000),(681,1511,1354816460,1354810834,1000,5421,NULL,1000,NULL,9000),(681,1521,1354817652,1354817211,1000,5431,NULL,1000,NULL,9000),(681,1531,1357918870,1354818197,1000,5441,NULL,1000,NULL,9000),(681,1541,1354823082,1354822717,1001,5451,NULL,1001,NULL,9000),(681,1551,1354824301,1354823220,2191,5461,NULL,2191,NULL,9000),(681,1561,1354824987,1354824485,2191,5471,NULL,2191,NULL,9000),(681,1571,1354826701,1354825296,2191,5481,NULL,2191,NULL,9000),(681,1631,-1,1354911700,202,5491,NULL,202,NULL,9000),(681,1641,-1,1355341857,203,5501,NULL,203,NULL,9000),(681,2021,-1,1360006189,1008,5511,NULL,1008,NULL,9000),(681,2021,1359554761,1356977686,1008,5521,NULL,1008,NULL,9000),(681,2021,1359556515,1359554761,1008,5531,NULL,1008,NULL,9000),(681,2021,1359570016,1359556515,1008,5541,NULL,1008,NULL,9000),(681,2021,1359571455,1359570016,1008,5551,NULL,1008,NULL,9000),(681,2021,1360002360,1359571455,1008,5561,NULL,1008,NULL,9000),(681,2021,1360002398,1360002360,1008,5571,NULL,1008,NULL,9000),(681,2021,1360004101,1360002398,1008,5581,NULL,1008,NULL,9000),(681,2021,1360006189,1360004101,1008,5591,NULL,1008,NULL,9000),(681,2031,-1,1356977758,1009,5601,NULL,1009,NULL,9000),(681,2041,-1,1360005139,1108,5611,NULL,1108,NULL,9000),(681,2041,1356977919,1356977816,1109,5621,NULL,1109,NULL,9000),(681,2041,1360005139,1356977919,1108,5631,NULL,1108,NULL,9000),(681,2051,-1,1356977991,1109,5641,NULL,1109,NULL,9000),(681,2061,-1,1356978636,1110,5651,NULL,1110,NULL,9000),(681,2181,1357659408,1357658428,3005,5661,NULL,3005,NULL,9000),(691,1661,1355723536,1355722365,3105,5671,NULL,3105,NULL,9000),(691,1791,-1,1355783636,501,5681,NULL,501,NULL,9000),(691,2201,1357680119,1357679580,3015,5691,NULL,3015,NULL,9000),(691,2301,1358541418,1358540237,3015,5701,NULL,3015,NULL,9000),(691,2301,1358542066,1358541418,3015,5711,NULL,3015,NULL,9000),(691,2411,1360125382,1360125242,3555,5721,NULL,3555,NULL,9000),(691,3771,1361937883,1361937805,1001,5731,NULL,1001,NULL,9000),(691,3771,1361937910,1361937883,1001,5741,NULL,1001,NULL,9000),(691,3781,1361938050,1361937962,1001,5751,NULL,1001,NULL,9000),(691,3781,1361939674,1361938050,1001,5761,NULL,1001,NULL,9000),(691,3791,-1,1361939875,1001,5771,NULL,1001,NULL,9000),(691,3791,1361939875,1361939710,1001,5781,NULL,1001,NULL,9000),(701,71,1349101352,1348964684,102,5791,NULL,102,NULL,9000),(701,111,-1,1348965931,106,5801,NULL,106,NULL,9000),(701,201,-1,1348968647,115,5811,NULL,115,NULL,9000),(701,261,-1,1349109341,102,5821,NULL,102,NULL,9000),(701,501,1351022680,1351022566,1010,5831,NULL,1010,NULL,9000),(701,511,1351023075,1351022874,1010,5841,NULL,1010,NULL,9000),(701,521,1351027009,1351026394,1010,5851,NULL,1010,NULL,9000),(701,531,1352295257,1351027609,1010,5861,NULL,1010,NULL,9000),(701,611,-1,1361659666,1010,5871,NULL,1010,NULL,9000),(701,611,1361659665,1352299135,1010,5881,NULL,1010,NULL,9000),(701,661,1352340629,1352338352,1000,5891,NULL,1000,NULL,9000),(701,1801,1355884330,1355883867,555,5901,NULL,555,NULL,9000),(701,2021,-1,1360006189,1008,5911,NULL,1008,NULL,9000),(701,2021,1360002398,1360002360,1008,5921,NULL,1008,NULL,9000),(701,2021,1360004101,1360002398,1008,5931,NULL,1008,NULL,9000),(701,2021,1360006189,1360004101,1008,5941,NULL,1008,NULL,9000),(701,2041,-1,1360005139,1108,5951,NULL,1108,NULL,9000),(701,2181,1357659408,1357658428,3005,5961,NULL,3005,NULL,9000),(701,2301,1358543826,1358542066,3015,5971,NULL,3015,NULL,9000),(701,2311,-1,1358960571,1333,5981,NULL,1333,NULL,9000),(701,2441,1360340126,1360339654,3160,5991,NULL,3160,NULL,9000),(711,491,1351022464,1351022071,1010,6001,NULL,1010,NULL,9000),(721,3751,-1,1361931408,100,6011,NULL,100,NULL,9000),(721,3751,1361931408,1361770853,100,6021,NULL,100,NULL,9000),(741,1591,1354892940,1354892617,3005,6031,NULL,3005,NULL,9000),(741,1601,-1,1354897065,3005,6041,NULL,3005,NULL,9000),(741,1641,-1,1355341857,203,6051,NULL,203,NULL,9000),(741,2281,1358447202,1358446319,601,6061,NULL,601,NULL,9000),(751,41,1348962908,1348961591,-1,6071,NULL,-1,NULL,9000),(751,51,-1,1361931032,100,6081,NULL,100,NULL,9000),(751,51,1361931032,1348963869,100,6091,NULL,100,NULL,9000),(751,71,1349101352,1348964684,102,6101,NULL,102,NULL,9000),(751,81,-1,1349108611,103,6111,NULL,103,NULL,9000),(751,81,1349108611,1348965005,103,6121,NULL,103,NULL,9000),(751,261,-1,1349109341,102,6131,NULL,102,NULL,9000),(751,1661,1355723536,1355722365,3105,6141,NULL,3105,NULL,9000),(751,1661,1355723578,1355723536,3005,6151,NULL,3005,NULL,9000),(751,1681,1355723732,1355723636,3005,6161,NULL,3005,NULL,9000),(751,1691,1355723985,1355723789,4012,6171,NULL,4012,NULL,9000),(751,1791,-1,1355783636,501,6181,NULL,501,NULL,9000),(751,1801,1355884330,1355883867,555,6191,NULL,555,NULL,9000),(751,1811,-1,1361930963,502,6201,NULL,502,NULL,9000),(751,1811,1361930963,1355886113,502,6211,NULL,502,NULL,9000),(751,1861,1356020379,1356019162,4013,6221,NULL,4013,NULL,9000),(751,2001,-1,1356377554,605,6231,NULL,605,NULL,9000),(751,2281,-1,1358447202,602,6241,NULL,602,NULL,9000),(751,2411,1360125382,1360125242,3555,6251,NULL,3555,NULL,9000),(761,391,1349788962,1349788421,123,6261,NULL,123,NULL,9000),(761,391,1349789186,1349788962,123,6271,NULL,123,NULL,9000),(761,391,1349789778,1349789186,123,6281,NULL,123,NULL,9000),(761,661,1352340629,1352338352,1000,6291,NULL,1000,NULL,9000),(761,1481,1354647601,1354638445,1000,6301,NULL,1000,NULL,9000),(761,1501,1354810417,1354809681,1000,6311,NULL,1000,NULL,9000),(761,1511,1354816460,1354810834,1000,6321,NULL,1000,NULL,9000),(761,1521,1354817652,1354817211,1000,6331,NULL,1000,NULL,9000),(761,1531,1357918870,1354818197,1000,6341,NULL,1000,NULL,9000),(761,1541,1354823082,1354822717,1001,6351,NULL,1001,NULL,9000),(761,1551,1354824301,1354823220,2191,6361,NULL,2191,NULL,9000),(761,1561,1354824987,1354824485,2191,6371,NULL,2191,NULL,9000),(761,1571,1354826701,1354825296,2191,6381,NULL,2191,NULL,9000),(761,1581,1354891957,1354891574,3005,6391,NULL,3005,NULL,9000),(761,1591,1354892940,1354892617,3005,6401,NULL,3005,NULL,9000),(761,1601,-1,1354897065,3005,6411,NULL,3005,NULL,9000),(761,1671,-1,1355723085,4091,6421,NULL,4091,NULL,9000),(761,1671,-1,1355723085,4092,6431,NULL,4092,NULL,9000),(761,2261,-1,1361931308,1000,6441,NULL,1000,NULL,9000),(761,2261,1361931308,1357918922,1000,6451,NULL,1000,NULL,9000),(781,411,1351006185,1351001842,1010,6461,NULL,1010,NULL,9000),(781,421,-1,1351006847,1010,6471,NULL,1010,NULL,9000),(781,2141,1357323016,1357322608,3717,6481,NULL,3717,NULL,9000),(781,2141,1357323278,1357323016,3717,6491,NULL,3717,NULL,9000),(781,2141,1357324107,1357323485,3717,6501,NULL,3717,NULL,9000),(781,2141,1357324428,1357324107,3717,6511,NULL,3717,NULL,9000),(781,2291,1358450728,1358448498,603,6521,NULL,603,NULL,9000),(791,231,1349106919,1349106722,100,6531,NULL,100,NULL,9000),(791,1031,1352508259,1352508221,1500,6541,NULL,1500,NULL,9000),(791,1181,1352679692,1352678445,3007,6551,NULL,3007,NULL,9000),(791,1251,1353289261,1352683676,3007,6561,NULL,3007,NULL,9000),(791,1271,1353250381,1352731240,3005,6571,NULL,3005,NULL,9000),(791,3751,-1,1361931408,100,6581,NULL,100,NULL,9000),(791,3751,1361931408,1361770853,100,6591,NULL,100,NULL,9000),(801,131,-1,1348966879,108,6601,NULL,108,NULL,9000),(801,181,-1,1348968098,113,6611,NULL,113,NULL,9000),(801,211,-1,1348968857,116,6621,NULL,116,NULL,9000),(801,221,1349098689,1349098624,100,6631,NULL,100,NULL,9000),(801,221,1349101402,1349098689,100,6641,NULL,100,NULL,9000),(801,251,1349112733,1349106993,100,6651,NULL,100,NULL,9000),(801,581,1352731859,1352139235,3006,6661,NULL,3006,NULL,9000),(801,941,1352500095,1352499237,3007,6671,NULL,3007,NULL,9000),(801,1351,1352746047,1352744467,3006,6681,NULL,3006,NULL,9000),(801,1961,-1,1356373807,601,6691,NULL,601,NULL,9000),(801,1961,1356373807,1356372905,601,6701,NULL,601,NULL,9000),(801,1971,-1,1356374029,602,6711,NULL,602,NULL,9000),(801,2201,1357681824,1357681175,3015,6721,NULL,3015,NULL,9000),(801,2201,1357682848,1357681824,3015,6731,NULL,3015,NULL,9000),(801,2211,1357703817,1357701950,3015,6741,NULL,3015,NULL,9000),(801,2291,-1,1358450728,603,6751,NULL,603,NULL,9000),(5591,1271,1353250381,1352731240,3807,6761,NULL,3807,NULL,9000),(20911,1181,1352679692,1352678445,612,6771,NULL,612,NULL,9000),(20911,1251,1353289261,1352683676,612,6781,NULL,612,NULL,9000),(20911,1481,1354647601,1354638445,609,6791,NULL,609,NULL,9000),(20911,1501,1354810417,1354809681,609,6801,NULL,609,NULL,9000),(20911,1511,1354816460,1354810834,609,6811,NULL,609,NULL,9000),(20911,1521,1354817652,1354817211,617,6821,NULL,617,NULL,9000),(29161,1011,1352502421,1352501566,3109,6831,NULL,3109,NULL,9000),(29431,1591,1354892940,1354892617,3005,6841,NULL,3005,NULL,9000),(29771,1261,1353518964,1352696879,3107,6851,NULL,3107,NULL,9000),(29791,1581,1354891957,1354891574,3005,6861,NULL,3005,NULL,9000),(29961,1601,-1,1354897065,3005,6871,NULL,3005,NULL,9000),(30321,941,1352500095,1352499237,3007,6881,NULL,3007,NULL,9000),(30321,1531,1357918870,1354818197,3105,6891,NULL,3105,NULL,9000),(30321,1541,1354823082,1354822717,3005,6901,NULL,3005,NULL,9000),(30321,1551,1354824301,1354823220,2899,6911,NULL,2899,NULL,9000),(30321,1561,1354824987,1354824485,2899,6921,NULL,2899,NULL,9000),(30321,1571,1354826701,1354825296,2899,6931,NULL,2899,NULL,9000),(31211,1931,1356024756,1356024108,3963,6941,NULL,3963,NULL,9000),(31211,2331,1359127127,1359126955,3768,6951,NULL,3768,NULL,9000),(31211,2381,1359133883,1359133342,3771,6961,NULL,3771,NULL,9000),(31211,2451,1360352587,1360352183,3882,6971,NULL,3882,NULL,9000),(45561,1821,1355950700,1355943866,3717,6981,NULL,3717,NULL,9000),(45561,1821,1355952280,1355950700,3717,6991,NULL,3717,NULL,9000),(45561,1851,1356014361,1356010629,3717,7001,NULL,3717,NULL,9000),(45561,1871,1356021622,1356021045,3717,7011,NULL,3717,NULL,9000),(45561,1941,1356041095,1356040284,3717,7021,NULL,3717,NULL,9000),(45561,1951,1356102805,1356102505,3717,7031,NULL,3717,NULL,9000),(45561,2091,1357144404,1357143727,3717,7041,NULL,3717,NULL,9000),(45561,2101,1357166175,1357165008,3717,7051,NULL,3717,NULL,9000),(45561,2121,1357315946,1357315718,3717,7061,NULL,3717,NULL,9000),(45561,2121,1357316161,1357315946,3717,7071,NULL,3717,NULL,9000),(45561,2131,1357322384,1357322199,3717,7081,NULL,3717,NULL,9000),(45561,2131,1357322540,1357322384,3717,7091,NULL,3717,NULL,9000),(45561,2151,1357334732,1357334376,3717,7101,NULL,3717,NULL,9000),(45561,2161,1357336400,1357335907,3717,7111,NULL,3717,NULL,9000),(45571,2171,1357606279,1357605577,3717,7121,NULL,3717,NULL,9000),(45571,2251,-1,1358969894,3717,7131,NULL,3717,NULL,9000),(45571,2251,1358969413,1357856197,3717,7141,NULL,3717,NULL,9000),(45571,2251,1358969894,1358969413,3717,7151,NULL,3717,NULL,9000),(45571,4171,-1,1362091612,1750,7161,NULL,1750,NULL,9000),(45581,1821,1355950700,1355943866,3717,7171,NULL,3717,NULL,9000),(45581,1821,1355952280,1355950700,3717,7181,NULL,3717,NULL,9000),(45581,1851,1356014361,1356010629,3717,7191,NULL,3717,NULL,9000),(45581,1871,1356021622,1356021045,3717,7201,NULL,3717,NULL,9000),(45581,1941,1356041095,1356040284,3717,7211,NULL,3717,NULL,9000),(45581,1951,1356102805,1356102505,3717,7221,NULL,3717,NULL,9000),(45581,2101,1357166175,1357165008,3717,7231,NULL,3717,NULL,9000),(45581,2111,1357315632,1357314408,3717,7241,NULL,3717,NULL,9000),(45581,2161,1357336400,1357335907,3717,7251,NULL,3717,NULL,9000),(45591,2091,1357144404,1357143727,3717,7261,NULL,3717,NULL,9000),(45591,2131,1357322384,1357322199,3717,7271,NULL,3717,NULL,9000),(45591,2131,1357322540,1357322384,3717,7281,NULL,3717,NULL,9000),(45591,2151,1357334732,1357334376,3717,7291,NULL,3717,NULL,9000),(45591,2171,1357606279,1357605577,3717,7301,NULL,3717,NULL,9000),(45591,2231,1357849505,1357828819,3717,7311,NULL,3717,NULL,9000),(45591,2241,1358969497,1357849764,3717,7321,NULL,3717,NULL,9000),(45591,2241,1358969804,1358969497,3717,7331,NULL,3717,NULL,9000),(45591,2241,1358970629,1358969804,3717,7341,NULL,3717,NULL,9000),(45591,2241,1358974748,1358970629,-1,7351,NULL,-1,NULL,9000),(45601,471,1351017814,1351009560,2000,7361,NULL,2000,NULL,9000),(45601,481,1351023925,1351023757,2000,7371,NULL,2000,NULL,9000),(45601,481,1351035840,1351026930,2000,7381,NULL,2000,NULL,9000),(45601,731,1352407089,1352406988,2005,7391,NULL,2005,NULL,9000),(45601,731,1353518627,1352407089,2005,7401,NULL,2005,NULL,9000),(45601,741,1353518518,1352407184,2006,7411,NULL,2006,NULL,9000),(45601,751,1353518718,1352415653,1780,7421,NULL,1780,NULL,9000),(45601,761,1353518701,1352415759,2759,7431,NULL,2759,NULL,9000),(45601,771,1353518689,1352415874,2760,7441,NULL,2760,NULL,9000),(45601,781,1353518675,1352416138,2800,7451,NULL,2800,NULL,9000),(45601,971,1353518153,1352500865,3001,7461,NULL,3001,NULL,9000),(45601,981,1352844422,1352500991,3002,7471,NULL,3002,NULL,9000),(45601,981,1352844591,1352844422,3002,7481,NULL,3002,NULL,9000),(45601,981,1353518168,1352844591,3002,7491,NULL,3002,NULL,9000),(45601,991,1352844667,1352501086,3003,7501,NULL,3003,NULL,9000),(45601,991,1353518490,1352844667,3003,7511,NULL,3003,NULL,9000),(45601,1001,1353518184,1352501128,3004,7521,NULL,3004,NULL,9000),(45601,1041,1353518792,1352588229,1796,7531,NULL,1796,NULL,9000),(45601,1051,1353518739,1352588332,1797,7541,NULL,1797,NULL,9000),(45601,1061,1353518894,1352588414,1798,7551,NULL,1798,NULL,9000),(45601,1071,1353518882,1352588494,1799,7561,NULL,1799,NULL,9000),(45601,1081,1353518778,1352662054,1781,7571,NULL,1781,NULL,9000),(45601,1091,1353518869,1352662176,1782,7581,NULL,1782,NULL,9000),(45601,1101,1353518766,1352662313,1783,7591,NULL,1783,NULL,9000),(45601,1181,1352679692,1352678445,3007,7601,NULL,3007,NULL,9000),(45601,1251,1353289261,1352683676,3007,7611,NULL,3007,NULL,9000),(45601,1261,1352697466,1352696879,3107,7621,NULL,3107,NULL,9000),(45601,1261,1353518964,1352697466,3107,7631,NULL,3107,NULL,9000),(45601,1271,1353250381,1352731240,3005,7641,NULL,3005,NULL,9000),(45601,1291,1353518805,1352738431,1790,7651,NULL,1790,NULL,9000),(45601,1301,1353518843,1352738504,1791,7661,NULL,1791,NULL,9000),(45601,1311,1353518856,1352738573,1792,7671,NULL,1792,NULL,9000),(45601,1321,1353518829,1352738641,1793,7681,NULL,1793,NULL,9000),(45601,1331,1353518907,1352738714,1794,7691,NULL,1794,NULL,9000),(45601,1341,1353518751,1352738786,1795,7701,NULL,1795,NULL,9000),(45601,1361,1352760378,1352755888,2008,7711,NULL,2008,NULL,9000),(45601,1361,1353518532,1352760378,2008,7721,NULL,2008,NULL,9000),(45601,1401,1352765452,1352760511,2007,7731,NULL,2007,NULL,9000),(45601,1401,1353518584,1352765452,2007,7741,NULL,2007,NULL,9000),(45601,1411,1352765381,1352760599,2756,7751,NULL,2756,NULL,9000),(45601,1411,1352846795,1352765381,2756,7761,NULL,2756,NULL,9000),(45601,1431,1353519052,1352772913,3006,7771,NULL,3006,NULL,9000),(45601,1471,1353518600,1352847241,2756,7781,NULL,2756,NULL,9000),(45611,481,1351023757,1351017921,2000,7791,NULL,2000,NULL,9000),(45611,481,1351023925,1351023757,2000,7801,NULL,2000,NULL,9000),(45611,481,1351024257,1351023925,2000,7811,NULL,2000,NULL,9000),(45611,481,1351024493,1351024257,1000,7821,NULL,1000,NULL,9000),(45611,481,1351026930,1351024493,2000,7831,NULL,2000,NULL,9000),(45611,481,1351265734,1351035840,2000,7841,NULL,2000,NULL,9000),(45611,911,1352498297,1352498153,2003,7851,NULL,2003,NULL,9000),(45611,911,1353518613,1352498297,2003,7861,NULL,2003,NULL,9000),(45611,921,1352498335,1352498225,2004,7871,NULL,2004,NULL,9000),(45611,921,1353518645,1352498335,2004,7881,NULL,2004,NULL,9000),(45621,471,1351017814,1351009560,1000,7891,NULL,1000,NULL,9000),(45621,481,1351023757,1351017921,1000,7901,NULL,1000,NULL,9000),(45621,481,1351024257,1351023925,2000,7911,NULL,2000,NULL,9000),(45621,481,1351024493,1351024257,2000,7921,NULL,2000,NULL,9000),(45621,481,1351026930,1351024493,1000,7931,NULL,1000,NULL,9000),(45621,481,1351035840,1351026930,1000,7941,NULL,1000,NULL,9000),(45621,481,1351265734,1351035840,1000,7951,NULL,1000,NULL,9000),(45621,551,1352498401,1351261932,2001,7961,NULL,2001,NULL,9000),(45621,551,1353518562,1352498401,2001,7971,NULL,2001,NULL,9000),(45621,561,1353518548,1351273606,2002,7981,NULL,2002,NULL,9000),(45641,911,1352498297,1352498153,2003,7991,NULL,2003,NULL,9000),(45641,911,1353518613,1352498297,2003,8001,NULL,2003,NULL,9000),(45641,921,1352498335,1352498225,2004,8011,NULL,2004,NULL,9000),(45641,921,1353518645,1352498335,2004,8021,NULL,2004,NULL,9000),(45651,551,1352498401,1351261932,2001,8031,NULL,2001,NULL,9000),(45651,551,1353518562,1352498401,2001,8041,NULL,2001,NULL,9000),(45651,561,1353518548,1351273606,2002,8051,NULL,2002,NULL,9000),(45661,731,1352407089,1352406988,2005,8061,NULL,2005,NULL,9000),(45661,731,1353518627,1352407089,2005,8071,NULL,2005,NULL,9000),(45661,741,1353518518,1352407184,2006,8081,NULL,2006,NULL,9000),(45661,1021,1352825498,1352501786,2761,8091,NULL,2761,NULL,9000),(45661,1021,1352848133,1352825498,2761,8101,NULL,2761,NULL,9000),(45661,1021,1354633947,1352848133,2761,8111,NULL,2761,NULL,9000),(45661,1361,1352760378,1352755888,2008,8121,NULL,2008,NULL,9000),(45661,1361,1353518532,1352760378,2008,8131,NULL,2008,NULL,9000),(45671,3831,-1,1361992261,3107,8141,NULL,3107,NULL,9000),(45671,3931,-1,1361993029,3100,8151,NULL,3100,NULL,9000),(45671,4001,-1,1361993829,3101,8161,NULL,3101,NULL,9000),(45671,4011,-1,1362144043,3103,8171,NULL,3103,NULL,9000),(45671,4011,1362144043,1361993889,3103,8181,NULL,3103,NULL,9000),(45671,4021,-1,1361993940,3106,8191,NULL,3106,NULL,9000),(45671,4041,-1,1361994109,3102,8201,NULL,3102,NULL,9000),(45671,4051,-1,1361994199,3104,8211,NULL,3104,NULL,9000),(45671,4061,-1,1361994255,3105,8221,NULL,3105,NULL,9000),(45691,1041,1353518792,1352588229,1796,8231,NULL,1796,NULL,9000),(45691,1051,1353518739,1352588332,1797,8241,NULL,1797,NULL,9000),(45691,1061,1353518894,1352588414,1798,8251,NULL,1798,NULL,9000),(45691,1071,1353518882,1352588494,1799,8261,NULL,1799,NULL,9000),(45691,1081,1353518778,1352662054,1781,8271,NULL,1781,NULL,9000),(45691,1091,1353518869,1352662176,1782,8281,NULL,1782,NULL,9000),(45691,1101,1353518766,1352662313,1783,8291,NULL,1783,NULL,9000),(45691,1291,1353518805,1352738431,1790,8301,NULL,1790,NULL,9000),(45691,1301,1353518843,1352738504,1791,8311,NULL,1791,NULL,9000),(45691,1311,1353518856,1352738573,1792,8321,NULL,1792,NULL,9000),(45691,1321,1353518829,1352738641,1793,8331,NULL,1793,NULL,9000),(45691,1331,1353518907,1352738714,1794,8341,NULL,1794,NULL,9000),(45691,1341,1353518751,1352738786,1795,8351,NULL,1795,NULL,9000),(45701,751,1353518718,1352415653,1780,8361,NULL,1780,NULL,9000),(45701,761,1353518701,1352415759,2759,8371,NULL,2759,NULL,9000),(45701,771,1353518689,1352415874,2760,8381,NULL,2760,NULL,9000),(45701,781,1353518675,1352416138,2800,8391,NULL,2800,NULL,9000),(45701,1931,1356024756,1356024108,3963,8401,NULL,3963,NULL,9000),(45711,1021,1352825498,1352501786,2761,8411,NULL,2761,NULL,9000),(45711,1021,1352848133,1352825498,2761,8421,NULL,2761,NULL,9000),(45711,1021,1354633947,1352848133,2761,8431,NULL,2761,NULL,9000),(45741,1401,1352765452,1352760511,2007,8441,NULL,2007,NULL,9000),(45741,1401,1353518584,1352765452,-1,8451,NULL,-1,NULL,9000),(45741,3841,-1,1361992319,2008,8461,NULL,2008,NULL,9000),(45741,3921,-1,1361992947,2001,8471,NULL,2001,NULL,9000),(45741,3971,-1,1361993393,2002,8481,NULL,2002,NULL,9000),(45741,4061,-1,1361994255,2003,8491,NULL,2003,NULL,9000),(45741,4071,-1,1361994302,2006,8501,NULL,2006,NULL,9000),(45741,4081,-1,1362144282,2005,8511,NULL,2005,NULL,9000),(45741,4081,1362144282,1361994356,2005,8521,NULL,2005,NULL,9000),(45741,4091,-1,1361994403,2007,8531,NULL,2007,NULL,9000),(45741,4101,-1,1361994451,2004,8541,NULL,2004,NULL,9000),(45751,1411,1352765381,1352760599,2756,8551,NULL,2756,NULL,9000),(45751,1411,1352846795,1352765381,-1,8561,NULL,-1,NULL,9000),(45751,1471,1353518600,1352847241,-1,8571,NULL,-1,NULL,9000),(45751,3811,-1,1361992120,3210,8581,NULL,3210,NULL,9000),(45751,3821,-1,1361992198,3211,8591,NULL,3211,NULL,9000),(45751,3831,-1,1361992261,3212,8601,NULL,3212,NULL,9000),(45751,3841,-1,1361992319,3216,8611,NULL,3216,NULL,9000),(45751,3851,-1,1361992378,3213,8621,NULL,3213,NULL,9000),(45751,3861,-1,1361992438,3217,8631,NULL,3217,NULL,9000),(45751,3871,-1,1362144481,3214,8641,NULL,3214,NULL,9000),(45751,3871,1362144481,1361992515,3214,8651,NULL,3214,NULL,9000),(45751,3881,-1,1361992684,3215,8661,NULL,3215,NULL,9000),(45801,2441,1360340126,1360339654,3160,8671,NULL,3160,NULL,9000),(45811,3761,1361992060,1361811066,1234,8681,NULL,1234,NULL,9000),(45811,3851,-1,1361992378,4078,8691,NULL,4078,NULL,9000),(45811,3911,-1,1361992881,4094,8701,NULL,4094,NULL,9000),(45811,3961,-1,1361993238,4093,8711,NULL,4093,NULL,9000),(45811,4041,-1,1361994109,4092,8721,NULL,4092,NULL,9000),(45811,4101,-1,1361994451,4089,8731,NULL,4089,NULL,9000),(45811,4111,-1,1361994496,4090,8741,NULL,4090,NULL,9000),(45811,4121,-1,1362144135,4091,8751,NULL,4091,NULL,9000),(45811,4121,1362144135,1361994552,4091,8761,NULL,4091,NULL,9000),(45811,4131,-1,1361994603,4088,8771,NULL,4088,NULL,9000),(45831,3821,-1,1361992199,3117,8781,NULL,3117,NULL,9000),(45831,3941,-1,1361993115,3110,8791,NULL,3110,NULL,9000),(45831,3951,-1,1361994150,3114,8801,NULL,3114,NULL,9000),(45831,3951,1361994149,1361993171,3114,8811,NULL,3114,NULL,9000),(45831,3961,-1,1361993238,3112,8821,NULL,3112,NULL,9000),(45831,3971,-1,1361993393,3115,8831,NULL,3115,NULL,9000),(45831,3981,-1,1361993442,3116,8841,NULL,3116,NULL,9000),(45831,3991,-1,1362144354,3113,8851,NULL,3113,NULL,9000),(45831,3991,1362144354,1361993526,3113,8861,NULL,3113,NULL,9000),(45831,4001,-1,1361993829,3111,8871,NULL,3111,NULL,9000),(45841,3871,-1,1362144481,3128,8881,NULL,3128,NULL,9000),(45841,3871,1362144481,1361992515,3214,8891,NULL,3214,NULL,9000),(45841,3901,-1,1362144424,3120,8901,NULL,3120,NULL,9000),(45841,3901,1362144424,1361992795,3113,8911,NULL,3113,NULL,9000),(45841,3991,-1,1362144354,3121,8921,NULL,3121,NULL,9000),(45841,3991,1362144354,1361993526,3120,8931,NULL,3120,NULL,9000),(45841,4011,-1,1362144043,3122,8941,NULL,3122,NULL,9000),(45841,4011,1362144043,1361993889,3103,8951,NULL,3103,NULL,9000),(45841,4081,-1,1362144282,3126,8961,NULL,3126,NULL,9000),(45841,4081,1362144282,1361994356,2005,8971,NULL,2005,NULL,9000),(45841,4121,-1,1362144135,3123,8981,NULL,3123,NULL,9000),(45841,4121,1362144135,1361994552,3121,8991,NULL,3121,NULL,9000),(45841,4151,-1,1362144220,3127,9001,NULL,3127,NULL,9000),(45841,4151,1362144220,1361994688,2504,9011,NULL,2504,NULL,9000),(45841,4161,-1,1362143960,3125,9021,NULL,3125,NULL,9000),(45841,4161,1362143960,1361994728,3122,9031,NULL,3122,NULL,9000),(45851,3731,-1,1361556086,2068,9041,NULL,2068,NULL,9000),(45861,3881,-1,1361992684,2050,9051,NULL,2050,NULL,9000),(45861,3891,-1,1361992748,2051,9061,NULL,2051,NULL,9000),(45861,3951,-1,1361994150,2052,9071,NULL,2052,NULL,9000),(45861,3951,1361994149,1361993171,2053,9081,NULL,2053,NULL,9000),(45861,4051,-1,1361994199,2053,9091,NULL,2053,NULL,9000),(45861,4071,-1,1361994302,2054,9101,NULL,2054,NULL,9000),(45861,4111,-1,1361994496,2055,9111,NULL,2055,NULL,9000),(45861,4141,-1,1361994643,2056,9121,NULL,2056,NULL,9000),(45861,4161,-1,1362143960,2057,9131,NULL,2057,NULL,9000),(45861,4161,1362143960,1361994728,2057,9141,NULL,2057,NULL,9000),(391,4181,1449156435,1386083827,200,10631,NULL,200,NULL,9000),(511,4181,1449156435,1386083827,2,10641,NULL,2,NULL,9000),(321,4181,1449156435,1386083827,2,10651,NULL,2,NULL,9000),(321,4182,1442517482,1435247020,4,10661,NULL,4,NULL,9000),(511,4182,1442517482,1435247020,4,10662,NULL,4,NULL,9000),(511,4182,1442517482,1435247020,5,10663,NULL,5,NULL,9000),(511,4182,1442517482,1435247020,6,10664,NULL,6,NULL,9000),(511,4182,1442517482,1435247020,7,10665,NULL,7,NULL,9000),(321,4183,-1,1443037937,4,10666,NULL,4,NULL,9000),(511,4183,-1,1443037937,4,10667,NULL,4,NULL,9000),(511,4183,-1,1443037937,5,10668,NULL,5,NULL,9000),(511,4183,-1,1443037937,6,10669,NULL,6,NULL,9000),(511,4183,-1,1443037937,7,10670,NULL,7,NULL,9000),(391,4181,-1,1449156435,200,10671,NULL,200,NULL,9000),(321,4181,-1,1449156435,2,10672,NULL,2,NULL,9000),(45791,4181,-1,1449156435,500,10673,NULL,500,NULL,9000),(501,4181,-1,1449156435,600,10674,NULL,600,NULL,9000);
+INSERT INTO `circuit_edge_interface_membership` VALUES (261,401,1352404946,1350575652,2090,1,NULL,2090,NULL,9000),(261,541,1352409782,1351187296,2495,11,NULL,2495,NULL,9000),(261,541,1355752805,1352409782,2495,21,NULL,2495,NULL,9000),(261,701,-1,1352402411,211,31,NULL,211,0,9000),(261,711,-1,1352405331,2063,41,NULL,2063,0,9000),(261,721,-1,1352405455,2048,51,NULL,2048,0,9000),(261,971,1353518153,1352500865,3001,61,NULL,3001,NULL,9000),(261,981,1352844422,1352500991,3002,71,NULL,3002,NULL,9000),(261,981,1352844591,1352844422,3002,81,NULL,3002,NULL,9000),(261,981,1353518168,1352844591,3002,91,NULL,3002,NULL,9000),(261,991,1352844667,1352501086,3003,101,NULL,3003,NULL,9000),(261,991,1353518490,1352844667,3003,111,NULL,3003,NULL,9000),(261,1001,1353518184,1352501128,3004,121,NULL,3004,NULL,9000),(261,1701,-1,1355752877,2495,131,NULL,2495,0,9000),(261,1711,-1,1355776962,2000,141,NULL,2000,0,9000),(261,1711,1355763396,1355763066,2000,151,NULL,2000,NULL,9000),(261,1711,1355766268,1355763396,2000,161,NULL,2000,NULL,9000),(261,1711,1355776962,1355766268,2000,171,NULL,2000,NULL,9000),(261,2231,1357849505,1357828819,114,181,NULL,114,NULL,9000),(261,2241,1358969497,1357849764,114,191,NULL,114,NULL,9000),(261,2241,1358969804,1358969497,114,201,NULL,114,NULL,9000),(261,2241,1358970629,1358969804,114,211,NULL,114,NULL,9000),(261,2241,1358974748,1358970629,-1,221,NULL,-1,NULL,9000),(261,3761,1361992060,1361811066,1234,231,NULL,1234,NULL,9000),(261,3811,-1,1361992120,3117,241,NULL,3117,0,9000),(261,3861,-1,1361992438,2507,251,NULL,2507,0,9000),(261,3891,-1,1361992748,3114,261,NULL,3114,0,9000),(261,3901,-1,1362144424,3113,271,NULL,3113,0,9000),(261,3901,1362144424,1361992795,3113,281,NULL,3113,NULL,9000),(261,3911,-1,1361992881,3112,291,NULL,3112,0,9000),(261,3921,-1,1361992947,3115,301,NULL,3115,0,9000),(261,3931,-1,1361993029,3111,311,NULL,3111,0,9000),(261,3941,-1,1361993115,3110,321,NULL,3110,0,9000),(261,3981,-1,1361993442,2501,331,NULL,2501,0,9000),(261,4021,-1,1361993940,2502,341,NULL,2502,0,9000),(261,4091,-1,1361994403,2056,351,NULL,2056,0,9000),(261,4131,-1,1361994603,2503,361,NULL,2503,0,9000),(261,4141,-1,1361994643,2505,371,NULL,2505,0,9000),(261,4151,-1,1362144220,2504,381,NULL,2504,0,9000),(261,4151,1362144220,1361994688,2504,391,NULL,2504,NULL,9000),(321,1261,1352697466,1352696879,3107,401,NULL,3107,NULL,9000),(321,1261,1353518964,1352697466,3107,411,NULL,3107,NULL,9000),(321,1491,-1,1361929111,201,421,NULL,201,0,9000),(321,1491,1360125490,1354649958,201,431,NULL,201,NULL,9000),(321,1491,1360125530,1360125490,201,441,NULL,201,NULL,9000),(321,1491,1360125558,1360125530,201,451,NULL,201,NULL,9000),(321,1491,1360125823,1360125558,201,461,NULL,201,NULL,9000),(321,1491,1361929111,1360125823,201,471,NULL,201,NULL,9000),(321,1581,1354891957,1354891574,3005,481,NULL,3005,NULL,9000),(321,2261,-1,1361931308,3107,491,NULL,3107,0,9000),(321,2261,1361931308,1357918922,3107,501,NULL,3107,NULL,9000),(321,2271,-1,1358196664,642,511,NULL,642,0,9000),(331,291,1349112329,1349112223,10,521,NULL,10,NULL,9000),(331,301,1349112881,1349112858,400,531,NULL,400,NULL,9000),(331,321,-1,1361930245,101,541,NULL,101,0,9000),(331,321,1361930245,1349115872,101,551,NULL,101,NULL,9000),(331,361,1349271255,1349269025,2001,561,NULL,2001,NULL,9000),(331,361,1349271454,1349271255,2001,571,NULL,2001,NULL,9000),(331,361,1349271885,1349271454,2001,581,NULL,2001,NULL,9000),(331,361,1352405011,1349271885,2001,591,NULL,2001,NULL,9000),(331,371,-1,1361930477,444,601,NULL,444,0,9000),(331,371,1349277633,1349272370,444,611,NULL,444,NULL,9000),(331,371,1349283588,1349277633,444,621,NULL,444,NULL,9000),(331,371,1349284670,1349283588,444,631,NULL,444,NULL,9000),(331,371,1349286925,1349284670,444,641,NULL,444,NULL,9000),(331,371,1349287611,1349286925,444,651,NULL,444,NULL,9000),(331,371,1361930477,1349287611,444,661,NULL,444,NULL,9000),(331,2471,1361458338,1360848531,443,671,NULL,443,NULL,9000),(331,3721,-1,1361459445,445,681,NULL,445,0,9000),(371,2021,-1,1360006189,1008,691,NULL,1008,0,9000),(371,2021,1359554761,1356977686,1008,701,NULL,1008,NULL,9000),(371,2021,1359570016,1359556515,1008,711,NULL,1008,NULL,9000),(371,2021,1359571455,1359570016,1008,721,NULL,1008,NULL,9000),(371,2021,1360002360,1359571455,1008,731,NULL,1008,NULL,9000),(371,2021,1360002398,1360002360,1008,741,NULL,1008,NULL,9000),(371,2021,1360004101,1360002398,1008,751,NULL,1008,NULL,9000),(371,2031,-1,1356977758,1009,761,NULL,1009,0,9000),(371,2041,-1,1360005139,1108,771,NULL,1108,0,9000),(371,2041,1356977919,1356977816,1108,781,NULL,1108,NULL,9000),(371,2041,1360005139,1356977919,1108,791,NULL,1108,NULL,9000),(371,2051,-1,1356977991,1109,801,NULL,1109,0,9000),(371,2061,-1,1356978636,1110,811,NULL,1110,0,9000),(371,2251,-1,1358969894,3717,821,NULL,3717,0,9000),(371,2251,1358969413,1357856197,3717,831,NULL,3717,NULL,9000),(371,2251,1358969894,1358969413,3717,841,NULL,3717,NULL,9000),(371,4171,-1,1362091612,3711,851,NULL,3711,0,9000),(381,191,-1,1348968376,114,861,NULL,114,0,9000),(381,211,-1,1348968857,116,871,NULL,116,0,9000),(381,2141,1357324428,1357324107,3717,881,NULL,3717,NULL,9000),(381,2141,1357333400,1357324428,3717,891,NULL,3717,NULL,9000),(381,2481,1360910657,1360908287,100,901,NULL,100,NULL,9000),(381,2491,1360917452,1360912217,80,911,NULL,80,NULL,9000),(381,2501,1360917454,1360912302,81,921,NULL,81,NULL,9000),(381,2511,1360917456,1360912393,83,931,NULL,83,NULL,9000),(381,2521,1360917459,1360912484,84,941,NULL,84,NULL,9000),(381,2531,1360917461,1360912584,85,951,NULL,85,NULL,9000),(381,2541,1360917463,1360912651,87,961,NULL,87,NULL,9000),(381,2551,1360917465,1360912753,88,971,NULL,88,NULL,9000),(381,2561,1360917467,1360912830,90,981,NULL,90,NULL,9000),(381,2571,1360915847,1360912904,100,991,NULL,100,NULL,9000),(381,2601,1360917474,1360915772,0,1001,NULL,0,NULL,9000),(381,2621,1360917478,1360915938,1,1011,NULL,1,NULL,9000),(381,2631,1360917480,1360915940,2,1021,NULL,2,NULL,9000),(381,2641,1360917482,1360915942,3,1031,NULL,3,NULL,9000),(381,2651,1360917484,1360915944,4,1041,NULL,4,NULL,9000),(381,2661,1360917486,1360915946,5,1051,NULL,5,NULL,9000),(381,2671,1360917488,1360915948,6,1061,NULL,6,NULL,9000),(381,2681,1360917490,1360915951,7,1071,NULL,7,NULL,9000),(381,2691,1360917492,1360915953,8,1081,NULL,8,NULL,9000),(381,2701,1360917495,1360915955,9,1091,NULL,9,NULL,9000),(381,2711,1360917497,1360915957,10,1101,NULL,10,NULL,9000),(381,2721,1360917498,1360915959,11,1111,NULL,11,NULL,9000),(381,2731,1360917501,1360915961,12,1121,NULL,12,NULL,9000),(381,2741,1360917503,1360915964,13,1131,NULL,13,NULL,9000),(381,2751,1360917505,1360915966,14,1141,NULL,14,NULL,9000),(381,2761,1360917507,1360915968,15,1151,NULL,15,NULL,9000),(381,2771,1360917509,1360915970,16,1161,NULL,16,NULL,9000),(381,2781,1360917511,1360915972,17,1171,NULL,17,NULL,9000),(381,2791,1360917513,1360915974,18,1181,NULL,18,NULL,9000),(381,2801,1360917515,1360915977,19,1191,NULL,19,NULL,9000),(381,2811,1360917517,1360915979,20,1201,NULL,20,NULL,9000),(381,2821,1360917520,1360915982,21,1211,NULL,21,NULL,9000),(381,2831,1360917522,1360915984,22,1221,NULL,22,NULL,9000),(381,2841,1360917524,1360915986,23,1231,NULL,23,NULL,9000),(381,2851,1360917526,1360915988,24,1241,NULL,24,NULL,9000),(381,2861,1360917528,1360915990,25,1251,NULL,25,NULL,9000),(381,2871,1360917531,1360915992,26,1261,NULL,26,NULL,9000),(381,2881,1360917533,1360915995,27,1271,NULL,27,NULL,9000),(381,2891,1360917535,1360915997,28,1281,NULL,28,NULL,9000),(381,2901,1360917537,1360915999,29,1291,NULL,29,NULL,9000),(381,2911,1360917539,1360916001,30,1301,NULL,30,NULL,9000),(381,2921,1360917541,1360916003,31,1311,NULL,31,NULL,9000),(381,2931,1360917543,1360916005,32,1321,NULL,32,NULL,9000),(381,2941,1360917545,1360916007,33,1331,NULL,33,NULL,9000),(381,2951,1360917547,1360916009,34,1341,NULL,34,NULL,9000),(381,2961,1360917549,1360916011,35,1351,NULL,35,NULL,9000),(381,2971,1360917552,1360916013,36,1361,NULL,36,NULL,9000),(381,2981,1360917554,1360916016,37,1371,NULL,37,NULL,9000),(381,2991,1360917556,1360916018,38,1381,NULL,38,NULL,9000),(381,3001,1360917558,1360916020,39,1391,NULL,39,NULL,9000),(381,3011,1360917560,1360916022,40,1401,NULL,40,NULL,9000),(381,3021,1360917562,1360916024,41,1411,NULL,41,NULL,9000),(381,3031,1360917564,1360916026,42,1421,NULL,42,NULL,9000),(381,3041,1360917567,1360916028,43,1431,NULL,43,NULL,9000),(381,3051,1360917569,1360916031,44,1441,NULL,44,NULL,9000),(381,3061,1360917571,1360916033,45,1451,NULL,45,NULL,9000),(381,3071,1360917573,1360916035,46,1461,NULL,46,NULL,9000),(381,3081,1360917575,1360916037,47,1471,NULL,47,NULL,9000),(381,3091,1360917578,1360916039,48,1481,NULL,48,NULL,9000),(381,3101,1360917580,1360916041,49,1491,NULL,49,NULL,9000),(381,3111,1360917582,1360916043,50,1501,NULL,50,NULL,9000),(381,3121,1360917584,1360916046,51,1511,NULL,51,NULL,9000),(381,3131,1360917586,1360916048,52,1521,NULL,52,NULL,9000),(381,3141,1360917588,1360916050,53,1531,NULL,53,NULL,9000),(381,3151,1360917591,1360916052,54,1541,NULL,54,NULL,9000),(381,3161,1360917593,1360916055,55,1551,NULL,55,NULL,9000),(381,3171,1360917595,1360916057,56,1561,NULL,56,NULL,9000),(381,3181,1360917597,1360916060,57,1571,NULL,57,NULL,9000),(381,3191,1360917599,1360916062,58,1581,NULL,58,NULL,9000),(381,3201,1360917601,1360916064,59,1591,NULL,59,NULL,9000),(381,3211,1360917604,1360916066,60,1601,NULL,60,NULL,9000),(381,3221,1360917606,1360916069,61,1611,NULL,61,NULL,9000),(381,3231,1360917608,1360916071,62,1621,NULL,62,NULL,9000),(381,3241,1360917610,1360916073,63,1631,NULL,63,NULL,9000),(381,3251,1360917612,1360916075,64,1641,NULL,64,NULL,9000),(381,3261,1360917614,1360916077,65,1651,NULL,65,NULL,9000),(381,3271,1360917617,1360916080,66,1661,NULL,66,NULL,9000),(381,3281,1360917618,1360916082,67,1671,NULL,67,NULL,9000),(381,3291,1360917621,1360916085,68,1681,NULL,68,NULL,9000),(381,3301,1360917623,1360916087,69,1691,NULL,69,NULL,9000),(381,3311,1360917625,1360916090,70,1701,NULL,70,NULL,9000),(381,3321,1360917627,1360916092,71,1711,NULL,71,NULL,9000),(381,3331,1360917629,1360916095,72,1721,NULL,72,NULL,9000),(381,3341,1360917631,1360916097,73,1731,NULL,73,NULL,9000),(381,3351,1360917633,1360916100,74,1741,NULL,74,NULL,9000),(381,3361,1360917635,1360916102,75,1751,NULL,75,NULL,9000),(381,3371,1360917637,1360916105,76,1761,NULL,76,NULL,9000),(381,3381,1360917639,1360916107,77,1771,NULL,77,NULL,9000),(381,3391,1360917642,1360916110,78,1781,NULL,78,NULL,9000),(381,3401,1360917644,1360916112,79,1791,NULL,79,NULL,9000),(381,3521,1360917664,1360916133,91,1801,NULL,91,NULL,9000),(381,3531,1360917666,1360916135,92,1811,NULL,92,NULL,9000),(381,3541,1360917668,1360916137,93,1821,NULL,93,NULL,9000),(381,3551,1360917670,1360916140,94,1831,NULL,94,NULL,9000),(381,3561,1360917672,1360916142,95,1841,NULL,95,NULL,9000),(381,3571,1360917674,1360916145,96,1851,NULL,96,NULL,9000),(381,3581,1360917677,1360916147,97,1861,NULL,97,NULL,9000),(381,3591,1360917679,1360916150,98,1871,NULL,98,NULL,9000),(381,3611,1360917682,1360916154,100,1881,NULL,100,NULL,9000),(381,3621,1360917685,1360916156,101,1891,NULL,101,NULL,9000),(381,3631,1360917687,1360916158,102,1901,NULL,102,NULL,9000),(381,3641,1360917688,1360916160,103,1911,NULL,103,NULL,9000),(381,3651,1360917691,1360916162,104,1921,NULL,104,NULL,9000),(381,3661,1360917693,1360916165,105,1931,NULL,105,NULL,9000),(381,3671,1360917695,1360916167,106,1941,NULL,106,NULL,9000),(381,3681,1360917697,1360916170,107,1951,NULL,107,NULL,9000),(381,3691,1361770800,1360916172,108,1961,NULL,108,NULL,9000),(391,1861,-1,1356020829,4013,1971,NULL,4013,0,9000),(391,2281,1358447202,1358446319,601,1981,NULL,601,NULL,9000),(401,151,-1,1348967392,110,1991,NULL,110,0,9000),(401,181,-1,1348968098,113,2001,NULL,113,0,9000),(401,191,-1,1348968376,114,2011,NULL,114,0,9000),(401,251,1349114627,1349112733,100,2021,NULL,100,NULL,9000),(401,311,-1,1349121932,100,2031,NULL,100,0,9000),(401,311,1349115092,1349114669,100,2041,NULL,100,NULL,9000),(401,311,1349115533,1349115092,100,2051,NULL,100,NULL,9000),(401,311,1349115553,1349115533,100,2061,NULL,100,NULL,9000),(401,311,1349115740,1349115553,100,2071,NULL,100,NULL,9000),(401,311,1349121316,1349115740,100,2081,NULL,100,NULL,9000),(401,311,1349121833,1349121316,100,2091,NULL,100,NULL,9000),(401,311,1349121886,1349121833,100,2101,NULL,100,NULL,9000),(401,311,1349121932,1349121886,100,2111,NULL,100,NULL,9000),(401,1841,-1,1355978227,504,2121,NULL,504,0,9000),(401,1861,1356020379,1356019162,4013,2131,NULL,4013,NULL,9000),(401,1861,1356020829,1356020379,4013,2141,NULL,4013,NULL,9000),(401,1961,-1,1356373807,601,2151,NULL,601,0,9000),(401,1961,1356373807,1356372905,601,2161,NULL,601,NULL,9000),(401,2011,-1,1356721874,505,2171,NULL,505,0,9000),(401,2071,1356990120,1356989625,511,2181,NULL,511,NULL,9000),(401,2081,1356994731,1356994599,1500,2191,NULL,1500,NULL,9000),(401,2201,1357680119,1357679580,3015,2201,NULL,3015,NULL,9000),(401,2201,1357680636,1357680119,3015,2211,NULL,3015,NULL,9000),(401,2201,1357682848,1357681824,3015,2221,NULL,3015,NULL,9000),(401,2281,-1,1358447202,602,2231,NULL,602,0,9000),(401,2291,-1,1358450728,603,2241,NULL,603,0,9000),(401,2291,1358450728,1358448498,603,2251,NULL,603,NULL,9000),(401,2301,1358540237,1358453660,3015,2261,NULL,3015,NULL,9000),(401,2301,1358541418,1358540237,3015,2271,NULL,3015,NULL,9000),(401,2301,1358542066,1358541418,3015,2281,NULL,3015,NULL,9000),(401,2301,1358543826,1358542066,3015,2291,NULL,3015,NULL,9000),(401,2481,1360910657,1360908287,101,2301,NULL,101,NULL,9000),(401,2491,1360917452,1360912217,81,2311,NULL,81,NULL,9000),(401,2501,1360917454,1360912302,82,2321,NULL,82,NULL,9000),(401,2511,1360917456,1360912393,83,2331,NULL,83,NULL,9000),(401,2521,1360917459,1360912484,84,2341,NULL,84,NULL,9000),(401,2531,1360917461,1360912584,85,2351,NULL,85,NULL,9000),(401,2541,1360917463,1360912651,87,2361,NULL,87,NULL,9000),(401,2551,1360917465,1360912753,88,2371,NULL,88,NULL,9000),(401,2561,1360917467,1360912830,90,2381,NULL,90,NULL,9000),(401,2571,1360915847,1360912904,101,2391,NULL,101,NULL,9000),(401,2601,1360917474,1360915772,1,2401,NULL,1,NULL,9000),(401,2621,1360917478,1360915938,2,2411,NULL,2,NULL,9000),(401,2631,1360917480,1360915940,3,2421,NULL,3,NULL,9000),(401,2641,1360917482,1360915942,4,2431,NULL,4,NULL,9000),(401,2651,1360917484,1360915944,5,2441,NULL,5,NULL,9000),(401,2661,1360917486,1360915946,6,2451,NULL,6,NULL,9000),(401,2671,1360917488,1360915948,7,2461,NULL,7,NULL,9000),(401,2681,1360917490,1360915951,8,2471,NULL,8,NULL,9000),(401,2691,1360917492,1360915953,9,2481,NULL,9,NULL,9000),(401,2701,1360917495,1360915955,10,2491,NULL,10,NULL,9000),(401,2711,1360917497,1360915957,11,2501,NULL,11,NULL,9000),(401,2721,1360917498,1360915959,12,2511,NULL,12,NULL,9000),(401,2731,1360917501,1360915961,13,2521,NULL,13,NULL,9000),(401,2741,1360917503,1360915964,14,2531,NULL,14,NULL,9000),(401,2751,1360917505,1360915966,15,2541,NULL,15,NULL,9000),(401,2761,1360917507,1360915968,16,2551,NULL,16,NULL,9000),(401,2771,1360917509,1360915970,17,2561,NULL,17,NULL,9000),(401,2781,1360917511,1360915972,18,2571,NULL,18,NULL,9000),(401,2791,1360917513,1360915974,19,2581,NULL,19,NULL,9000),(401,2801,1360917515,1360915977,20,2591,NULL,20,NULL,9000),(401,2811,1360917517,1360915979,21,2601,NULL,21,NULL,9000),(401,2821,1360917520,1360915982,22,2611,NULL,22,NULL,9000),(401,2831,1360917522,1360915984,23,2621,NULL,23,NULL,9000),(401,2841,1360917524,1360915986,24,2631,NULL,24,NULL,9000),(401,2851,1360917526,1360915988,25,2641,NULL,25,NULL,9000),(401,2861,1360917528,1360915990,26,2651,NULL,26,NULL,9000),(401,2871,1360917531,1360915992,27,2661,NULL,27,NULL,9000),(401,2881,1360917533,1360915995,28,2671,NULL,28,NULL,9000),(401,2891,1360917535,1360915997,29,2681,NULL,29,NULL,9000),(401,2901,1360917537,1360915999,30,2691,NULL,30,NULL,9000),(401,2911,1360917539,1360916001,31,2701,NULL,31,NULL,9000),(401,2921,1360917541,1360916003,32,2711,NULL,32,NULL,9000),(401,2931,1360917543,1360916005,33,2721,NULL,33,NULL,9000),(401,2941,1360917545,1360916007,34,2731,NULL,34,NULL,9000),(401,2951,1360917547,1360916009,35,2741,NULL,35,NULL,9000),(401,2961,1360917549,1360916011,36,2751,NULL,36,NULL,9000),(401,2971,1360917552,1360916013,37,2761,NULL,37,NULL,9000),(401,2981,1360917554,1360916016,38,2771,NULL,38,NULL,9000),(401,2991,1360917556,1360916018,39,2781,NULL,39,NULL,9000),(401,3001,1360917558,1360916020,40,2791,NULL,40,NULL,9000),(401,3011,1360917560,1360916022,41,2801,NULL,41,NULL,9000),(401,3021,1360917562,1360916024,42,2811,NULL,42,NULL,9000),(401,3031,1360917564,1360916026,43,2821,NULL,43,NULL,9000),(401,3041,1360917567,1360916028,44,2831,NULL,44,NULL,9000),(401,3051,1360917569,1360916031,45,2841,NULL,45,NULL,9000),(401,3061,1360917571,1360916033,46,2851,NULL,46,NULL,9000),(401,3071,1360917573,1360916035,47,2861,NULL,47,NULL,9000),(401,3081,1360917575,1360916037,48,2871,NULL,48,NULL,9000),(401,3091,1360917578,1360916039,49,2881,NULL,49,NULL,9000),(401,3101,1360917580,1360916041,50,2891,NULL,50,NULL,9000),(401,3111,1360917582,1360916043,51,2901,NULL,51,NULL,9000),(401,3121,1360917584,1360916046,52,2911,NULL,52,NULL,9000),(401,3131,1360917586,1360916048,53,2921,NULL,53,NULL,9000),(401,3141,1360917588,1360916050,54,2931,NULL,54,NULL,9000),(401,3151,1360917591,1360916052,55,2941,NULL,55,NULL,9000),(401,3161,1360917593,1360916055,56,2951,NULL,56,NULL,9000),(401,3171,1360917595,1360916057,57,2961,NULL,57,NULL,9000),(401,3181,1360917597,1360916060,58,2971,NULL,58,NULL,9000),(401,3191,1360917599,1360916062,59,2981,NULL,59,NULL,9000),(401,3201,1360917601,1360916064,60,2991,NULL,60,NULL,9000),(401,3211,1360917604,1360916066,61,3001,NULL,61,NULL,9000),(401,3221,1360917606,1360916069,62,3011,NULL,62,NULL,9000),(401,3231,1360917608,1360916071,63,3021,NULL,63,NULL,9000),(401,3241,1360917610,1360916073,64,3031,NULL,64,NULL,9000),(401,3251,1360917612,1360916075,65,3041,NULL,65,NULL,9000),(401,3261,1360917614,1360916077,66,3051,NULL,66,NULL,9000),(401,3271,1360917617,1360916080,67,3061,NULL,67,NULL,9000),(401,3281,1360917618,1360916082,68,3071,NULL,68,NULL,9000),(401,3291,1360917621,1360916085,69,3081,NULL,69,NULL,9000),(401,3301,1360917623,1360916087,70,3091,NULL,70,NULL,9000),(401,3311,1360917625,1360916090,71,3101,NULL,71,NULL,9000),(401,3321,1360917627,1360916092,72,3111,NULL,72,NULL,9000),(401,3331,1360917629,1360916095,73,3121,NULL,73,NULL,9000),(401,3341,1360917631,1360916097,74,3131,NULL,74,NULL,9000),(401,3351,1360917633,1360916100,75,3141,NULL,75,NULL,9000),(401,3361,1360917635,1360916102,76,3151,NULL,76,NULL,9000),(401,3371,1360917637,1360916105,77,3161,NULL,77,NULL,9000),(401,3381,1360917639,1360916107,78,3171,NULL,78,NULL,9000),(401,3391,1360917642,1360916110,79,3181,NULL,79,NULL,9000),(401,3401,1360917644,1360916112,80,3191,NULL,80,NULL,9000),(401,3521,1360917664,1360916133,92,3201,NULL,92,NULL,9000),(401,3531,1360917666,1360916135,93,3211,NULL,93,NULL,9000),(401,3541,1360917668,1360916137,94,3221,NULL,94,NULL,9000),(401,3551,1360917670,1360916140,95,3231,NULL,95,NULL,9000),(401,3561,1360917672,1360916142,96,3241,NULL,96,NULL,9000),(401,3571,1360917674,1360916145,97,3251,NULL,97,NULL,9000),(401,3581,1360917677,1360916147,98,3261,NULL,98,NULL,9000),(401,3591,1360917679,1360916150,99,3271,NULL,99,NULL,9000),(401,3611,1360917682,1360916154,101,3281,NULL,101,NULL,9000),(401,3621,1360917685,1360916156,102,3291,NULL,102,NULL,9000),(401,3631,1360917687,1360916158,103,3301,NULL,103,NULL,9000),(401,3641,1360917688,1360916160,104,3311,NULL,104,NULL,9000),(401,3651,1360917691,1360916162,105,3321,NULL,105,NULL,9000),(401,3661,1360917693,1360916165,106,3331,NULL,106,NULL,9000),(401,3671,1360917695,1360916167,107,3341,NULL,107,NULL,9000),(401,3681,1360917697,1360916170,108,3351,NULL,108,NULL,9000),(401,3691,1361770800,1360916172,109,3361,NULL,109,NULL,9000),(401,3771,1361937883,1361937805,1001,3371,NULL,1001,NULL,9000),(401,3771,1361937910,1361937883,1001,3381,NULL,1001,NULL,9000),(401,3781,1361938050,1361937962,1001,3391,NULL,1001,NULL,9000),(401,3781,1361939674,1361938050,1001,3401,NULL,1001,NULL,9000),(401,3791,-1,1361939875,1001,3411,NULL,1001,0,9000),(401,3791,1361939875,1361939710,1001,3421,NULL,1001,NULL,9000),(401,4031,-1,1361993985,1002,3431,NULL,1002,0,9000),(411,391,1349788962,1349788421,123,3441,NULL,123,NULL,9000),(411,391,1349789186,1349788962,123,3451,NULL,123,NULL,9000),(411,391,1349789778,1349789186,123,3461,NULL,123,NULL,9000),(411,411,1351006185,1351001842,1010,3471,NULL,1010,NULL,9000),(411,421,-1,1351006847,1010,3481,NULL,1010,0,9000),(411,661,1352340629,1352338352,1000,3491,NULL,1000,NULL,9000),(411,2111,1357315632,1357314408,3717,3501,NULL,3717,NULL,9000),(411,2121,1357315946,1357315718,3717,3511,NULL,3717,NULL,9000),(411,2121,1357316161,1357315946,3717,3521,NULL,3717,NULL,9000),(411,2141,1357323016,1357322608,3717,3531,NULL,3717,NULL,9000),(411,2141,1357323278,1357323016,3717,3541,NULL,3717,NULL,9000),(411,2141,1357323485,1357323278,3717,3551,NULL,3717,NULL,9000),(411,2141,1357333400,1357324428,3717,3561,NULL,3717,NULL,9000),(421,11,-1,1348856534,-1,3571,NULL,-1,0,9000),(421,11,1348856534,1348855217,100,3581,NULL,100,NULL,9000),(421,1971,-1,1356374029,602,3591,NULL,602,0,9000),(421,1981,-1,1356374146,603,3601,NULL,603,0,9000),(421,2201,1357681175,1357680636,3015,3611,NULL,3015,NULL,9000),(421,2201,1357681824,1357681175,3015,3621,NULL,3015,NULL,9000),(421,2201,1357683366,1357682848,3015,3631,NULL,3015,NULL,9000),(421,2211,1357703817,1357701950,3015,3641,NULL,3015,NULL,9000),(431,121,-1,1348966552,107,3651,NULL,107,0,9000),(431,131,-1,1348966879,108,3661,NULL,108,0,9000),(441,1831,-1,1355974722,503,3671,NULL,503,0,9000),(441,1841,-1,1355978227,504,3681,NULL,504,0,9000),(441,1861,-1,1356020829,4013,3691,NULL,4013,0,9000),(441,2011,-1,1356721874,505,3701,NULL,505,0,9000),(451,141,-1,1348967155,109,3711,NULL,109,0,9000),(451,151,-1,1348967392,110,3721,NULL,110,0,9000),(451,1861,1356020829,1356020379,4013,3731,NULL,4013,NULL,9000),(451,2141,1357323485,1357323278,3717,3741,NULL,3717,NULL,9000),(451,2141,1357324107,1357323485,3717,3751,NULL,3717,NULL,9000),(451,2331,1359127127,1359126955,3768,3761,NULL,3768,NULL,9000),(451,2381,1359133883,1359133342,3771,3771,NULL,3771,NULL,9000),(451,2391,1359133758,1359133726,3772,3781,NULL,3772,NULL,9000),(451,2451,1360352587,1360352183,3882,3791,NULL,3882,NULL,9000),(461,3721,-1,1361459445,445,3801,NULL,445,0,9000),(471,11,-1,1348856534,-1,3811,NULL,-1,0,9000),(471,11,1348856534,1348855217,100,3821,NULL,100,NULL,9000),(471,91,-1,1348965318,104,3831,NULL,104,0,9000),(471,121,-1,1348966552,107,3841,NULL,107,0,9000),(471,171,-1,1348967880,112,3851,NULL,112,0,9000),(471,1731,1355775161,1355774221,4012,3861,NULL,4012,NULL,9000),(471,1981,-1,1356374146,603,3871,NULL,603,0,9000),(471,1991,-1,1356374296,604,3881,NULL,604,0,9000),(471,2201,1357680636,1357680119,3015,3891,NULL,3015,NULL,9000),(471,2201,1357681175,1357680636,3015,3901,NULL,3015,NULL,9000),(471,2201,1357683366,1357682848,3015,3911,NULL,3015,NULL,9000),(471,2301,1358540237,1358453660,3015,3921,NULL,3015,NULL,9000),(471,2461,1360458995,1360458902,508,3931,NULL,508,NULL,9000),(481,2431,1360331552,1360331540,550,3941,NULL,550,NULL,9000),(501,161,-1,1348967606,111,3951,NULL,111,0,9000),(501,171,-1,1348967880,112,3961,NULL,112,0,9000),(501,371,1349284670,1349283588,500,3971,NULL,500,NULL,9000),(501,371,1349286925,1349284670,500,3981,NULL,500,NULL,9000),(501,371,1349287611,1349286925,500,3991,NULL,500,NULL,9000),(501,571,1351889721,1351888102,200,4001,NULL,200,NULL,9000),(501,571,1351897096,1351889721,200,4011,NULL,200,NULL,9000),(501,571,1351899961,1351897096,200,4021,NULL,200,NULL,9000),(501,571,1351900878,1351899961,200,4031,NULL,200,NULL,9000),(501,571,1352312647,1351900878,200,4041,NULL,200,NULL,9000),(511,1811,-1,1361930963,502,4051,NULL,502,0,9000),(511,1811,1361930963,1355886113,502,4061,NULL,502,NULL,9000),(511,1831,-1,1355974722,503,4071,NULL,503,0,9000),(521,51,-1,1361931032,100,4081,NULL,100,0,9000),(521,51,1361931032,1348963869,100,4091,NULL,100,NULL,9000),(521,141,-1,1348967155,109,4101,NULL,109,0,9000),(521,161,-1,1348967606,111,4111,NULL,111,0,9000),(531,301,1349112881,1349112858,66,4121,NULL,66,NULL,9000),(531,321,-1,1361930245,101,4131,NULL,101,0,9000),(531,321,1361930245,1349115872,101,4141,NULL,101,NULL,9000),(531,2271,-1,1358196664,642,4151,NULL,642,0,9000),(551,361,1349271255,1349269025,101,4161,NULL,101,NULL,9000),(551,361,1349271454,1349271255,101,4171,NULL,101,NULL,9000),(551,361,1349271885,1349271454,101,4181,NULL,101,NULL,9000),(551,361,1352405011,1349271885,101,4191,NULL,101,NULL,9000),(551,371,-1,1361930477,444,4201,NULL,444,0,9000),(551,371,1349277633,1349272370,102,4211,NULL,102,NULL,9000),(551,371,1349283588,1349277633,102,4221,NULL,102,NULL,9000),(551,371,1349284670,1349283588,102,4231,NULL,102,NULL,9000),(551,371,1349286925,1349284670,102,4241,NULL,102,NULL,9000),(551,371,1349287611,1349286925,444,4251,NULL,444,NULL,9000),(551,371,1361930477,1349287611,444,4261,NULL,444,NULL,9000),(551,381,1349378032,1349359139,103,4271,NULL,103,NULL,9000),(551,401,1352404946,1350575652,102,4281,NULL,102,NULL,9000),(551,541,1352409782,1351187296,103,4291,NULL,103,NULL,9000),(551,541,1355752805,1352409782,103,4301,NULL,103,NULL,9000),(551,701,-1,1352402411,211,4311,NULL,211,0,9000),(551,711,-1,1352405331,101,4321,NULL,101,0,9000),(551,721,-1,1352405455,102,4331,NULL,102,0,9000),(551,1011,1352502421,1352501566,3109,4341,NULL,3109,NULL,9000),(551,1701,-1,1355752877,103,4351,NULL,103,0,9000),(551,1711,-1,1355776962,2000,4361,NULL,2000,0,9000),(551,1711,1355763396,1355763066,2000,4371,NULL,2000,NULL,9000),(551,1711,1355766268,1355763396,2000,4381,NULL,2000,NULL,9000),(551,1711,1355776962,1355766268,2000,4391,NULL,2000,NULL,9000),(551,2471,1361458338,1360848531,443,4401,NULL,443,NULL,9000),(551,3731,-1,1361556086,104,4411,NULL,104,0,9000),(561,221,1349098689,1349098624,100,4421,NULL,100,NULL,9000),(561,221,1349101402,1349098689,100,4431,NULL,100,NULL,9000),(571,41,1348962908,1348961591,-1,4441,NULL,-1,NULL,9000),(571,81,-1,1349108611,103,4451,NULL,103,0,9000),(571,81,1349108611,1348965005,103,4461,NULL,103,NULL,9000),(571,91,-1,1348965318,104,4471,NULL,104,0,9000),(571,281,-1,1349109657,117,4481,NULL,117,0,9000),(571,291,1349112329,1349112223,30,4491,NULL,30,NULL,9000),(571,371,1349286925,1349284670,500,4501,NULL,500,NULL,9000),(571,371,1349287611,1349286925,500,4511,NULL,500,NULL,9000),(571,1011,1352502421,1352501566,3109,4521,NULL,3109,NULL,9000),(571,1711,1355766268,1355763396,100,4531,NULL,100,NULL,9000),(571,1721,-1,1355764551,200,4541,NULL,200,0,9000),(571,1991,-1,1356374296,604,4551,NULL,604,0,9000),(571,2001,-1,1356377554,605,4561,NULL,605,0,9000),(571,2071,1356990120,1356989625,511,4571,NULL,511,NULL,9000),(571,2081,1356994731,1356994599,1500,4581,NULL,1500,NULL,9000),(571,2421,1360127704,1360127612,505,4591,NULL,505,NULL,9000),(571,4031,-1,1361993985,201,4601,NULL,201,0,9000),(581,981,1352844591,1352844422,500,4611,NULL,500,NULL,9000),(581,991,1353518490,1352844667,500,4621,NULL,500,NULL,9000),(591,1,1348877078,1348842871,100,4631,NULL,100,NULL,9000),(591,1,1348877098,1348877078,100,4641,NULL,100,NULL,9000),(591,31,1348877301,1348877239,100,4651,NULL,100,NULL,9000),(591,31,1348877315,1348877301,100,4661,NULL,100,NULL,9000),(591,61,-1,1348964241,101,4671,NULL,101,0,9000),(591,281,-1,1349109657,117,4681,NULL,117,0,9000),(591,341,1349265546,1349265509,111,4691,NULL,111,NULL,9000),(591,1711,1355776962,1355766268,102,4701,NULL,102,NULL,9000),(591,1721,-1,1355764551,100,4711,NULL,100,0,9000),(591,1731,1355775161,1355774221,4012,4721,NULL,4012,NULL,9000),(591,2461,1360458995,1360458902,508,4731,NULL,508,NULL,9000),(601,341,1349265546,1349265509,3434,4741,NULL,3434,NULL,9000),(611,1,1348877078,1348842871,100,4751,NULL,100,NULL,9000),(611,1,1348877098,1348877078,100,4761,NULL,100,NULL,9000),(611,31,1348877301,1348877239,100,4771,NULL,100,NULL,9000),(611,31,1348877315,1348877301,100,4781,NULL,100,NULL,9000),(611,61,-1,1348964241,101,4791,NULL,101,0,9000),(611,101,-1,1348965714,105,4801,NULL,105,0,9000),(611,111,-1,1348965931,106,4811,NULL,106,0,9000),(611,1661,1355723578,1355723536,3005,4821,NULL,3005,NULL,9000),(611,1681,1355723732,1355723636,3005,4831,NULL,3005,NULL,9000),(611,1691,1355723985,1355723789,4012,4841,NULL,4012,NULL,9000),(621,491,1351022464,1351022071,1010,4851,NULL,1010,NULL,9000),(621,501,1351022680,1351022566,1010,4861,NULL,1010,NULL,9000),(621,511,1351023075,1351022874,1010,4871,NULL,1010,NULL,9000),(621,521,1351027009,1351026394,1010,4881,NULL,1010,NULL,9000),(621,531,1352295257,1351027609,1010,4891,NULL,1010,NULL,9000),(621,611,-1,1361659666,1010,4901,NULL,1010,0,9000),(621,611,1361659665,1352299135,1010,4911,NULL,1010,NULL,9000),(621,2021,1359556515,1359554761,1008,4921,NULL,1008,NULL,9000),(621,2021,1359571455,1359570016,1008,4931,NULL,1008,NULL,9000),(621,2021,1360006189,1360004101,1008,4941,NULL,1008,NULL,9000),(621,2311,-1,1358960571,1434,4951,NULL,1434,0,9000),(621,2431,1360331552,1360331540,540,4961,NULL,540,NULL,9000),(621,3801,-1,1361988667,1702,4971,NULL,1702,0,9000),(631,21,1349101364,1348857517,-1,4981,NULL,-1,NULL,9000),(631,231,1349106919,1349106722,100,4991,NULL,100,NULL,9000),(641,21,1349101364,1348857517,-1,5001,NULL,-1,NULL,9000),(641,101,-1,1348965714,105,5011,NULL,105,0,9000),(641,201,-1,1348968647,115,5021,NULL,115,0,9000),(641,311,1349115092,1349114669,100,5031,NULL,100,NULL,9000),(641,571,1351900878,1351899961,201,5041,NULL,201,NULL,9000),(641,571,1352312647,1351900878,201,5051,NULL,201,NULL,9000),(641,1631,-1,1354911700,202,5061,NULL,202,0,9000),(641,2421,1360127704,1360127612,505,5071,NULL,505,NULL,9000),(651,251,1349112733,1349106993,100,5081,NULL,100,NULL,9000),(651,251,1349114627,1349112733,100,5091,NULL,100,NULL,9000),(651,311,-1,1349121932,100,5101,NULL,100,0,9000),(651,311,1349115533,1349115092,100,5111,NULL,100,NULL,9000),(651,311,1349115553,1349115533,100,5121,NULL,100,NULL,9000),(651,311,1349115740,1349115553,100,5131,NULL,100,NULL,9000),(651,311,1349121316,1349115740,100,5141,NULL,100,NULL,9000),(651,311,1349121833,1349121316,100,5151,NULL,100,NULL,9000),(651,311,1349121886,1349121833,100,5161,NULL,100,NULL,9000),(651,311,1349121932,1349121886,100,5171,NULL,100,NULL,9000),(661,1031,1352508259,1352508221,1000,5181,NULL,1000,NULL,9000),(661,3801,-1,1361988667,1702,5191,NULL,1702,0,9000),(671,1931,1356024756,1356024108,3963,5201,NULL,3963,NULL,9000),(671,2331,1359127127,1359126955,3768,5211,NULL,3768,NULL,9000),(671,2381,1359133883,1359133342,3771,5221,NULL,3771,NULL,9000),(671,2391,1359133758,1359133726,3772,5231,NULL,3772,NULL,9000),(671,2451,1360352587,1360352183,3882,5241,NULL,3882,NULL,9000),(681,381,1349378032,1349359139,103,5251,NULL,103,NULL,9000),(681,571,1351889721,1351888102,3003,5261,NULL,3003,NULL,9000),(681,571,1351897096,1351889721,200,5271,NULL,200,NULL,9000),(681,571,1351899961,1351897096,201,5281,NULL,201,NULL,9000),(681,571,1352312647,1351900878,201,5291,NULL,201,NULL,9000),(681,581,1352731859,1352139235,3006,5301,NULL,3006,NULL,9000),(681,941,1352500095,1352499237,3007,5311,NULL,3007,NULL,9000),(681,1351,1352746047,1352744467,3006,5321,NULL,3006,NULL,9000),(681,1431,1353519052,1352772913,609,5331,NULL,609,NULL,9000),(681,1481,1354647601,1354638445,1000,5341,NULL,1000,NULL,9000),(681,1491,-1,1361929111,201,5351,NULL,201,0,9000),(681,1491,1360125490,1354649958,201,5361,NULL,201,NULL,9000),(681,1491,1360125530,1360125490,201,5371,NULL,201,NULL,9000),(681,1491,1360125558,1360125530,201,5381,NULL,201,NULL,9000),(681,1491,1360125823,1360125558,201,5391,NULL,201,NULL,9000),(681,1491,1361929111,1360125823,201,5401,NULL,201,NULL,9000),(681,1501,1354810417,1354809681,1000,5411,NULL,1000,NULL,9000),(681,1511,1354816460,1354810834,1000,5421,NULL,1000,NULL,9000),(681,1521,1354817652,1354817211,1000,5431,NULL,1000,NULL,9000),(681,1531,1357918870,1354818197,1000,5441,NULL,1000,NULL,9000),(681,1541,1354823082,1354822717,1001,5451,NULL,1001,NULL,9000),(681,1551,1354824301,1354823220,2191,5461,NULL,2191,NULL,9000),(681,1561,1354824987,1354824485,2191,5471,NULL,2191,NULL,9000),(681,1571,1354826701,1354825296,2191,5481,NULL,2191,NULL,9000),(681,1631,-1,1354911700,202,5491,NULL,202,0,9000),(681,1641,-1,1355341857,203,5501,NULL,203,0,9000),(681,2021,-1,1360006189,1008,5511,NULL,1008,0,9000),(681,2021,1359554761,1356977686,1008,5521,NULL,1008,NULL,9000),(681,2021,1359556515,1359554761,1008,5531,NULL,1008,NULL,9000),(681,2021,1359570016,1359556515,1008,5541,NULL,1008,NULL,9000),(681,2021,1359571455,1359570016,1008,5551,NULL,1008,NULL,9000),(681,2021,1360002360,1359571455,1008,5561,NULL,1008,NULL,9000),(681,2021,1360002398,1360002360,1008,5571,NULL,1008,NULL,9000),(681,2021,1360004101,1360002398,1008,5581,NULL,1008,NULL,9000),(681,2021,1360006189,1360004101,1008,5591,NULL,1008,NULL,9000),(681,2031,-1,1356977758,1009,5601,NULL,1009,0,9000),(681,2041,-1,1360005139,1108,5611,NULL,1108,0,9000),(681,2041,1356977919,1356977816,1109,5621,NULL,1109,NULL,9000),(681,2041,1360005139,1356977919,1108,5631,NULL,1108,NULL,9000),(681,2051,-1,1356977991,1109,5641,NULL,1109,0,9000),(681,2061,-1,1356978636,1110,5651,NULL,1110,0,9000),(681,2181,1357659408,1357658428,3005,5661,NULL,3005,NULL,9000),(691,1661,1355723536,1355722365,3105,5671,NULL,3105,NULL,9000),(691,1791,-1,1355783636,501,5681,NULL,501,0,9000),(691,2201,1357680119,1357679580,3015,5691,NULL,3015,NULL,9000),(691,2301,1358541418,1358540237,3015,5701,NULL,3015,NULL,9000),(691,2301,1358542066,1358541418,3015,5711,NULL,3015,NULL,9000),(691,2411,1360125382,1360125242,3555,5721,NULL,3555,NULL,9000),(691,3771,1361937883,1361937805,1001,5731,NULL,1001,NULL,9000),(691,3771,1361937910,1361937883,1001,5741,NULL,1001,NULL,9000),(691,3781,1361938050,1361937962,1001,5751,NULL,1001,NULL,9000),(691,3781,1361939674,1361938050,1001,5761,NULL,1001,NULL,9000),(691,3791,-1,1361939875,1001,5771,NULL,1001,0,9000),(691,3791,1361939875,1361939710,1001,5781,NULL,1001,NULL,9000),(701,71,1349101352,1348964684,102,5791,NULL,102,NULL,9000),(701,111,-1,1348965931,106,5801,NULL,106,0,9000),(701,201,-1,1348968647,115,5811,NULL,115,0,9000),(701,261,-1,1349109341,102,5821,NULL,102,0,9000),(701,501,1351022680,1351022566,1010,5831,NULL,1010,NULL,9000),(701,511,1351023075,1351022874,1010,5841,NULL,1010,NULL,9000),(701,521,1351027009,1351026394,1010,5851,NULL,1010,NULL,9000),(701,531,1352295257,1351027609,1010,5861,NULL,1010,NULL,9000),(701,611,-1,1361659666,1010,5871,NULL,1010,0,9000),(701,611,1361659665,1352299135,1010,5881,NULL,1010,NULL,9000),(701,661,1352340629,1352338352,1000,5891,NULL,1000,NULL,9000),(701,1801,1355884330,1355883867,555,5901,NULL,555,NULL,9000),(701,2021,-1,1360006189,1008,5911,NULL,1008,0,9000),(701,2021,1360002398,1360002360,1008,5921,NULL,1008,NULL,9000),(701,2021,1360004101,1360002398,1008,5931,NULL,1008,NULL,9000),(701,2021,1360006189,1360004101,1008,5941,NULL,1008,NULL,9000),(701,2041,-1,1360005139,1108,5951,NULL,1108,0,9000),(701,2181,1357659408,1357658428,3005,5961,NULL,3005,NULL,9000),(701,2301,1358543826,1358542066,3015,5971,NULL,3015,NULL,9000),(701,2311,-1,1358960571,1333,5981,NULL,1333,0,9000),(701,2441,1360340126,1360339654,3160,5991,NULL,3160,NULL,9000),(711,491,1351022464,1351022071,1010,6001,NULL,1010,NULL,9000),(721,3751,-1,1361931408,100,6011,NULL,100,0,9000),(721,3751,1361931408,1361770853,100,6021,NULL,100,NULL,9000),(741,1591,1354892940,1354892617,3005,6031,NULL,3005,NULL,9000),(741,1601,-1,1354897065,3005,6041,NULL,3005,0,9000),(741,1641,-1,1355341857,203,6051,NULL,203,0,9000),(741,2281,1358447202,1358446319,601,6061,NULL,601,NULL,9000),(751,41,1348962908,1348961591,-1,6071,NULL,-1,NULL,9000),(751,51,-1,1361931032,100,6081,NULL,100,0,9000),(751,51,1361931032,1348963869,100,6091,NULL,100,NULL,9000),(751,71,1349101352,1348964684,102,6101,NULL,102,NULL,9000),(751,81,-1,1349108611,103,6111,NULL,103,0,9000),(751,81,1349108611,1348965005,103,6121,NULL,103,NULL,9000),(751,261,-1,1349109341,102,6131,NULL,102,0,9000),(751,1661,1355723536,1355722365,3105,6141,NULL,3105,NULL,9000),(751,1661,1355723578,1355723536,3005,6151,NULL,3005,NULL,9000),(751,1681,1355723732,1355723636,3005,6161,NULL,3005,NULL,9000),(751,1691,1355723985,1355723789,4012,6171,NULL,4012,NULL,9000),(751,1791,-1,1355783636,501,6181,NULL,501,0,9000),(751,1801,1355884330,1355883867,555,6191,NULL,555,NULL,9000),(751,1811,-1,1361930963,502,6201,NULL,502,0,9000),(751,1811,1361930963,1355886113,502,6211,NULL,502,NULL,9000),(751,1861,1356020379,1356019162,4013,6221,NULL,4013,NULL,9000),(751,2001,-1,1356377554,605,6231,NULL,605,0,9000),(751,2281,-1,1358447202,602,6241,NULL,602,0,9000),(751,2411,1360125382,1360125242,3555,6251,NULL,3555,NULL,9000),(761,391,1349788962,1349788421,123,6261,NULL,123,NULL,9000),(761,391,1349789186,1349788962,123,6271,NULL,123,NULL,9000),(761,391,1349789778,1349789186,123,6281,NULL,123,NULL,9000),(761,661,1352340629,1352338352,1000,6291,NULL,1000,NULL,9000),(761,1481,1354647601,1354638445,1000,6301,NULL,1000,NULL,9000),(761,1501,1354810417,1354809681,1000,6311,NULL,1000,NULL,9000),(761,1511,1354816460,1354810834,1000,6321,NULL,1000,NULL,9000),(761,1521,1354817652,1354817211,1000,6331,NULL,1000,NULL,9000),(761,1531,1357918870,1354818197,1000,6341,NULL,1000,NULL,9000),(761,1541,1354823082,1354822717,1001,6351,NULL,1001,NULL,9000),(761,1551,1354824301,1354823220,2191,6361,NULL,2191,NULL,9000),(761,1561,1354824987,1354824485,2191,6371,NULL,2191,NULL,9000),(761,1571,1354826701,1354825296,2191,6381,NULL,2191,NULL,9000),(761,1581,1354891957,1354891574,3005,6391,NULL,3005,NULL,9000),(761,1591,1354892940,1354892617,3005,6401,NULL,3005,NULL,9000),(761,1601,-1,1354897065,3005,6411,NULL,3005,0,9000),(761,1671,-1,1355723085,4091,6421,NULL,4091,0,9000),(761,1671,-1,1355723085,4092,6431,NULL,4092,0,9000),(761,2261,-1,1361931308,1000,6441,NULL,1000,0,9000),(761,2261,1361931308,1357918922,1000,6451,NULL,1000,NULL,9000),(781,411,1351006185,1351001842,1010,6461,NULL,1010,NULL,9000),(781,421,-1,1351006847,1010,6471,NULL,1010,0,9000),(781,2141,1357323016,1357322608,3717,6481,NULL,3717,NULL,9000),(781,2141,1357323278,1357323016,3717,6491,NULL,3717,NULL,9000),(781,2141,1357324107,1357323485,3717,6501,NULL,3717,NULL,9000),(781,2141,1357324428,1357324107,3717,6511,NULL,3717,NULL,9000),(781,2291,1358450728,1358448498,603,6521,NULL,603,NULL,9000),(791,231,1349106919,1349106722,100,6531,NULL,100,NULL,9000),(791,1031,1352508259,1352508221,1500,6541,NULL,1500,NULL,9000),(791,1181,1352679692,1352678445,3007,6551,NULL,3007,NULL,9000),(791,1251,1353289261,1352683676,3007,6561,NULL,3007,NULL,9000),(791,1271,1353250381,1352731240,3005,6571,NULL,3005,NULL,9000),(791,3751,-1,1361931408,100,6581,NULL,100,0,9000),(791,3751,1361931408,1361770853,100,6591,NULL,100,NULL,9000),(801,131,-1,1348966879,108,6601,NULL,108,0,9000),(801,181,-1,1348968098,113,6611,NULL,113,0,9000),(801,211,-1,1348968857,116,6621,NULL,116,0,9000),(801,221,1349098689,1349098624,100,6631,NULL,100,NULL,9000),(801,221,1349101402,1349098689,100,6641,NULL,100,NULL,9000),(801,251,1349112733,1349106993,100,6651,NULL,100,NULL,9000),(801,581,1352731859,1352139235,3006,6661,NULL,3006,NULL,9000),(801,941,1352500095,1352499237,3007,6671,NULL,3007,NULL,9000),(801,1351,1352746047,1352744467,3006,6681,NULL,3006,NULL,9000),(801,1961,-1,1356373807,601,6691,NULL,601,0,9000),(801,1961,1356373807,1356372905,601,6701,NULL,601,NULL,9000),(801,1971,-1,1356374029,602,6711,NULL,602,0,9000),(801,2201,1357681824,1357681175,3015,6721,NULL,3015,NULL,9000),(801,2201,1357682848,1357681824,3015,6731,NULL,3015,NULL,9000),(801,2211,1357703817,1357701950,3015,6741,NULL,3015,NULL,9000),(801,2291,-1,1358450728,603,6751,NULL,603,0,9000),(5591,1271,1353250381,1352731240,3807,6761,NULL,3807,NULL,9000),(20911,1181,1352679692,1352678445,612,6771,NULL,612,NULL,9000),(20911,1251,1353289261,1352683676,612,6781,NULL,612,NULL,9000),(20911,1481,1354647601,1354638445,609,6791,NULL,609,NULL,9000),(20911,1501,1354810417,1354809681,609,6801,NULL,609,NULL,9000),(20911,1511,1354816460,1354810834,609,6811,NULL,609,NULL,9000),(20911,1521,1354817652,1354817211,617,6821,NULL,617,NULL,9000),(29161,1011,1352502421,1352501566,3109,6831,NULL,3109,NULL,9000),(29431,1591,1354892940,1354892617,3005,6841,NULL,3005,NULL,9000),(29771,1261,1353518964,1352696879,3107,6851,NULL,3107,NULL,9000),(29791,1581,1354891957,1354891574,3005,6861,NULL,3005,NULL,9000),(29961,1601,-1,1354897065,3005,6871,NULL,3005,0,9000),(30321,941,1352500095,1352499237,3007,6881,NULL,3007,NULL,9000),(30321,1531,1357918870,1354818197,3105,6891,NULL,3105,NULL,9000),(30321,1541,1354823082,1354822717,3005,6901,NULL,3005,NULL,9000),(30321,1551,1354824301,1354823220,2899,6911,NULL,2899,NULL,9000),(30321,1561,1354824987,1354824485,2899,6921,NULL,2899,NULL,9000),(30321,1571,1354826701,1354825296,2899,6931,NULL,2899,NULL,9000),(31211,1931,1356024756,1356024108,3963,6941,NULL,3963,NULL,9000),(31211,2331,1359127127,1359126955,3768,6951,NULL,3768,NULL,9000),(31211,2381,1359133883,1359133342,3771,6961,NULL,3771,NULL,9000),(31211,2451,1360352587,1360352183,3882,6971,NULL,3882,NULL,9000),(45561,1821,1355950700,1355943866,3717,6981,NULL,3717,NULL,9000),(45561,1821,1355952280,1355950700,3717,6991,NULL,3717,NULL,9000),(45561,1851,1356014361,1356010629,3717,7001,NULL,3717,NULL,9000),(45561,1871,1356021622,1356021045,3717,7011,NULL,3717,NULL,9000),(45561,1941,1356041095,1356040284,3717,7021,NULL,3717,NULL,9000),(45561,1951,1356102805,1356102505,3717,7031,NULL,3717,NULL,9000),(45561,2091,1357144404,1357143727,3717,7041,NULL,3717,NULL,9000),(45561,2101,1357166175,1357165008,3717,7051,NULL,3717,NULL,9000),(45561,2121,1357315946,1357315718,3717,7061,NULL,3717,NULL,9000),(45561,2121,1357316161,1357315946,3717,7071,NULL,3717,NULL,9000),(45561,2131,1357322384,1357322199,3717,7081,NULL,3717,NULL,9000),(45561,2131,1357322540,1357322384,3717,7091,NULL,3717,NULL,9000),(45561,2151,1357334732,1357334376,3717,7101,NULL,3717,NULL,9000),(45561,2161,1357336400,1357335907,3717,7111,NULL,3717,NULL,9000),(45571,2171,1357606279,1357605577,3717,7121,NULL,3717,NULL,9000),(45571,2251,-1,1358969894,3717,7131,NULL,3717,0,9000),(45571,2251,1358969413,1357856197,3717,7141,NULL,3717,NULL,9000),(45571,2251,1358969894,1358969413,3717,7151,NULL,3717,NULL,9000),(45571,4171,-1,1362091612,1750,7161,NULL,1750,0,9000),(45581,1821,1355950700,1355943866,3717,7171,NULL,3717,NULL,9000),(45581,1821,1355952280,1355950700,3717,7181,NULL,3717,NULL,9000),(45581,1851,1356014361,1356010629,3717,7191,NULL,3717,NULL,9000),(45581,1871,1356021622,1356021045,3717,7201,NULL,3717,NULL,9000),(45581,1941,1356041095,1356040284,3717,7211,NULL,3717,NULL,9000),(45581,1951,1356102805,1356102505,3717,7221,NULL,3717,NULL,9000),(45581,2101,1357166175,1357165008,3717,7231,NULL,3717,NULL,9000),(45581,2111,1357315632,1357314408,3717,7241,NULL,3717,NULL,9000),(45581,2161,1357336400,1357335907,3717,7251,NULL,3717,NULL,9000),(45591,2091,1357144404,1357143727,3717,7261,NULL,3717,NULL,9000),(45591,2131,1357322384,1357322199,3717,7271,NULL,3717,NULL,9000),(45591,2131,1357322540,1357322384,3717,7281,NULL,3717,NULL,9000),(45591,2151,1357334732,1357334376,3717,7291,NULL,3717,NULL,9000),(45591,2171,1357606279,1357605577,3717,7301,NULL,3717,NULL,9000),(45591,2231,1357849505,1357828819,3717,7311,NULL,3717,NULL,9000),(45591,2241,1358969497,1357849764,3717,7321,NULL,3717,NULL,9000),(45591,2241,1358969804,1358969497,3717,7331,NULL,3717,NULL,9000),(45591,2241,1358970629,1358969804,3717,7341,NULL,3717,NULL,9000),(45591,2241,1358974748,1358970629,-1,7351,NULL,-1,NULL,9000),(45601,471,1351017814,1351009560,2000,7361,NULL,2000,NULL,9000),(45601,481,1351023925,1351023757,2000,7371,NULL,2000,NULL,9000),(45601,481,1351035840,1351026930,2000,7381,NULL,2000,NULL,9000),(45601,731,1352407089,1352406988,2005,7391,NULL,2005,NULL,9000),(45601,731,1353518627,1352407089,2005,7401,NULL,2005,NULL,9000),(45601,741,1353518518,1352407184,2006,7411,NULL,2006,NULL,9000),(45601,751,1353518718,1352415653,1780,7421,NULL,1780,NULL,9000),(45601,761,1353518701,1352415759,2759,7431,NULL,2759,NULL,9000),(45601,771,1353518689,1352415874,2760,7441,NULL,2760,NULL,9000),(45601,781,1353518675,1352416138,2800,7451,NULL,2800,NULL,9000),(45601,971,1353518153,1352500865,3001,7461,NULL,3001,NULL,9000),(45601,981,1352844422,1352500991,3002,7471,NULL,3002,NULL,9000),(45601,981,1352844591,1352844422,3002,7481,NULL,3002,NULL,9000),(45601,981,1353518168,1352844591,3002,7491,NULL,3002,NULL,9000),(45601,991,1352844667,1352501086,3003,7501,NULL,3003,NULL,9000),(45601,991,1353518490,1352844667,3003,7511,NULL,3003,NULL,9000),(45601,1001,1353518184,1352501128,3004,7521,NULL,3004,NULL,9000),(45601,1041,1353518792,1352588229,1796,7531,NULL,1796,NULL,9000),(45601,1051,1353518739,1352588332,1797,7541,NULL,1797,NULL,9000),(45601,1061,1353518894,1352588414,1798,7551,NULL,1798,NULL,9000),(45601,1071,1353518882,1352588494,1799,7561,NULL,1799,NULL,9000),(45601,1081,1353518778,1352662054,1781,7571,NULL,1781,NULL,9000),(45601,1091,1353518869,1352662176,1782,7581,NULL,1782,NULL,9000),(45601,1101,1353518766,1352662313,1783,7591,NULL,1783,NULL,9000),(45601,1181,1352679692,1352678445,3007,7601,NULL,3007,NULL,9000),(45601,1251,1353289261,1352683676,3007,7611,NULL,3007,NULL,9000),(45601,1261,1352697466,1352696879,3107,7621,NULL,3107,NULL,9000),(45601,1261,1353518964,1352697466,3107,7631,NULL,3107,NULL,9000),(45601,1271,1353250381,1352731240,3005,7641,NULL,3005,NULL,9000),(45601,1291,1353518805,1352738431,1790,7651,NULL,1790,NULL,9000),(45601,1301,1353518843,1352738504,1791,7661,NULL,1791,NULL,9000),(45601,1311,1353518856,1352738573,1792,7671,NULL,1792,NULL,9000),(45601,1321,1353518829,1352738641,1793,7681,NULL,1793,NULL,9000),(45601,1331,1353518907,1352738714,1794,7691,NULL,1794,NULL,9000),(45601,1341,1353518751,1352738786,1795,7701,NULL,1795,NULL,9000),(45601,1361,1352760378,1352755888,2008,7711,NULL,2008,NULL,9000),(45601,1361,1353518532,1352760378,2008,7721,NULL,2008,NULL,9000),(45601,1401,1352765452,1352760511,2007,7731,NULL,2007,NULL,9000),(45601,1401,1353518584,1352765452,2007,7741,NULL,2007,NULL,9000),(45601,1411,1352765381,1352760599,2756,7751,NULL,2756,NULL,9000),(45601,1411,1352846795,1352765381,2756,7761,NULL,2756,NULL,9000),(45601,1431,1353519052,1352772913,3006,7771,NULL,3006,NULL,9000),(45601,1471,1353518600,1352847241,2756,7781,NULL,2756,NULL,9000),(45611,481,1351023757,1351017921,2000,7791,NULL,2000,NULL,9000),(45611,481,1351023925,1351023757,2000,7801,NULL,2000,NULL,9000),(45611,481,1351024257,1351023925,2000,7811,NULL,2000,NULL,9000),(45611,481,1351024493,1351024257,1000,7821,NULL,1000,NULL,9000),(45611,481,1351026930,1351024493,2000,7831,NULL,2000,NULL,9000),(45611,481,1351265734,1351035840,2000,7841,NULL,2000,NULL,9000),(45611,911,1352498297,1352498153,2003,7851,NULL,2003,NULL,9000),(45611,911,1353518613,1352498297,2003,7861,NULL,2003,NULL,9000),(45611,921,1352498335,1352498225,2004,7871,NULL,2004,NULL,9000),(45611,921,1353518645,1352498335,2004,7881,NULL,2004,NULL,9000),(45621,471,1351017814,1351009560,1000,7891,NULL,1000,NULL,9000),(45621,481,1351023757,1351017921,1000,7901,NULL,1000,NULL,9000),(45621,481,1351024257,1351023925,2000,7911,NULL,2000,NULL,9000),(45621,481,1351024493,1351024257,2000,7921,NULL,2000,NULL,9000),(45621,481,1351026930,1351024493,1000,7931,NULL,1000,NULL,9000),(45621,481,1351035840,1351026930,1000,7941,NULL,1000,NULL,9000),(45621,481,1351265734,1351035840,1000,7951,NULL,1000,NULL,9000),(45621,551,1352498401,1351261932,2001,7961,NULL,2001,NULL,9000),(45621,551,1353518562,1352498401,2001,7971,NULL,2001,NULL,9000),(45621,561,1353518548,1351273606,2002,7981,NULL,2002,NULL,9000),(45641,911,1352498297,1352498153,2003,7991,NULL,2003,NULL,9000),(45641,911,1353518613,1352498297,2003,8001,NULL,2003,NULL,9000),(45641,921,1352498335,1352498225,2004,8011,NULL,2004,NULL,9000),(45641,921,1353518645,1352498335,2004,8021,NULL,2004,NULL,9000),(45651,551,1352498401,1351261932,2001,8031,NULL,2001,NULL,9000),(45651,551,1353518562,1352498401,2001,8041,NULL,2001,NULL,9000),(45651,561,1353518548,1351273606,2002,8051,NULL,2002,NULL,9000),(45661,731,1352407089,1352406988,2005,8061,NULL,2005,NULL,9000),(45661,731,1353518627,1352407089,2005,8071,NULL,2005,NULL,9000),(45661,741,1353518518,1352407184,2006,8081,NULL,2006,NULL,9000),(45661,1021,1352825498,1352501786,2761,8091,NULL,2761,NULL,9000),(45661,1021,1352848133,1352825498,2761,8101,NULL,2761,NULL,9000),(45661,1021,1354633947,1352848133,2761,8111,NULL,2761,NULL,9000),(45661,1361,1352760378,1352755888,2008,8121,NULL,2008,NULL,9000),(45661,1361,1353518532,1352760378,2008,8131,NULL,2008,NULL,9000),(45671,3831,-1,1361992261,3107,8141,NULL,3107,0,9000),(45671,3931,-1,1361993029,3100,8151,NULL,3100,0,9000),(45671,4001,-1,1361993829,3101,8161,NULL,3101,0,9000),(45671,4011,-1,1362144043,3103,8171,NULL,3103,0,9000),(45671,4011,1362144043,1361993889,3103,8181,NULL,3103,NULL,9000),(45671,4021,-1,1361993940,3106,8191,NULL,3106,0,9000),(45671,4041,-1,1361994109,3102,8201,NULL,3102,0,9000),(45671,4051,-1,1361994199,3104,8211,NULL,3104,0,9000),(45671,4061,-1,1361994255,3105,8221,NULL,3105,0,9000),(45691,1041,1353518792,1352588229,1796,8231,NULL,1796,NULL,9000),(45691,1051,1353518739,1352588332,1797,8241,NULL,1797,NULL,9000),(45691,1061,1353518894,1352588414,1798,8251,NULL,1798,NULL,9000),(45691,1071,1353518882,1352588494,1799,8261,NULL,1799,NULL,9000),(45691,1081,1353518778,1352662054,1781,8271,NULL,1781,NULL,9000),(45691,1091,1353518869,1352662176,1782,8281,NULL,1782,NULL,9000),(45691,1101,1353518766,1352662313,1783,8291,NULL,1783,NULL,9000),(45691,1291,1353518805,1352738431,1790,8301,NULL,1790,NULL,9000),(45691,1301,1353518843,1352738504,1791,8311,NULL,1791,NULL,9000),(45691,1311,1353518856,1352738573,1792,8321,NULL,1792,NULL,9000),(45691,1321,1353518829,1352738641,1793,8331,NULL,1793,NULL,9000),(45691,1331,1353518907,1352738714,1794,8341,NULL,1794,NULL,9000),(45691,1341,1353518751,1352738786,1795,8351,NULL,1795,NULL,9000),(45701,751,1353518718,1352415653,1780,8361,NULL,1780,NULL,9000),(45701,761,1353518701,1352415759,2759,8371,NULL,2759,NULL,9000),(45701,771,1353518689,1352415874,2760,8381,NULL,2760,NULL,9000),(45701,781,1353518675,1352416138,2800,8391,NULL,2800,NULL,9000),(45701,1931,1356024756,1356024108,3963,8401,NULL,3963,NULL,9000),(45711,1021,1352825498,1352501786,2761,8411,NULL,2761,NULL,9000),(45711,1021,1352848133,1352825498,2761,8421,NULL,2761,NULL,9000),(45711,1021,1354633947,1352848133,2761,8431,NULL,2761,NULL,9000),(45741,1401,1352765452,1352760511,2007,8441,NULL,2007,NULL,9000),(45741,1401,1353518584,1352765452,-1,8451,NULL,-1,NULL,9000),(45741,3841,-1,1361992319,2008,8461,NULL,2008,0,9000),(45741,3921,-1,1361992947,2001,8471,NULL,2001,0,9000),(45741,3971,-1,1361993393,2002,8481,NULL,2002,0,9000),(45741,4061,-1,1361994255,2003,8491,NULL,2003,0,9000),(45741,4071,-1,1361994302,2006,8501,NULL,2006,0,9000),(45741,4081,-1,1362144282,2005,8511,NULL,2005,0,9000),(45741,4081,1362144282,1361994356,2005,8521,NULL,2005,NULL,9000),(45741,4091,-1,1361994403,2007,8531,NULL,2007,0,9000),(45741,4101,-1,1361994451,2004,8541,NULL,2004,0,9000),(45751,1411,1352765381,1352760599,2756,8551,NULL,2756,NULL,9000),(45751,1411,1352846795,1352765381,-1,8561,NULL,-1,NULL,9000),(45751,1471,1353518600,1352847241,-1,8571,NULL,-1,NULL,9000),(45751,3811,-1,1361992120,3210,8581,NULL,3210,0,9000),(45751,3821,-1,1361992198,3211,8591,NULL,3211,0,9000),(45751,3831,-1,1361992261,3212,8601,NULL,3212,0,9000),(45751,3841,-1,1361992319,3216,8611,NULL,3216,0,9000),(45751,3851,-1,1361992378,3213,8621,NULL,3213,0,9000),(45751,3861,-1,1361992438,3217,8631,NULL,3217,0,9000),(45751,3871,-1,1362144481,3214,8641,NULL,3214,0,9000),(45751,3871,1362144481,1361992515,3214,8651,NULL,3214,NULL,9000),(45751,3881,-1,1361992684,3215,8661,NULL,3215,0,9000),(45801,2441,1360340126,1360339654,3160,8671,NULL,3160,NULL,9000),(45811,3761,1361992060,1361811066,1234,8681,NULL,1234,NULL,9000),(45811,3851,-1,1361992378,4078,8691,NULL,4078,0,9000),(45811,3911,-1,1361992881,4094,8701,NULL,4094,0,9000),(45811,3961,-1,1361993238,4093,8711,NULL,4093,0,9000),(45811,4041,-1,1361994109,4092,8721,NULL,4092,0,9000),(45811,4101,-1,1361994451,4089,8731,NULL,4089,0,9000),(45811,4111,-1,1361994496,4090,8741,NULL,4090,0,9000),(45811,4121,-1,1362144135,4091,8751,NULL,4091,0,9000),(45811,4121,1362144135,1361994552,4091,8761,NULL,4091,NULL,9000),(45811,4131,-1,1361994603,4088,8771,NULL,4088,0,9000),(45831,3821,-1,1361992199,3117,8781,NULL,3117,0,9000),(45831,3941,-1,1361993115,3110,8791,NULL,3110,0,9000),(45831,3951,-1,1361994150,3114,8801,NULL,3114,0,9000),(45831,3951,1361994149,1361993171,3114,8811,NULL,3114,NULL,9000),(45831,3961,-1,1361993238,3112,8821,NULL,3112,0,9000),(45831,3971,-1,1361993393,3115,8831,NULL,3115,0,9000),(45831,3981,-1,1361993442,3116,8841,NULL,3116,0,9000),(45831,3991,-1,1362144354,3113,8851,NULL,3113,0,9000),(45831,3991,1362144354,1361993526,3113,8861,NULL,3113,NULL,9000),(45831,4001,-1,1361993829,3111,8871,NULL,3111,0,9000),(45841,3871,-1,1362144481,3128,8881,NULL,3128,0,9000),(45841,3871,1362144481,1361992515,3214,8891,NULL,3214,NULL,9000),(45841,3901,-1,1362144424,3120,8901,NULL,3120,0,9000),(45841,3901,1362144424,1361992795,3113,8911,NULL,3113,NULL,9000),(45841,3991,-1,1362144354,3121,8921,NULL,3121,0,9000),(45841,3991,1362144354,1361993526,3120,8931,NULL,3120,NULL,9000),(45841,4011,-1,1362144043,3122,8941,NULL,3122,0,9000),(45841,4011,1362144043,1361993889,3103,8951,NULL,3103,NULL,9000),(45841,4081,-1,1362144282,3126,8961,NULL,3126,0,9000),(45841,4081,1362144282,1361994356,2005,8971,NULL,2005,NULL,9000),(45841,4121,-1,1362144135,3123,8981,NULL,3123,0,9000),(45841,4121,1362144135,1361994552,3121,8991,NULL,3121,NULL,9000),(45841,4151,-1,1362144220,3127,9001,NULL,3127,0,9000),(45841,4151,1362144220,1361994688,2504,9011,NULL,2504,NULL,9000),(45841,4161,-1,1362143960,3125,9021,NULL,3125,0,9000),(45841,4161,1362143960,1361994728,3122,9031,NULL,3122,NULL,9000),(45851,3731,-1,1361556086,2068,9041,NULL,2068,0,9000),(45861,3881,-1,1361992684,2050,9051,NULL,2050,0,9000),(45861,3891,-1,1361992748,2051,9061,NULL,2051,0,9000),(45861,3951,-1,1361994150,2052,9071,NULL,2052,0,9000),(45861,3951,1361994149,1361993171,2053,9081,NULL,2053,NULL,9000),(45861,4051,-1,1361994199,2053,9091,NULL,2053,0,9000),(45861,4071,-1,1361994302,2054,9101,NULL,2054,0,9000),(45861,4111,-1,1361994496,2055,9111,NULL,2055,0,9000),(45861,4141,-1,1361994643,2056,9121,NULL,2056,0,9000),(45861,4161,-1,1362143960,2057,9131,NULL,2057,0,9000),(45861,4161,1362143960,1361994728,2057,9141,NULL,2057,NULL,9000),(391,4181,1449156435,1386083827,200,10631,NULL,200,NULL,9000),(511,4181,1449156435,1386083827,2,10641,NULL,2,NULL,9000),(321,4181,1449156435,1386083827,2,10651,NULL,2,NULL,9000),(321,4182,1442517482,1435247020,4,10661,NULL,4,NULL,9000),(511,4182,1442517482,1435247020,4,10662,NULL,4,NULL,9000),(511,4182,1442517482,1435247020,5,10663,NULL,5,NULL,9000),(511,4182,1442517482,1435247020,6,10664,NULL,6,NULL,9000),(511,4182,1442517482,1435247020,7,10665,NULL,7,NULL,9000),(321,4183,-1,1443037937,4,10666,NULL,4,0,9000),(511,4183,-1,1443037937,4,10667,NULL,4,0,9000),(511,4183,-1,1443037937,5,10668,NULL,5,0,9000),(511,4183,-1,1443037937,6,10669,NULL,6,0,9000),(511,4183,-1,1443037937,7,10670,NULL,7,0,9000),(391,4181,-1,1449156435,200,10671,NULL,200,0,9000),(321,4181,-1,1449156435,2,10672,NULL,2,0,9000),(45791,4181,-1,1449156435,500,10673,NULL,500,0,9000),(501,4181,-1,1449156435,600,10674,NULL,600,0,9000);
/*!40000 ALTER TABLE `circuit_edge_interface_membership` ENABLE KEYS */;
UNLOCK TABLES;
@@ -641,6 +641,7 @@ CREATE TABLE `node_instantiation` (
`mgmt_addr` varchar(255) DEFAULT NULL,
`loopback_address` varchar(255) DEFAULT NULL,
`tcp_port` int(6) DEFAULT '830',
+ `controller` enum('openflow','netconf','nso') NOT NULL DEFAULT 'nso',
PRIMARY KEY (`node_id`,`end_epoch`),
UNIQUE KEY `node_instantiation_idx` (`end_epoch`,`dpid`),
KEY `node_instantiation_idx1` (`end_epoch`),
@@ -654,7 +655,7 @@ CREATE TABLE `node_instantiation` (
LOCK TABLES `node_instantiation` WRITE;
/*!40000 ALTER TABLE `node_instantiation` DISABLE KEYS */;
-INSERT INTO `node_instantiation` VALUES (1,-1,1348237415,'active','155568807680',1,1,NULL,NULL,NULL,NULL,NULL,830),(11,-1,1348255796,'active','155568803584',1,1,NULL,NULL,NULL,NULL,NULL,830),(21,-1,1348598855,'active','155569080320',1,1,NULL,NULL,NULL,NULL,NULL,830),(31,-1,1348600958,'active','155568735232',1,1,NULL,NULL,NULL,NULL,NULL,830),(41,-1,1348748776,'active','155568969984',1,1,NULL,NULL,NULL,NULL,NULL,830),(51,-1,1348749176,'active','155569035008',1,1,NULL,NULL,NULL,NULL,NULL,830),(61,-1,1348752079,'active','155568362496',1,1,NULL,NULL,NULL,NULL,NULL,830),(71,-1,1348752171,'active','155568668928',1,1,NULL,NULL,NULL,NULL,NULL,830),(81,-1,1348752274,'active','155569068800',1,1,NULL,NULL,NULL,NULL,NULL,830),(91,-1,1348754042,'active','155569081856',1,1,NULL,NULL,NULL,NULL,NULL,830),(101,-1,1348754820,'active','155568799232',1,1,NULL,NULL,NULL,NULL,NULL,830),(111,-1,1348757861,'active','155569091328',1,1,NULL,NULL,NULL,NULL,NULL,830),(131,-1,1348763465,'active','155569011968',1,1,NULL,NULL,NULL,NULL,NULL,830),(141,-1,1348860000,'active','155568780288',1,1,NULL,NULL,NULL,NULL,NULL,830),(5721,-1,1358269138,'active','155569084160',1,1,NULL,NULL,NULL,NULL,NULL,830),(5731,-1,1360987388,'active','689971058402',1,1,NULL,NULL,NULL,NULL,NULL,830),(5732,-1,1374032215,'active','189441487323072',1,1,NULL,NULL,NULL,NULL,NULL,830),(5733,-1,1412233973,'active','110383266872512',1,1,NULL,NULL,NULL,NULL,NULL,830),(5734,-1,1362683428,'active','189441482319808',1,1,NULL,NULL,NULL,NULL,NULL,830),(5735,-1,1378295616,'active','189441487316928',1,1,NULL,NULL,NULL,NULL,NULL,830);
+INSERT INTO `node_instantiation` VALUES (1,-1,1348237415,'active','155568807680',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(11,-1,1348255796,'active','155568803584',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(21,-1,1348598855,'active','155569080320',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(31,-1,1348600958,'active','155568735232',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(41,-1,1348748776,'active','155568969984',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(51,-1,1348749176,'active','155569035008',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(61,-1,1348752079,'active','155568362496',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(71,-1,1348752171,'active','155568668928',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(81,-1,1348752274,'active','155569068800',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(91,-1,1348754042,'active','155569081856',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(101,-1,1348754820,'active','155568799232',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(111,-1,1348757861,'active','155569091328',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(131,-1,1348763465,'active','155569011968',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(141,-1,1348860000,'active','155568780288',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5721,-1,1358269138,'active','155569084160',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5731,-1,1360987388,'active','689971058402',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5732,-1,1374032215,'active','189441487323072',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5733,-1,1412233973,'active','110383266872512',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5734,-1,1362683428,'active','189441482319808',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(5735,-1,1378295616,'active','189441487316928',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(4581,-1,1378295616,'active','189441487316938',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf'),(2121,-1,1378295616,'active','189441487316948',1,1,NULL,NULL,NULL,NULL,NULL,830,'netconf');
/*!40000 ALTER TABLE `node_instantiation` ENABLE KEYS */;
UNLOCK TABLES;
@@ -701,7 +702,7 @@ CREATE TABLE `oess_version` (
LOCK TABLES `oess_version` WRITE;
/*!40000 ALTER TABLE `oess_version` DISABLE KEYS */;
-INSERT INTO `oess_version` VALUES ('2.0.5');
+INSERT INTO `oess_version` VALUES ('2.0.12');
/*!40000 ALTER TABLE `oess_version` ENABLE KEYS */;
UNLOCK TABLES;
@@ -1034,7 +1035,7 @@ CREATE TABLE `vrf_ep` (
`vrf_ep_id` int(11) NOT NULL AUTO_INCREMENT,
`inner_tag` int(10) DEFAULT NULL,
`tag` int(10) DEFAULT NULL,
- `bandwidth` int(10) DEFAULT NULL,
+ `bandwidth` int(10) DEFAULT '0',
`vrf_id` int(10) DEFAULT NULL,
`interface_id` int(10) NOT NULL,
`state` enum('active','decom') DEFAULT NULL,
@@ -1043,7 +1044,7 @@ CREATE TABLE `vrf_ep` (
PRIMARY KEY (`vrf_ep_id`),
KEY `vrf_id` (`vrf_id`),
KEY `interface_id` (`interface_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -1052,7 +1053,7 @@ CREATE TABLE `vrf_ep` (
LOCK TABLES `vrf_ep` WRITE;
/*!40000 ALTER TABLE `vrf_ep` DISABLE KEYS */;
-INSERT INTO `vrf_ep` VALUES (2,NULL,3,1000,2,391,'active',3,9000),(3,3,3,50,3,1,'active',5001,9000),(4,NULL,40,50,4,391,'decom',40,9000),(5,NULL,40,50,4,1,'decom',40,9000),(6,21,20,50,5,391,'decom',5000,9000),(7,21,20,50,5,1,'decom',5000,9000);
+INSERT INTO `vrf_ep` VALUES (2,NULL,3,1000,2,391,'active',3,9000),(3,3,3,50,3,1,'active',5001,9000),(4,NULL,40,50,4,391,'decom',40,9000),(5,NULL,40,50,4,1,'decom',40,9000),(6,21,20,50,5,391,'decom',5000,9000),(7,21,20,50,5,1,'decom',5000,9000),(8,NULL,3010,100,1,45841,'active',200,9000),(9,NULL,2010,100,1,45741,'active',200,9000);
/*!40000 ALTER TABLE `vrf_ep` ENABLE KEYS */;
UNLOCK TABLES;
@@ -1066,7 +1067,7 @@ DROP TABLE IF EXISTS `vrf_ep_peer`;
CREATE TABLE `vrf_ep_peer` (
`vrf_ep_peer_id` int(10) NOT NULL AUTO_INCREMENT,
`peer_ip` varchar(255) NOT NULL,
- `peer_asn` int(10) NOT NULL,
+ `peer_asn` int(10) unsigned DEFAULT NULL,
`vrf_ep_id` int(11) DEFAULT NULL,
`state` enum('active','decom') DEFAULT NULL,
`local_ip` varchar(255) DEFAULT NULL,
@@ -1079,7 +1080,7 @@ CREATE TABLE `vrf_ep_peer` (
KEY `vrf_ep_id` (`vrf_ep_id`),
KEY `vrf_ep_peer_ibfk_2` (`circuit_ep_id`),
CONSTRAINT `vrf_ep_peer_ibfk_2` FOREIGN KEY (`circuit_ep_id`) REFERENCES `circuit_edge_interface_membership` (`circuit_edge_id`) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -1088,6 +1089,7 @@ CREATE TABLE `vrf_ep_peer` (
LOCK TABLES `vrf_ep_peer` WRITE;
/*!40000 ALTER TABLE `vrf_ep_peer` DISABLE KEYS */;
+INSERT INTO `vrf_ep_peer` VALUES (1,'192.168.1.3/31',64601,8,'active','192.168.1.2/31','','ipv4',1,NULL,0),(2,'192.168.2.3/31',64602,9,'active','192.168.2.2/31','','ipv4',1,NULL,0),(3,'192.168.5.3/31',64605,8,'active','192.168.5.2/31','','ipv4',1,NULL,0);
/*!40000 ALTER TABLE `vrf_ep_peer` ENABLE KEYS */;
UNLOCK TABLES;
@@ -1185,4 +1187,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2020-06-24 15:16:44
+-- Dump completed on 2021-07-13 0:19:01
diff --git a/perl-lib/OESS/t/topology-shortest_path.t b/perl-lib/OESS/t/topology-shortest_path.t
index 45c0120a9..b31df2403 100644
--- a/perl-lib/OESS/t/topology-shortest_path.t
+++ b/perl-lib/OESS/t/topology-shortest_path.t
@@ -25,6 +25,13 @@ Log::Log4perl::init_and_watch('t/conf/logging.conf',10);
#--- instantiate OESS DB and Topo
my $db = OESS::Database->new(config => "$cwd/conf/database.xml");
ok(defined($db));
+
+
+# OESS::Topology::find_path works by fetching nodes with the specified
+# type. These tests use a node type of 'openflow'.
+$db->_execute_query("update node_instantiation set controller='openflow'", []);
+
+
my $config_file = "$cwd/conf/database.xml";
my $topo = OESS::Topology->new(
config => $config_file,
diff --git a/perl-lib/OESS/t/z-DB/Node.update.00.t b/perl-lib/OESS/t/z-DB/Node.update.00.t
new file mode 100644
index 000000000..ce61a307d
--- /dev/null
+++ b/perl-lib/OESS/t/z-DB/Node.update.00.t
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/..";
+
+
+use Data::Dumper;
+use Test::More tests => 20;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::DB::Node;
+
+# Purpose:
+#
+# Verify interface updates are correctly saved into the database.
+
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../conf/database.xml",
+ dbdump => "$path/../conf/oess_known_state.sql"
+);
+
+my $db = new OESS::DB(
+ config => "$path/../conf/database.xml"
+);
+
+
+my $model = {
+ node_id => 1,
+ name => 'host.examle.com', # Optional
+ latitude => 1, # Optional
+ longitude => 1, # Optional
+ operational_state_mpls => 'up', # Optional
+ vlan_tag_range => '1-4095', # Optional
+ pending_diff => 1, # Optional
+ short_name => 'host', # Optional
+ admin_state => 'active', # Optional
+ vendor => 'juniper', # Optional
+ model => 'mx', # Optional
+ sw_version => '13.3R3', # Optional
+ mgmt_addr => '192.168.1.1', # Optional
+ loopback_address => '10.0.0.1', # Optional
+ tcp_port => 830 # Optional
+};
+
+
+my $i1 = $db->execute_query("select * from node_instantiation where node_id=1");
+my $icount1 = @$i1;
+
+my $err = OESS::DB::Node::update(
+ db => $db,
+ node => $model
+);
+ok(!defined $err, 'Node updated');
+warn $err if defined $err;
+
+# Verify created instantiation entry
+my $i2 = $db->execute_query("select * from node_instantiation where node_id=1");
+my $icount2 = @$i2;
+ok($icount2 == $icount1+1, "Got expected number of instantiation entries.");
+
+# Verify non-effective edit creates no new instantiation entries
+OESS::DB::Node::update(
+ db => $db,
+ node => $model
+);
+my $i3 = $db->execute_query("select * from node_instantiation where node_id=1");
+my $icount3 = @$i2;
+ok($icount3 == $icount1+1, "Got expected number of instantiation entries.");
+
+my $intf = OESS::DB::Node::fetch(
+ db => $db,
+ node_id => 1
+);
+
+foreach my $key (keys %$model) {
+ ok($intf->{$key} eq $model->{$key}, "got expected $key from db");
+}
+
+
+my $err1 = OESS::DB::Node::update(
+ db => $db,
+ node => undef
+);
+ok(defined $err1, "Got expected error $err1");
+
+
+delete $model->{node_id};
+my $err2 = OESS::DB::Node::update(
+ db => $db,
+ node => $model
+);
+ok(defined $err2, "Got expected error $err2");
diff --git a/perl-lib/OESS/t/z-DB/Peer.update.00.t b/perl-lib/OESS/t/z-DB/Peer.update.00.t
index 710725571..a0e913b31 100644
--- a/perl-lib/OESS/t/z-DB/Peer.update.00.t
+++ b/perl-lib/OESS/t/z-DB/Peer.update.00.t
@@ -55,6 +55,7 @@ warn $err if defined $err;
$model->{vrf_ep_peer_id} = $id;
$model->{local_ip} = '192.168.3.2/31';
$model->{peer_ip} = '192.168.3.3/31';
+$model->{md5_key} = 'a new key';
my $err3 = OESS::DB::Peer::update(db => $db, peer => $model);
ok(!defined $err3, "no error on standard update");
diff --git a/perl-lib/OESS/t/z-DB/User.edit_user.01.t b/perl-lib/OESS/t/z-DB/User.edit_user.01.t
new file mode 100644
index 000000000..a61a29923
--- /dev/null
+++ b/perl-lib/OESS/t/z-DB/User.edit_user.01.t
@@ -0,0 +1,137 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/..";
+
+use Data::Dumper;
+use Test::More tests => 28;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::DB::User;
+
+# Purpose:
+#
+# Verify user creation errors when bad type specified.
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../conf/database.xml",
+ dbdump => "$path/../conf/oess_known_state.sql"
+);
+
+my $db = new OESS::DB(
+ config => "$path/../conf/database.xml"
+);
+my $model = {
+ given_names => 'Testerfield',
+ family_name => 'Testerton',
+ email => 'ttesterton@testertonestates.com',
+ username => 'ttesterton',
+ status => 'active'
+};
+
+my ($id, $err) = OESS::DB::User::add_user(
+ db => $db,
+ given_name => $model->{given_names},
+ family_name => $model->{family_name},
+ email => $model->{email},
+ auth_names => $model->{username}
+);
+ok(defined $id, "User entry was created");
+
+my $user = OESS::DB::User::fetch(db => $db, user_id => $id);
+foreach my $key (keys %$model) {
+ ok($user->{$key} eq $model->{$key}, "got expected initial $key from db");
+}
+$model->{family_name} = 'Please-Ignore';
+
+
+my ($res, $err2) = OESS::DB::User::edit_user(
+ db => $db,
+ user_id => $id,
+ given_name => $model->{given_names},
+ family_name => $model->{family_name},
+ email => $model->{email},
+ auth_names => [ $model->{username}, 'ttesterton2', 'ttesterton3' ],
+ status => $model->{status}
+);
+print ("ERR = $err2") if defined $err2;
+ok($res == 1, "Editing User was successful");
+
+
+my $index = { 'ttesterton' => 962, 'ttesterton2' => 963, 'ttesterton3' => 964 };
+my $users = $db->execute_query("select * from remote_auth where user_id=?", [$id]);
+
+
+foreach my $user (@$users) {
+ my $name = $user->{auth_name};
+ my $uid = $user->{auth_id};
+ ok(defined $index->{$name}, "found expected username $name");
+ ok($index->{$name} == $uid, "found expected user id $uid");
+ delete $index->{$name};
+}
+
+ok(keys %$index == 0, "all expected usernames accounted for");
+
+
+my ($res3, $err3) = OESS::DB::User::edit_user(
+ db => $db,
+ user_id => $id,
+ given_name => $model->{given_names},
+ family_name => $model->{family_name},
+ email => $model->{email},
+ auth_names => [ $model->{username}, 'ttesterton3' ],
+ status => $model->{status}
+);
+print ("ERR = $err3") if defined $err3;
+ok($res3 == 1, "Editing User was successful");
+
+$index = { 'ttesterton' => 962, 'ttesterton3' => 964 };
+$users = $db->execute_query("select * from remote_auth where user_id=?", [$id]);
+
+foreach my $user (@$users) {
+ my $name = $user->{auth_name};
+ my $uid = $user->{auth_id};
+ ok(defined $index->{$name}, "found expected username $name");
+ ok($index->{$name} == $uid, "found expected user id $uid");
+ delete $index->{$name};
+}
+
+ok(keys %$index == 0, "all expected usernames accounted for");
+
+
+my ($res4, $err4) = OESS::DB::User::edit_user(
+ db => $db,
+ user_id => $id,
+ given_name => $model->{given_names},
+ family_name => $model->{family_name},
+ email => $model->{email},
+ auth_names => [ $model->{username}, 'ttesterton3', 'ttesterton4' ],
+ status => $model->{status}
+);
+print ("ERR = $err4") if defined $err4;
+ok($res4 == 1, "Editing User was successful");
+
+$index = { 'ttesterton' => 962, 'ttesterton3' => 964, 'ttesterton4' => 965 };
+$users = $db->execute_query("select * from remote_auth where user_id=?", [$id]);
+
+foreach my $user (@$users) {
+ my $name = $user->{auth_name};
+ my $uid = $user->{auth_id};
+ ok(defined $index->{$name}, "found expected username $name");
+ ok($index->{$name} == $uid, "found expected user id $uid");
+ delete $index->{$name};
+}
+
+ok(keys %$index == 0, "all expected usernames accounted for");
diff --git a/perl-lib/OESS/t/z-DB/User.has_circuit_permission.00.t b/perl-lib/OESS/t/z-DB/User.has_circuit_permission.00.t
new file mode 100755
index 000000000..e07bd5e70
--- /dev/null
+++ b/perl-lib/OESS/t/z-DB/User.has_circuit_permission.00.t
@@ -0,0 +1,176 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/..";
+
+use Data::Dumper;
+use Test::More tests => 80;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::DB::User;
+use OESS::DB::Workgroup;
+use OESS::DB::Circuit;
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../conf/database.xml",
+ dbdump => "$path/../conf/oess_known_state.sql"
+);
+
+my $db = new OESS::DB(
+ config => "$path/../conf/database.xml"
+);
+
+$db->execute_query("update circuit set workgroup_id=31 where circuit_id=2281", []);
+$db->execute_query("update interface set workgroup_id=21 where interface_id=401 or interface_id=751", []);
+
+# user 501: workgroup 31 user with role admin + not in admin workgroup + not in workgroup 21
+$db->execute_query("delete from user_workgroup_membership where user_id=501 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=501 and workgroup_id=21", []);
+$db->execute_query(
+ "insert into user_workgroup_membership (workgroup_id,user_id,role) values (?,?,?)",
+ [31, 501, 'admin']
+);
+
+# user 601: workgroup 31 user with role normal + not in admin workgroup + not in workgroup 21
+$db->execute_query("delete from user_workgroup_membership where user_id=601 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=601 and workgroup_id=21", []);
+$db->execute_query(
+ "insert into user_workgroup_membership (workgroup_id,user_id,role) values (?,?,?)",
+ [31, 601, 'normal']
+);
+
+# user 701: workgroup 31 user with role read-only + not in admin workgroup + not in workgroup 21
+$db->execute_query("delete from user_workgroup_membership where user_id=701 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=701 and workgroup_id=21", []);
+$db->execute_query(
+ "insert into user_workgroup_membership (workgroup_id,user_id,role) values (?,?,?)",
+ [31, 701, 'read-only']
+);
+
+# user 201: workgroup user with role admin + not in admin workgroup + not in workgroup 31
+$db->execute_query("delete from user_workgroup_membership where user_id=201 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=201 and workgroup_id=31", []);
+
+# user 301: workgroup user with role normal + not in admin workgroup + not in workgroup 31
+$db->execute_query("delete from user_workgroup_membership where user_id=301 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=301 and workgroup_id=31", []);
+$db->execute_query(
+ "insert into user_workgroup_membership (workgroup_id,user_id,role) values (?,?,?)",
+ [21, 301, 'normal']
+);
+
+# user 401: workgroup user with role read-only + not in admin workgroup + not in workgroup 31
+$db->execute_query("delete from user_workgroup_membership where user_id=401 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=401 and workgroup_id=31", []);
+$db->execute_query(
+ "insert into user_workgroup_membership (workgroup_id,user_id,role) values (?,?,?)",
+ [21, 401, 'read-only']
+);
+
+# user 11 (aragusa): admin workgroup user with role admin + not in workgroup 21
+$db->execute_query("update user_workgroup_membership set role='normal' where user_id=31 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=11 and workgroup_id=21", []);
+
+# user 31: admin workgroup user with role normal + not in workgroup 21
+$db->execute_query("update user_workgroup_membership set role='normal' where user_id=31 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=31 and workgroup_id=21", []);
+
+# user 21: admin workgroup user with role read-only + not in workgroup 21
+$db->execute_query("update user_workgroup_membership set role='read-only' where user_id=21 and workgroup_id=11", []);
+$db->execute_query("delete from user_workgroup_membership where user_id=21 and workgroup_id=21", []);
+
+
+# NOTE: circuit 2281 is owned by workgroup 31. interfaces 401 and 751
+# used by circuit 2281 are owned by workgroup 21.
+
+my $tests = [
+ # BEGIN Circuit owners
+ # user 501: workgroup 31 user with role admin + not in admin workgroup + not in workgroup 21
+ { args => { db => $db, user_id => 501, circuit_id => 2281, permission => 'create' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 501, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 501, circuit_id => 2281, permission => 'update' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 501, circuit_id => 2281, permission => 'delete' }, result => { value => 1, error => undef } },
+
+ # user 601: workgroup 31 user with role normal + not in admin workgroup + not in workgroup 21
+ { args => { db => $db, user_id => 601, circuit_id => 2281, permission => 'create' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 601, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 601, circuit_id => 2281, permission => 'update' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 601, circuit_id => 2281, permission => 'delete' }, result => { value => 1, error => undef } },
+
+ # user 701: workgroup 31 user with role read-only + not in admin workgroup + not in workgroup 21
+ { args => { db => $db, user_id => 701, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 701, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 701, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 701, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+ # END Circuit owners
+
+ # BEGIN Interface owners
+ # user 201: workgroup user with role admin + not in admin workgroup
+ { args => { db => $db, user_id => 201, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 201, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 201, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 201, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+
+ # user 301: workgroup user with role normal + not in admin workgroup
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+
+ # user 401: workgroup user with role normal + not in admin workgroup
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 301, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+ # END Interface owners
+
+ # BEGIN Admins
+ # admin workgroup user with a role of admin. has global access to everything.
+ { args => { db => $db, username => 'aragusa', circuit_id => 2281, permission => 'create' }, result => { value => 1, error => undef } },
+ { args => { db => $db, username => 'aragusa', circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, username => 'aragusa', circuit_id => 2281, permission => 'update' }, result => { value => 1, error => undef } },
+ { args => { db => $db, username => 'aragusa', circuit_id => 2281, permission => 'delete' }, result => { value => 1, error => undef } },
+
+ # admin workgroup user with a role of normal. has global access to circuits.
+ { args => { db => $db, user_id => 31, circuit_id => 2281, permission => 'create' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 31, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 31, circuit_id => 2281, permission => 'update' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 31, circuit_id => 2281, permission => 'delete' }, result => { value => 1, error => undef } },
+
+ # admin workgroup user with a role of read-only. has global read access to circuits.
+ { args => { db => $db, user_id => 21, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 21, circuit_id => 2281, permission => 'read' }, result => { value => 1, error => undef } },
+ { args => { db => $db, user_id => 21, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 21, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+ # END Admins
+
+ # user not in admin workgroup, circuit workgroup, or circuit's interfaces' workgroup
+ { args => { db => $db, user_id => 371, circuit_id => 2281, permission => 'create' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 371, circuit_id => 2281, permission => 'read' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 371, circuit_id => 2281, permission => 'update' }, result => { value => 0, error => 1 } },
+ { args => { db => $db, user_id => 371, circuit_id => 2281, permission => 'delete' }, result => { value => 0, error => 1 } },
+];
+
+foreach my $test (@$tests) {
+ my ($result, $error) = OESS::DB::User::has_circuit_permission(%{$test->{args}});
+
+ ok($result == $test->{result}->{value}, "Got '$result'. Expected '$test->{result}->{value}'.");
+ if (defined $test->{result}->{error}) {
+ ok(defined $error, "Got error message '$error'. Expected an error message.");
+ } else {
+ my $error_str = (!defined $error) ? 'undef' : $error;
+ ok(!defined $error, "Got error message '$error_str'. Expected error message 'undef'.");
+ }
+}
diff --git a/perl-lib/OESS/t/z-Object/L2Circuit.nso_diff.00.t b/perl-lib/OESS/t/z-Object/L2Circuit.nso_diff.00.t
new file mode 100644
index 000000000..1d7c0462c
--- /dev/null
+++ b/perl-lib/OESS/t/z-Object/L2Circuit.nso_diff.00.t
@@ -0,0 +1,137 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/..";
+
+
+use Data::Dumper;
+use Test::Deep;
+use Test::More tests => 3;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::L2Circuit;
+
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../conf/database.xml",
+ dbdump => "$path/../conf/oess_known_state.sql"
+);
+
+
+my $db = new OESS::DB(
+ config => "$path/../conf/database.xml"
+);
+
+
+my $nso_l2connection_tests = [];
+
+
+my $nso_l2connection = {
+ 'connection_id' => 3000,
+ 'directly-modified' => {
+ 'services' => [
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'0\'][sdp:name=\'3000\']',
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'1\'][sdp:name=\'3000\']'
+ ],
+ 'devices' => [
+ 'xr0'
+ ]
+ },
+ 'endpoint' => [
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 1,
+ 'interface' => 'GigabitEthernet0/0',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ },
+ {
+ 'bandwidth' => 0,
+ 'endpoint_id' => 2,
+ 'interface' => 'GigabitEthernet0/1',
+ 'tag' => 1,
+ 'device' => 'xr0'
+ }
+ ],
+ 'device-list' => [
+ 'xr0'
+ ],
+ 'modified' => {
+ 'services' => [
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'1\'][sdp:name=\'3000\']',
+ '/i2-common:internal-services/sdp:sdp-attach[sdp:sdp=\'0\'][sdp:name=\'3000\']'
+ ],
+ 'devices' => [
+ 'xr0'
+ ]
+ }
+};
+
+
+my $expect1 = {
+ 'Node 11' => '+ e15/6
++ Bandwidth: 0
++ Tag: 3126
+',
+ 'Node 31' => '+ e15/4
++ Bandwidth: 0
++ Tag: 2005
+',
+ 'xr0' => '- GigabitEthernet0/0
+- Bandwidth: 0
+- Tag: 1
+- GigabitEthernet0/1
+- Bandwidth: 0
+- Tag: 1
+'
+};
+push @$nso_l2connection_tests, { circuit_id => 4081, result => $expect1 };
+
+
+my $expect2 = {
+ 'xr0' => '- GigabitEthernet0/0
+- Bandwidth: 0
+- Tag: 1
+- GigabitEthernet0/1
+- Bandwidth: 0
+- Tag: 1
+'
+};
+push @$nso_l2connection_tests, { model => {}, result => $expect2 };
+
+
+my $expect3 = {};
+push @$nso_l2connection_tests, {
+ model => {
+ endpoints => [
+ { interface => 'GigabitEthernet0/0', node => 'xr0', tag => 1, bandwidth => 0 },
+ { interface => 'GigabitEthernet0/1', node => 'xr0', tag => 1, bandwidth => 0 }
+ ]
+ },
+ result => $expect3
+};
+
+foreach my $test (@$nso_l2connection_tests) {
+ my $conn = new OESS::L2Circuit(
+ db => $db,
+ circuit_id => $test->{circuit_id},
+ model => $test->{model}
+ );
+ $conn->load_endpoints;
+
+ my $result = $conn->nso_diff($nso_l2connection);
+ my $ok = cmp_deeply($result, $test->{result}, 'Human readable diff generated');
+ warn Dumper($result) if !$ok;
+}
diff --git a/perl-lib/OESS/t/z-Object/NSO/FWDCTL.addVlan.00.t b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.addVlan.00.t
new file mode 100644
index 000000000..982d8679b
--- /dev/null
+++ b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.addVlan.00.t
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/../..";
+
+
+use Data::Dumper;
+use Test::More tests => 1;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::L2Circuit;
+use OESS::NSO::ClientStub;
+use OESS::NSO::ConnectionCache;
+use OESS::NSO::FWDCTL;
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../../conf/database.xml",
+ dbdump => "$path/../../conf/oess_known_state.sql"
+);
+
+
+my $cache = new OESS::NSO::ConnectionCache();
+my $db = new OESS::DB(config => "$path/../../conf/database.xml");
+my $nso = new OESS::NSO::ClientStub();
+
+my $fwdctl = new OESS::NSO::FWDCTL(
+ config_filename => "$path/../../conf/database.xml",
+ connection_cache => $cache,
+ db => $db,
+ nso => $nso
+);
+
+
+my $err1 = $fwdctl->addVlan(circuit_id => 4081);
+ok(!defined $err1, 'Vlan created');
diff --git a/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.00.t b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.00.t
new file mode 100644
index 000000000..e174f47ab
--- /dev/null
+++ b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.00.t
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/../..";
+
+
+use Data::Dumper;
+use Test::More tests => 5;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::L2Circuit;
+use OESS::NSO::ClientStub;
+use OESS::NSO::ConnectionCache;
+use OESS::NSO::FWDCTL;
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../../conf/database.xml",
+ dbdump => "$path/../../conf/oess_known_state.sql"
+);
+
+
+my $cache = new OESS::NSO::ConnectionCache();
+my $db = new OESS::DB(config => "$path/../../conf/database.xml");
+my $nso = new OESS::NSO::ClientStub();
+
+
+# OESS::NSO::FWDCTL::get_diff_text works by fetching nodes with
+# controller of 'nso'.
+$db->execute_query("update node_instantiation set controller='nso'", []);
+
+
+my $fwdctl = new OESS::NSO::FWDCTL(
+ config_filename => "$path/../../conf/database.xml",
+ connection_cache => $cache,
+ db => $db,
+ nso => $nso
+);
+
+my $expect1 = {
+ 'Node 11' => '+ e15/6
++ Bandwidth: 0
++ Tag: 3126
+- e15/6
+- Bandwidth: 200
+- Tag: 300
+- Peer 1:
+- Local ASN: 64600
+- Local IP: 192.168.3.2/31
+- Peer ASN: 64001
+- Peer IP: 192.168.3.3
+- BFD: 1
+',
+ 'Node 31' => '+ e15/4
++ Bandwidth: 0
++ Tag: 2005
+',
+ 'xr0' => '- GigabitEthernet0/0
+- Bandwidth: 0
+- Tag: 1
+- GigabitEthernet0/1
+- Bandwidth: 0
+- Tag: 1
+'
+};
+
+my $err = $fwdctl->addVlan(circuit_id => 4081);
+ok(!defined $err, 'Vlan created');
+
+my ($text1, $err1) = $fwdctl->get_diff_text(node_id => 11);
+ok($text1 eq $expect1->{'Node 11'}, 'Got expected diff');
+if ($text1 ne $expect1->{'Node 11'}) {
+ print "Expected:\n$expect1->{'Node 11'}\nGot:\n$text1";
+}
+
+my ($text2, $err2) = $fwdctl->get_diff_text(node_id => 31);
+ok($text2 eq $expect1->{'Node 31'}, 'Got expected diff');
+
+my ($text3, $err3) = $fwdctl->get_diff_text(node_name => 'xr0');
+ok($text3 eq $expect1->{'xr0'}, 'Got expected diff');
+
+
+my $cache2 = new OESS::NSO::ConnectionCache();
+
+my $fwdctl2 = new OESS::NSO::FWDCTL(
+ config_filename => "$path/../../conf/database.xml",
+ connection_cache => $cache2,
+ db => $db,
+ nso => $nso
+);
+
+my $expect2 = {
+ 'xr0' => '- GigabitEthernet0/0
+- Bandwidth: 0
+- Tag: 1
+- GigabitEthernet0/1
+- Bandwidth: 0
+- Tag: 1
+'
+};
+
+my ($text4, $err4) = $fwdctl2->get_diff_text(node_name => 'xr0');
+ok($text4 eq $expect2->{'xr0'}, 'Got expected diff');
diff --git a/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.01.t b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.01.t
new file mode 100644
index 000000000..fa9413aa2
--- /dev/null
+++ b/perl-lib/OESS/t/z-Object/NSO/FWDCTL.get_diff_text.01.t
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/../..";
+
+
+use Data::Dumper;
+use Test::More tests => 4;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::L2Circuit;
+use OESS::NSO::ClientStub;
+use OESS::NSO::ConnectionCache;
+use OESS::NSO::FWDCTL;
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../../conf/database.xml",
+ dbdump => "$path/../../conf/oess_known_state.sql"
+);
+
+
+my $cache = new OESS::NSO::ConnectionCache();
+my $db = new OESS::DB(config => "$path/../../conf/database.xml");
+my $nso = new OESS::NSO::ClientStub();
+
+
+# OESS::NSO::FWDCTL::get_diff_text works by fetching nodes with
+# controller of 'nso'.
+$db->execute_query("update node_instantiation set controller='nso'", []);
+
+
+my $fwdctl = new OESS::NSO::FWDCTL(
+ config_filename => "$path/../../conf/database.xml",
+ connection_cache => $cache,
+ db => $db,
+ nso => $nso
+);
+
+my $expect1 = {
+ 'Node 31' => '+ e15/4
++ Bandwidth: 100
++ Tag: 2010
++ Peer 2:
++ Local ASN: 7
++ Local IP: 192.168.2.2/31
++ Peer ASN: 64602
++ Peer IP: 192.168.2.3
++ BFD: 0
+',
+ 'Node 11' => ' e15/6
+- Bandwidth: 200
++ Bandwidth: 100
+- Tag: 300
++ Tag: 3010
+ Peer 1:
+- Local IP: 192.168.3.2/31
++ Local IP: 192.168.1.2/31
+- Peer ASN: 64001
++ Peer ASN: 64601
+- Peer IP: 192.168.3.3
++ Peer IP: 192.168.1.3
+- BFD: 1
++ BFD: 0
++ Peer 3:
++ Local ASN:
++ Local IP: 192.168.5.2/31
++ Peer ASN: 64605
++ Peer IP: 192.168.5.3
++ BFD: 0
+',
+ 'xr1' => '- GigabitEthernet0/1
+- Bandwidth: 100
+- Tag: 300
+- Peer 2:
+- Local ASN: 64600
+- Local IP: 192.168.2.2/31
+- Peer ASN: 64602
+- Peer IP: 192.168.2.3
+- BFD: 0
+'
+};
+
+my $err = $fwdctl->addVrf(vrf_id => 1);
+ok(!defined $err, 'Vrf created');
+
+my ($text1, $err1) = $fwdctl->get_diff_text(node_id => 11);
+ok($text1 eq $expect1->{'Node 11'}, 'Got expected diff');
+
+my ($text2, $err2) = $fwdctl->get_diff_text(node_id => 31);
+ok($text2 eq $expect1->{'Node 31'}, 'Got expected diff');
+
+my ($text3, $err3) = $fwdctl->get_diff_text(node_name => 'xr1');
+ok($text3 eq $expect1->{'xr1'}, 'Got expected diff');
diff --git a/perl-lib/OESS/t/z-Object/VRF.nso_diff.00.t b/perl-lib/OESS/t/z-Object/VRF.nso_diff.00.t
new file mode 100644
index 000000000..28cab6b18
--- /dev/null
+++ b/perl-lib/OESS/t/z-Object/VRF.nso_diff.00.t
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+my $path;
+
+BEGIN {
+ if ($FindBin::Bin =~ /(.*)/) {
+ $path = $1;
+ }
+}
+use lib "$path/..";
+
+
+use Data::Dumper;
+use Test::Deep;
+use Test::More tests => 1;
+
+use OESSDatabaseTester;
+
+use OESS::DB;
+use OESS::VRF;
+use OESS::NSO::ClientStub;
+
+OESSDatabaseTester::resetOESSDB(
+ config => "$path/../conf/database.xml",
+ dbdump => "$path/../conf/oess_known_state.sql"
+);
+
+
+my $db = new OESS::DB(
+ config => "$path/../conf/database.xml"
+);
+
+
+my $nso_l3connection_tests = [];
+
+my $nso = new OESS::NSO::ClientStub();
+
+my ($nso_l3connections, $err) = $nso->get_l3connections();
+my $nso_l3connection = $nso_l3connections->[0];
+
+my $expect1 = {
+ 'Node 31' => '+ e15/4
++ Bandwidth: 100
++ Tag: 2010
++ Peer 2:
++ Local ASN: 7
++ Local IP: 192.168.2.2/31
++ Peer ASN: 64602
++ Peer IP: 192.168.2.3
++ BFD: 0
+',
+ 'Node 11' => ' e15/6
+- Bandwidth: 200
++ Bandwidth: 100
+- Tag: 300
++ Tag: 3010
+ Peer 1:
+- Local IP: 192.168.3.2/31
++ Local IP: 192.168.1.2/31
+- Peer ASN: 64001
++ Peer ASN: 64601
+- Peer IP: 192.168.3.3
++ Peer IP: 192.168.1.3
+- BFD: 1
++ BFD: 0
++ Peer 3:
++ Local ASN:
++ Local IP: 192.168.5.2/31
++ Peer ASN: 64605
++ Peer IP: 192.168.5.3
++ BFD: 0
+',
+ 'xr1' => '- GigabitEthernet0/1
+- Bandwidth: 100
+- Tag: 300
+- Peer 2:
+- Local ASN: 64600
+- Local IP: 192.168.2.2/31
+- Peer ASN: 64602
+- Peer IP: 192.168.2.3
+- BFD: 0
+'
+};
+push @$nso_l3connection_tests, { vrf_id => 1, result => $expect1 };
+
+
+foreach my $test (@$nso_l3connection_tests) {
+ my $conn = new OESS::VRF(
+ db => $db,
+ vrf_id => $test->{vrf_id},
+ model => $test->{model}
+ );
+ $conn->load_endpoints;
+ foreach my $ep (@{$conn->endpoints}) {
+ $ep->load_peers;
+ }
+
+ my $result = $conn->nso_diff($nso_l3connection);
+ my $ok = cmp_deeply($result, $test->{result}, 'Human readable diff generated');
+ warn Dumper($result) if !$ok;
+}