else messages.debug ("debug_query: " + msg + " query= " + query);
}
+// http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript
+// attach the .equals method to Array's prototype to call it on any array
+Array.prototype.equals = function (array) {
+ // if the other array is a falsy value, return
+ if (!array)
+ return false;
+
+ // compare lengths - can save a lot of time
+ if (this.length != array.length)
+ return false;
+
+ for (var i = 0, l=this.length; i < l; i++) {
+ // Check if we have nested arrays
+ if (this[i] instanceof Array && array[i] instanceof Array) {
+ // recurse into the nested arrays
+ if (!this[i].equals(array[i]))
+ return false;
+ }
+ else if (this[i] != array[i]) {
+ // Warning - two different object instances will never be equal: {x:20} != {x:20}
+ return false;
+ }
+ }
+ return true;
+}
+
// http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
Object.toType = (function toType(global) {
return function(obj) {
* RECORD STATES (for query_store)
******************************************************************************/
-var STATE_SET = 0;
-var STATE_VALUE = 1;
-var STATE_WARNINGS = 2;
-var STATE_VISIBLE = 3;
+var STATE_SET = 20;
+var STATE_VALUE = 21;
+var STATE_WARNINGS = 22;
+var STATE_VISIBLE = 23;
// ACTIONS
var STATE_SET_CHANGE = 0;
var CONSTRAINT_RESERVABLE_LEASE_MSG = "Configuration required: this resource needs to be scheduled";
+var CONSTRAINT_SLA = 1;
+
+var CONSTRAINT_SLA_MSG = "SLA acceptance required: testbed offers SLA for its resources"
+
// A structure for storing queries
function QueryExt(query, parent_query_ext, main_query_ext, update_query_ext, disabled, domain_query_ext) {
// XXX query.change_action() should become deprecated
update_query = query.clone();
update_query.action = 'update';
+ update_query.fields = [];
update_query.analyzed_query.action = 'update';
update_query.params = {};
update_query_ext = new QueryExt(update_query);
default_set = (default_set === undefined) ? STATE_SET_OUT : default_set;
var self = this;
- var query_ext = this.find_analyzed_query_ext(query_uuid);
- var record_key = manifold.metadata.get_key(query_ext.query.object);
+ var key, object, query_ext, record_key;
+
+ query_ext = this.find_analyzed_query_ext(query_uuid);
+ object = query_ext.query.object;
+ if (object.indexOf(':') != -1) {
+ object = object.split(':')[1];
+ }
+ record_key = manifold.metadata.get_key(object);
+
+ // ["start_time", "resource", "end_time"]
+ // ["urn"]
+
$.each(records, function(i, record) {
- var key = manifold.metadata.get_key(query_ext.query.object);
- // ["start_time", "resource", "end_time"]
- // ["urn"]
+ //var key = manifold.metadata.get_key(query_ext.query.object);
var record_key_value = manifold.record_get_value(record, record_key);
query_ext.records.put(record_key_value, record);
return query_ext.records.get(record_key);
}
+ this.del_record = function(query_uuid, record_key)
+ {
+ var query_ext = this.find_analyzed_query_ext(query_uuid);
+ return query_ext.records.remove(record_key);
+ }
+
+ this.del_state = function(query_uuid, record_key)
+ {
+ var query_ext = this.find_analyzed_query_ext(query_uuid);
+ return query_ext.state.remove(record_key);
+ }
+
this.add_record = function(query_uuid, record, new_state)
{
var query_ext, key, record_key;
} else {
record_key = record;
}
-
- manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state);
+
+ if ((query_ext.query.object == 'lease') && (new_state == STATE_SET_OUT)) {
+ // Leases that are marked out are in fact leases from other slices
+ // We need to _remove_ leases that we mark as OUT
+ manifold.query_store.del_record(query_uuid, record_key);
+ manifold.query_store.del_state(query_uuid, record_key);
+ } else {
+ manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state);
+ }
}
this.iter_records = function(query_uuid, callback)
{
var query_ext = this.find_analyzed_query_ext(query_uuid);
query_ext.filters = $.grep(query_ext.filters, function(x) {
- return x == filter;
+ return !(x.equals(filter));
});
this.apply_filters(query_uuid);
this.recount = function(query_uuid)
{
var query_ext;
- var is_reserved, is_pending, in_set, is_unconfigured;
+ var is_reserved, is_pending, in_set, is_unconfigured, is_unavailable, is_available;
query_ext = manifold.query_store.find_analyzed_query_ext(query_uuid);
query_ext.num_pending = 0;
this.iter_records(query_uuid, function(record_key, record) {
var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET);
var record_warnings = manifold.query_store.get_record_state(query_uuid, record_key, STATE_WARNINGS);
+ is_unavailable = (record.available == 'false');
+ is_available = (record.available == 'true');
is_reserved = (record_state == STATE_SET_IN)
|| (record_state == STATE_SET_OUT_PENDING)
// Adapted from querytable._querytable_filter()
this.iter_records(query_uuid, function(record_key, record) {
- var is_reserved, is_pending, in_set, is_unconfigured;
+ var is_reserved, is_pending, in_set, is_unconfigured, is_unavailable, is_available;
+
+ /* By default, a record is visible unless a filter says the opposite */
var visible = true;
var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET);
var record_warnings = manifold.query_store.get_record_state(query_uuid, record_key, STATE_WARNINGS);
+ is_unavailable = (record.available == 'false');
+ is_available = (record.available == 'true');
+
is_reserved = (record_state == STATE_SET_IN)
|| (record_state == STATE_SET_OUT_PENDING)
|| (record_state == STATE_SET_IN_SUCCESS)
// false => ~ break
visible = is_reserved;
return visible;
+ case 'available':
+ visible = is_available;
+ return visible;
+ case 'unavailable':
+ visible = is_unavailable;
+ return visible;
case 'unconfigured':
visible = is_unconfigured;
return visible;
if (op == '=' || op == '==') {
if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
visible = false;
+
}else if (op == 'included') {
+ /* By default, the filter returns false unless the record
+ * field match at least one value of the included statement
+ */
+ visible = false;
$.each(value, function(i,x) {
if(x == col_value){
visible = true;
return false; // ~ break
- }else{
- visible = false;
}
});
}else if (op == '!=') {
});
var end = new Date().getTime();
- console.log("APPLY FILTERS took", end - start, "ms");
+ console.log("APPLY FILTERS [", filters, "] took", end - start, "ms");
}
} else {
console.log('Unknown field');
}
+ // FIX if the record contains a string instead of a key:value
+ // example: select resource, slice_hrn from slice where slice_hrn=='xxx'
+ // Result will be {slice_hrn:'xxx', resource:'urn+zzz'}
+ // We don't have this resource:{urn:'urn+zzz'}
+ } else if(typeof(record) === 'string'){
+ return record;
} else {
return record[fields];
}
{
return function() {
ret = "";
- for (i=0; i < key_fields.length; i++)
+ for (var i=0; i < key_fields.length; i++)
ret += "@@" + this[key_fields[i]];
return ret;
};
_record_equals: function(self, other, key_fields)
{
- for (i=0; i < key_fields.length; i++) {
+ if ((typeof self === "string") && (typeof other === "string")) {
+ return self == other;
+ }
+ for (var i=0; i < key_fields.length; i++) {
var this_value = self[key_fields[i]];
var other_value = other[key_fields[i]];
switch (this_type) {
case TYPE_VALUE:
case TYPE_LIST_OF_VALUES:
+ case TYPE_LIST_OF_RECORDS:
if (this_value != other_value)
return false;
break;
if (!(_record_equals(this_value, other_value, key_fields)))
return false;
break;
+ /*
+ XXX WARNING = disabled for OpenFlow plugin !!!
+
case TYPE_LIST_OF_RECORDS:
if (this_value.length != other_value.length)
return false;
- for (i = 0; i < this_value.length; i++)
- if (!(_record_equals(this_value, other_value, key_fields)))
+ for (var j = 0; j < this_value.length; j++)
+ if (!(_record_equals(this_value[j], other_value[j], key_fields)))
return false;
break;
+ */
}
}
return true;
_in_array: function(element, array, key_fields)
{
if (key_fields.length > 1) {
- for (i = 0; i < array.length; i++) {
+ for (var i = 0; i < array.length; i++) {
if (manifold._record_equals(element, array[i], key_fields))
return true;
}
var query_ext = manifold.query_store.find_query_ext(query.query_uuid);
query_ext.query_state = QUERY_STATE_INPROGRESS;
- var query_json = JSON.stringify(query);
+ /*
+ If the Query object concerns SFA AM objects, iterate on each AM platform
+ Loop per platform, allows a progressive loading per AM platform
+ Update is run on all platforms at the same time to get a final answer, we don't manage partial answers yet...
+ */
+ // Removed slice from the per platform query - it's quick enough...
+ if((query.object == 'resource' || query.object == 'lease') && query.action != "update"){
+ var obj = query.object;
+ $.post("/rest/platform/", function( data ) {
+ $.each(data, function(index, p) {
+ query.object = p.platform+":"+obj;
+ var query_json = JSON.stringify(query);
+
+ // Inform plugins about the progress
+ query.iter_subqueries(function (sq) {
+ var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid);
+ sq_query_ext.query_state = QUERY_STATE_INPROGRESS;
+ manifold.raise_record_event(sq.query_uuid, IN_PROGRESS);
+ });
- // Inform plugins about the progress
- query.iter_subqueries(function (sq) {
- var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid);
- sq_query_ext.query_state = QUERY_STATE_INPROGRESS;
+ $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback));
- manifold.raise_record_event(sq.query_uuid, IN_PROGRESS);
- });
+ });
+ });
+ }else{
+ var query_json = JSON.stringify(query);
- $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback));
+ // Inform plugins about the progress
+ query.iter_subqueries(function (sq) {
+ var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid);
+ sq_query_ext.query_state = QUERY_STATE_INPROGRESS;
+ manifold.raise_record_event(sq.query_uuid, IN_PROGRESS);
+ });
+
+ $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback));
+
+ }
},
// XXX DEPRECATED
* \param array results results corresponding to query
*/
publish_result: function(query, result) {
- if (typeof result === 'undefined')
+ if (result == null || typeof result === 'undefined')
result = [];
// NEW PLUGIN API
},
store_records: function(query, records) {
- // Store records
- var query_ext = manifold.query_store.find_analyzed_query_ext(query.query_uuid);
- if (query_ext.set_query_ext) {
- // We have a domain query
- // The results are stored in the corresponding set_query
- manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records)
-
- } else if (query_ext.domain_query_ext) {
- // We have a set query, it is only used to determine which objects are in the set, we should only retrieve the key
- // Has it a domain query, and has it completed ?
- $.each(records, function(i, record) {
- var key = manifold.metadata.get_key(query.object);
- var record_key = manifold.record_get_value(record, key);
- manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_SET, STATE_SET_IN);
- });
+ if(records != null && records.length != 0){
+ // Store records
+ var query_ext = manifold.query_store.find_analyzed_query_ext(query.query_uuid);
+ if (query_ext.set_query_ext) {
+ // We have a domain query
+ // The results are stored in the corresponding set_query
+ manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records);
+
+ } else if (query_ext.domain_query_ext) {
+ // We have a set query, it is only used to determine which objects are in the set, we should only retrieve the key
+ // Has it a domain query, and has it completed ?
+ $.each(records, function(i, record) {
+ var key = manifold.metadata.get_key(query.object);
+ if ( typeof record === "string" ){
+ var record_key = record;
+ }else{
+ var record_key = manifold.record_get_value(record, key);
+ }
+ manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_SET, STATE_SET_IN);
+ });
- } else {
- // We have a normal query
- manifold.query_store.set_records(query.query_uuid, records, STATE_SET_IN);
+ } else {
+ // We have a normal query
+ manifold.query_store.set_records(query.query_uuid, records, STATE_SET_IN);
+ }
}
},
make_record: function(object, record)
{
// To make an object a record, we just add the hash function
- var key = manifold.metadata.get_key(object);
- record.hashCode = manifold.record_hashcode(record, key.sort());
- record.equals = manifold.record_equals(record, key);
+ var key, new_object;
+
+ if (object.indexOf(':') != -1) {
+ new_object = object.split(':')[1];
+ } else {
+ new_object = object;
+ }
+
+ key = manifold.metadata.get_key(new_object);
+ if (!key){
+ console.log("object type: " + new_object + " has no key");
+ console.log(record);
+ return;
+ }
+ record.hashCode = manifold.record_hashcode(key.sort());
+ record.equals = manifold.record_equals(key);
// Looking after subrecords
for (var field in record) {
*/
case TYPE_LIST_OF_VALUES: // XXX Until fixed
case TYPE_LIST_OF_RECORDS:
- var new_state,cur_query_uuid;
-
- cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid;
+ var key, new_state, cur_query_uuid;
+ if($.inArray(field,Object.keys(query.analyzed_query.subqueries)) > -1){
+ cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid;
+ }
// example: slice.resource
// - update_query_orig.params.resource = resources in slice before update
// - update_query.params.resource = resource requested in slice
// - keys from field = resources obtained
- var key = manifold.metadata.get_key(field);
+
+ if (field == 'lease') {
+ // lease_id has been added to be repeated when
+ // constructing request rspec. We don't want it for
+ // comparisons
+ key = ['start_time', 'end_time', 'resource'];
+ } else {
+ key = manifold.metadata.get_key(field);
+ }
if (!key)
continue;
/*
data = { state: STATE_SET, key : field, op : new_state, value: added_key }
manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data);
+
+ // Inform subquery also
+ data.key = '';
+ manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data);
+ // XXX Passing no parameters so that they can redraw everything would
+ // be more efficient but is currently not supported
+ // XXX We could also need to inform plugins about nodes IN (not pending) that are no more, etc.
+ // XXX refactor all this when suppressing update_queries, and relying on state instead !
});
$.each(removed_keys, function(i, removed_key) {
new_state = (manifold._in_array(removed_key, result_keys, key)) ? STATE_SET_OUT_FAILURE : STATE_SET_OUT_SUCCESS;
data = { state: STATE_SET, key : field, op : new_state, value: removed_key }
manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data);
+
+ // Inform subquery also
+ data.key = '';
+ manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data);
});
break;
var query_ext = manifold.query_store.find_query_ext(query.query_uuid);
query_ext.query_state = QUERY_STATE_DONE;
+ var tmp_query = manifold.query_store.find_analyzed_query(query.query_uuid);
+ manifold.publish_result_rec(tmp_query, records);
+
// Send DONE message to plugins
query.iter_subqueries(function(sq, data, parent_query) {
manifold.raise_record_event(sq.query_uuid, DONE);
}
},
- _enforce_constraints: function(query_ext, record, resource_key, event_type)
+ _enforce_constraints: function(query_ext, record, record_key, event_type)
{
var query, data;
query = query_ext.query;
+ var testbeds_with_sla = localStorage.getItem("sla_testbeds").split(",");
+
switch(query.object) {
case 'resource':
+
+ var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS);
// CONSTRAINT_RESERVABLE_LEASE
//
// +) If a reservable node is added to the slice, then it should have a corresponding lease
// XXX Not always a resource
- var is_reservable = (record.exclusive == true);
+ var is_reservable = (record.exclusive == 'true');
if (is_reservable) {
- var warnings = manifold.query_store.get_record_state(query.query_uuid, resource_key, STATE_WARNINGS);
+ // var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS);
if (event_type == STATE_SET_ADD) {
// We should have a lease_query associated
var lease_query = query_ext.parent_query_ext.query.subqueries['lease']; // in options
var lease_query_ext = manifold.query_store.find_analyzed_query_ext(lease_query.query_uuid);
// Do we have lease records (in) with this resource
- var lease_records = $.grep(lease_query_ext.records.entries(), this._grep_active_lease_callback(lease_query, resource_key));
+ var lease_records = $.grep(lease_query_ext.records.entries(), this._grep_active_lease_callback(lease_query, record_key));
if (lease_records.length == 0) {
// Sets a warning
// XXX Need for a better function to manage warnings
var warn = CONSTRAINT_RESERVABLE_LEASE_MSG;
warnings[CONSTRAINT_RESERVABLE_LEASE] = warn;
+
+ /*manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings);
+ // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark)
+ data = {
+ state: STATE_WARNINGS,
+ key : record_key,
+ op : null,
+ value : warnings
+ }
+ manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data);*/
+
} else {
// Lease are defined, delete the warning in case it was set previously
delete warnings[CONSTRAINT_RESERVABLE_LEASE];
// Remove warnings attached to this resource
delete warnings[CONSTRAINT_RESERVABLE_LEASE];
}
-
- manifold.query_store.set_record_state(query.query_uuid, resource_key, STATE_WARNINGS, warnings);
}
- /* This was redundant */
- // manifold.query_store.recount(query.query_uuid);
+ var urn_regexp = /\+(.*?)\+/;
+ var testbed_urn = urn_regexp.exec(record.urn)[1];
+ var has_sla = $.inArray(testbed_urn, testbeds_with_sla) != -1;
+
+ if (has_sla) {
+ // var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS);
+
+ if (event_type == STATE_SET_ADD) {
+ var warn = CONSTRAINT_SLA_MSG;
+ warnings[CONSTRAINT_SLA] = warn;
+ } else {
+ delete warnings[CONSTRAINT_SLA];
+ }
+ }
+ manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings);
// Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark)
data = {
state: STATE_WARNINGS,
- key : resource_key,
+ key : record_key,
op : null,
value : warnings
}
manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data);
+
+ // JGLL: SLA code
+ /*get_testbeds_with_sla()
+ .done( function(testbeds) {
+ var urn_regexp = /\+(.*?)\+/;
+ var testbed_urn = urn_regexp.exec(record.urn)[1];
+
+ var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS);
+
+ if ($.inArray(testbed_urn, testbeds) != -1) {
+ // JGLL: Set a warning on resources covered by testbeds offering SLAs
+ // CONSTRAINT_SLA
+
+ if (event_type == STATE_SET_ADD) {
+ var warn = CONSTRAINT_SLA_MSG;
+ warnings[CONSTRAINT_SLA] = warn;
+ } else {
+ delete warnings[CONSTRAINT_SLA]
+ }
+ }
+
+ manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings);
+
+ // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark)
+ data = {
+ state: STATE_WARNINGS,
+ key : record_key,
+ op : null,
+ value : warnings
+ }
+
+ manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data);
+ })
+ .fail( function(err) {
+ console.log("SLA - Error retrieving testbeds that support SLAs");
+ });*/
+
+ /* This was redundant */
+ // manifold.query_store.recount(query.query_uuid);
+
break;
case 'lease':
- var resource_key = record.resource;
+ var resource_key = record_key.resource;
var resource_query = query_ext.parent_query_ext.query.subqueries['resource'];
var warnings = manifold.query_store.get_record_state(resource_query.query_uuid, resource_key, STATE_WARNINGS);
- if (event_type == STATE_SET_ADD) {
+ if (event_type == STATE_SET_ADD || event_type == STATE_SET_IN_PENDING) {
// A lease is added, it removes the constraint
delete warnings[CONSTRAINT_RESERVABLE_LEASE];
} else {
// XXX Need for a better function to manage warnings
var warn = CONSTRAINT_RESERVABLE_LEASE_MSG;
warnings[CONSTRAINT_RESERVABLE_LEASE] = warn;
+
+ // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark)
+ data = {
+ state: STATE_WARNINGS,
+ key : resource_key,
+ op : null,
+ value : warnings
+ }
+ manifold.raise_record_event(resource_query.query_uuid, FIELD_STATE_CHANGED, data);
} else {
// Lease are defined, delete the warning in case it was set previously
delete warnings[CONSTRAINT_RESERVABLE_LEASE];
}
-
}
-
+ /* Adding a lease can remove a warning and reduce the unconfigured resources */
manifold.query_store.recount(resource_query.query_uuid);
-
- // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark)
- data = {
- state: STATE_WARNINGS,
- key : resource_key,
- op : null,
- value : warnings
- }
- manifold.raise_record_event(resource_query.query_uuid, FIELD_STATE_CHANGED, data);
break;
}
query = query_ext.query;
switch(event_type) {
+ case STATUS_REMOVE_WARNING:
+ record = manifold.query_store.get_record(query_uuid, data.value);
+ this._enforce_constraints(query_ext, record, data.value, STATE_SET_REMOVE);
+ break;
// XXX At some point, should be renamed to RECORD_STATE_CHANGED
case FIELD_STATE_CHANGED:
/* Process update query in parent */
path = this._get_query_path(query_ext);
arr = update_query.params[path];
- arr = $.grep(arr, function(x) { return x != data.value; });
+
+ var key = manifold.metadata.get_key(query.object);
+ arr = $.grep(arr, function(x) { return (!(manifold._record_equals(x, data.value, key))); });
if (update_query.params[path] === undefined)
update_query.params[path] = Array();
update_query.params[path] = arr;
break;
case RUN_UPDATE:
+ query_ext.main_query_ext.update_query_ext.query.fields = [];
manifold.run_query(query_ext.main_query_ext.update_query_ext.query);
break;
// FILTERS
case FILTER_ADDED:
+ console.log("FILTER ADDED", data);
/* Update internal record state */
manifold.query_store.add_filter(query_uuid, data);
break;
case FILTER_REMOVED:
+ console.log("FILTER REMOVED", data);
/* Update internal record state */
manifold.query_store.remove_filter(query_uuid, data);