fuel-ui/static/js/models.js

826 lines
35 KiB
JavaScript

/*
* Copyright 2013 Mirantis, Inc.
*
* 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.
**/
define(['utils', 'deepModel'], function(utils) {
'use strict';
var models = {};
var cacheMixin = {
fetch: function(options) {
if (this.cacheFor && options && options.cache && this.lastSyncTime && (this.cacheFor > (new Date() - this.lastSyncTime))) {
return $.Deferred().resolve();
}
return this.constructor.__super__.fetch.apply(this, arguments);
},
sync: function(options) {
if (this.cacheFor) {
this.lastSyncTime = new Date();
}
return this.constructor.__super__.sync.apply(this, arguments);
}
};
models.Release = Backbone.Model.extend({
constructorName: 'Release',
urlRoot: '/api/releases'
});
models.Releases = Backbone.Collection.extend({
constructorName: 'Releases',
model: models.Release,
url: '/api/releases',
comparator: function(release1, release2) {
var version1 = release1.get('version'), version2 = release2.get('version');
if (version1 == version2) {
var name1 = release1.get('name').toLowerCase(), name2 = release2.get('name').toLowerCase();
return name1 > name2 ? 1 : name1 < name2 ? -1 : 0;
}
return version1 < version2 ? 1 : -1;
}
});
models.Cluster = Backbone.Model.extend({
constructorName: 'Cluster',
urlRoot: '/api/clusters',
defaults: function() {
var defaults = {
nodes: new models.Nodes(),
tasks: new models.Tasks()
};
defaults.nodes.cluster = defaults.tasks.cluster = this;
return defaults;
},
validate: function(attrs) {
var errors = {};
if (!$.trim(attrs.name) || $.trim(attrs.name).length == 0) {
errors.name = 'Environment name cannot be empty';
}
if (!attrs.release) {
errors.release = 'Please choose OpenStack release';
}
return _.isEmpty(errors) ? null : errors;
},
groupings: function() {
return {roles: $.t('cluster_page.nodes_tab.roles'), hardware: $.t('cluster_page.nodes_tab.hardware_info'), both: $.t('cluster_page.nodes_tab.roles_and_hardware_info')};
},
task: function(filter1, filter2) {
var filters = _.isPlainObject(filter1) ? filter1 : {name: filter1, status: filter2};
return this.get('tasks') && this.get('tasks').findTask(filters);
},
tasks: function(filter1, filter2) {
var filters = _.isPlainObject(filter1) ? filter1 : {name: filter1, status: filter2};
return this.get('tasks') && this.get('tasks').filterTasks(filters);
},
hasChanges: function() {
return this.get('nodes').hasChanges() || (this.get('changes').length && this.get('nodes').currentNodes().length);
},
needsRedeployment: function() {
return this.get('nodes').where({pending_addition: false, status: 'error'}).length && (this.get('status') != 'update_error');
},
availableModes: function() {
return ['ha_compact', 'multinode'];
},
fetchRelated: function(related, options) {
return this.get(related).fetch(_.extend({data: {cluster_id: this.id}}, options));
},
isAvailableForSettingsChanges: function() {
return this.get('status') == 'new' || (this.get('status') == 'stopped' && !this.get('nodes').where({status: 'ready'}).length);
}
});
models.Clusters = Backbone.Collection.extend({
constructorName: 'Clusters',
model: models.Cluster,
url: '/api/clusters',
comparator: 'id'
});
models.Node = Backbone.Model.extend({
constructorName: 'Node',
urlRoot: '/api/nodes',
resource: function(resourceName) {
var resource = 0;
try {
if (resourceName == 'cores') {
resource = this.get('meta').cpu.total;
} else if (resourceName == 'hdd') {
resource = _.reduce(this.get('meta').disks, function(hdd, disk) {return _.isNumber(disk.size) ? hdd + disk.size : hdd;}, 0);
} else if (resourceName == 'ram') {
resource = this.get('meta').memory.total;
} else if (resourceName == 'disks') {
resource = _.pluck(this.get('meta').disks, 'size').sort(function(a, b) {return a - b;});
} else if (resourceName == 'interfaces') {
resource = this.get('meta').interfaces.length;
}
} catch (ignore) {}
if (_.isNaN(resource)) {
resource = 0;
}
return resource;
},
sortedRoles: function() {
var preferredOrder = this.collection.cluster.get('release').get('roles');
return _.union(this.get('roles'), this.get('pending_roles')).sort(function(a, b) {
return _.indexOf(preferredOrder, a) - _.indexOf(preferredOrder, b);
});
},
toJSON: function(options) {
var result = this.constructor.__super__.toJSON.call(this, options);
return _.omit(result, 'checked');
},
isSelectable: function() {
return this.get('status') != 'error' || this.get('cluster');
},
hasRole: function(role, onlyDeployedRoles) {
var roles = onlyDeployedRoles ? this.get('roles') : _.union(this.get('roles'), this.get('pending_roles'));
return _.contains(roles, role);
},
getRolesSummary: function() {
var rolesMetaData = this.collection.cluster.get('release').get('roles_metadata');
return _.map(this.sortedRoles(), function(role) {return rolesMetaData[role].name;}).join(', ');
},
getHardwareSummary: function() {
return $.t('node_details.hdd') + ': ' + utils.showDiskSize(this.resource('hdd')) + ' \u00A0 ' + $.t('node_details.ram') + ': ' + utils.showMemorySize(this.resource('ram'));
}
});
models.Nodes = Backbone.Collection.extend({
constructorName: 'Nodes',
model: models.Node,
url: '/api/nodes',
comparator: 'id',
hasChanges: function() {
return !!this.filter(function(node) {
return node.get('pending_addition') || node.get('pending_deletion') || node.get('pending_roles').length;
}).length;
},
currentNodes: function() {
return this.filter(function(node) {return !node.get('pending_addition');});
},
nodesAfterDeployment: function() {
return this.filter(function(node) {return node.get('pending_addition') || !node.get('pending_deletion');});
},
nodesAfterDeploymentWithRole: function(role) {
return _.filter(this.nodesAfterDeployment(), function(node) {return _.contains(_.union(node.get('roles'), node.get('pending_roles')), role);}).length;
},
resources: function(resourceName) {
var resources = this.map(function(node) {return node.resource(resourceName);});
return _.reduce(resources, function(sum, n) {return sum + n;}, 0);
},
getByIds: function(ids) {
return this.filter(function(node) {return _.contains(ids, node.id);});
},
groupByAttribute: function(attr) {
if (attr == 'roles') {
return this.groupBy(function(node) {return node.getRolesSummary();});
}
if (attr == 'hardware') {
return this.groupBy(function(node) {return node.getHardwareSummary();});
}
return this.groupBy(function(node) {return node.getRolesSummary() + '; \u00A0' + node.getHardwareSummary();});
}
});
models.NodesStatistics = Backbone.Model.extend({
constructorName: 'NodesStatistics',
urlRoot: '/api/nodes/allocation/stats'
});
models.Task = Backbone.Model.extend({
constructorName: 'Task',
urlRoot: '/api/tasks',
releaseId: function() {
var id;
try {
id = this.get('result').release_info.release_id;
} catch (ignore) {}
return id;
},
groups: {
release_setup: ['redhat_setup'],
network: ['verify_networks', 'check_networks'],
deployment: ['update', 'stop_deployment', 'deploy', 'reset_environment']
},
extendGroups: function(filters) {
return _.union(utils.composeList(filters.name), _.flatten(_.map(utils.composeList(filters.group), _.bind(function(group) {return this.groups[group];}, this))));
},
match: function(filters) {
filters = filters || {};
var result = false;
if (filters.group || filters.name) {
if (_.contains(this.extendGroups(filters), this.get('name'))) {
result = true;
if (filters.status) {
result = _.contains(utils.composeList(filters.status), this.get('status'));
}
if (filters.release) {
result = result && this.releaseId() == filters.release;
}
}
} else if (filters.status) {
result = _.contains(utils.composeList(filters.status), this.get('status'));
}
return result;
}
});
models.Tasks = Backbone.Collection.extend({
constructorName: 'Tasks',
model: models.Task,
url: '/api/tasks',
toJSON: function(options) {
return this.pluck('id');
},
comparator: 'id',
filterTasks: function(filters) {
return _.flatten(_.map(this.model.prototype.extendGroups(filters), function(name) {
return this.filter(function(task) {
return task.match(_.extend(_.omit(filters, 'group'), {name: name}));
});
}, this));
},
findTask: function(filters) {
return this.filterTasks(filters)[0];
},
bindToView: function(view, filters, bindCallback, addCallback, removeCallback) {
bindCallback = _.bind(bindCallback, view);
addCallback = _.bind(addCallback || view.render, view);
removeCallback = _.bind(removeCallback || view.render, view);
function taskMatchesFilters(task) {
return _.any(filters, task.match, task);
}
function onTaskAdd(task) {
if (taskMatchesFilters(task)) {
bindCallback(task);
addCallback();
}
}
function onTaskRemove(task) {
if (taskMatchesFilters(task)) {
removeCallback();
}
}
this.each(function(task) {
if (taskMatchesFilters(task)) {
bindCallback(task);
}
});
this.on('add', onTaskAdd, view);
this.on('remove', onTaskRemove, view);
}
});
models.Notification = Backbone.Model.extend({
constructorName: 'Notification',
urlRoot: '/api/notifications'
});
models.Notifications = Backbone.Collection.extend({
constructorName: 'Notifications',
model: models.Notification,
url: '/api/notifications',
comparator: 'id'
});
models.Settings = Backbone.DeepModel.extend({
constructorName: 'Settings',
urlRoot: '/api/clusters/',
cacheFor: 60 * 1000,
isNew: function() {
return false;
},
parse: function(response) {
return response.editable;
},
toJSON: function(options) {
var currentSettings = this.constructor.__super__.toJSON.call(this, options);
if (this.initialAttributes) {
var result = _.cloneDeep(this.initialAttributes);
_.each(currentSettings, function(group, groupName) {
_.each(group, function(setting, settingName) {
if (settingName == 'metadata') {
if (!_.isUndefined(setting.toggleable)) {
result[groupName][settingName].enabled = setting.enabled;
}
} else {
result[groupName][settingName].value = setting.value;
}
});
}, this);
return {editable: result};
}
return {editable: currentSettings};
},
expandRestrictions: function() {
_.each(this.attributes, function(group, groupName) {
_.each(group, function(setting, settingName) {
setting.restrictions = _.map(setting.restrictions, utils.expandRestriction);
_.each(setting.values, function(value) {
value.restrictions = _.map(value.restrictions, utils.expandRestriction);
});
}, this);
}, this);
},
validate: function(attrs) {
var errors = [];
_.each(attrs, function(group, groupName) {
if (group.metadata && (group.metadata.disabled || !group.metadata.visible)) { return; }
_.each(group, function(setting, settingName) {
if (!(setting.regex && setting.regex.source) || setting.disabled) { return; }
var regExp = new RegExp(setting.regex.source);
if (!setting.value.match(regExp)) {
errors.push({
field: groupName + '.' + settingName,
message: setting.regex.error
});
}
});
});
return errors.length ? errors : null;
}
});
_.extend(models.Settings.prototype, cacheMixin);
models.Disk = Backbone.Model.extend({
constructorName: 'Disk',
urlRoot: '/api/nodes/',
parse: function(response) {
response.volumes = new models.Volumes(response.volumes);
response.volumes.disk = this;
return response;
},
toJSON: function(options) {
return _.extend(this.constructor.__super__.toJSON.call(this, options), {volumes: this.get('volumes').toJSON()});
},
getUnallocatedSpace: function(options) {
options = options || {};
var volumes = options.volumes || this.get('volumes');
var allocatedSpace = volumes.reduce(function(sum, volume) {return volume.get('name') == options.skip ? sum : sum + volume.get('size');}, 0);
return this.get('size') - allocatedSpace;
},
validate: function(attrs) {
var error;
var unallocatedSpace = this.getUnallocatedSpace({volumes: attrs.volumes});
if (unallocatedSpace < 0) {
error = 'Volume groups total size exceeds available space of ' + utils.formatNumber(unallocatedSpace * -1) + ' MB';
}
return error;
}
});
models.Disks = Backbone.Collection.extend({
constructorName: 'Disks',
model: models.Disk,
url: '/api/nodes/',
comparator: 'name'
});
models.Volume = Backbone.Model.extend({
constructorName: 'Volume',
urlRoot: '/api/volumes/',
getMinimalSize: function(minimum) {
var currentDisk = this.collection.disk;
var groupAllocatedSpace = currentDisk.collection.reduce(function(sum, disk) {return disk.id == currentDisk.id ? sum : sum + disk.get('volumes').findWhere({name: this.get('name')}).get('size');}, 0, this);
return minimum - groupAllocatedSpace;
},
validate: function(attrs, options) {
var error;
var min = this.getMinimalSize(options.minimum);
if (_.isNaN(attrs.size)) {
error = 'Invalid size';
} else if (attrs.size < min) {
error = 'The value is too low. You must allocate at least ' + utils.formatNumber(min) + ' MB';
}
return error;
}
});
models.Volumes = Backbone.Collection.extend({
constructorName: 'Volumes',
model: models.Volume,
url: '/api/volumes/'
});
models.Interface = Backbone.Model.extend({
constructorName: 'Interface',
bondingModes: ['active-backup', 'balance-slb', 'lacp-balance-tcp'],
parse: function(response) {
response.assigned_networks = new models.InterfaceNetworks(response.assigned_networks);
response.assigned_networks.interface = this;
return response;
},
toJSON: function(options) {
return _.omit(_.extend(this.constructor.__super__.toJSON.call(this, options), {
assigned_networks: this.get('assigned_networks').toJSON()
}), 'checked');
},
isBond: function() {
return this.get('type') == 'bond';
},
getSlaveInterfaces: function() {
if (!this.isBond()) {return [this];}
var slaveInterfaceNames = _.pluck(this.get('slaves'), 'name');
return this.collection.filter(function(slaveInterface) {
return _.contains(slaveInterfaceNames, slaveInterface.get('name'));
});
},
validate: function() {
var errors = [];
var networks = new models.Networks(this.get('assigned_networks').invoke('getFullNetwork'));
var untaggedNetworks = networks.filter(function(network) { return _.isNull(network.getVlanRange()); });
// public and floating networks are allowed to be assigned to the same interface
var maxUntaggedNetworksCount = networks.where({name: 'public'}).length && networks.where({name: 'floating'}).length ? 2 : 1;
if (untaggedNetworks.length > maxUntaggedNetworksCount) {
errors.push($.t('cluster_page.nodes_tab.configure_interfaces.validation.too_many_untagged_networks'));
}
return errors;
}
});
models.Interfaces = Backbone.Collection.extend({
constructorName: 'Interfaces',
model: models.Interface,
generateBondName: function() {
var index, proposedName, base = 'ovs-bond';
for (index = 0; true; index += 1) {
proposedName = base + index;
if (!this.where({name: proposedName}).length) {
return proposedName;
}
}
},
comparator: function(ifc) {
return [!ifc.isBond(), ifc.get('name')];
}
});
models.InterfaceNetwork = Backbone.Model.extend({
constructorName: 'InterfaceNetwork'
});
models.InterfaceNetworks = Backbone.Collection.extend({
constructorName: 'InterfaceNetworks',
model: models.InterfaceNetwork,
preferredOrder: ['public', 'floating', 'storage', 'management', 'fixed'],
comparator: function(network) {
return _.indexOf(this.preferredOrder, network.get('name'));
}
});
models.Network = Backbone.Model.extend({
constructorName: 'Network'
});
models.Networks = Backbone.Collection.extend({
constructorName: 'Networks',
model: models.Network
});
models.NetworkingParameters = Backbone.Model.extend({
constructorName: 'NetworkingParameters'
});
models.NetworkConfiguration = Backbone.Model.extend({
constructorName: 'NetworkConfiguration',
cacheFor: 60 * 1000,
parse: function(response) {
response.networks = new models.Networks(response.networks);
response.networking_parameters = new models.NetworkingParameters(response.networking_parameters);
return response;
},
toJSON: function() {
return {
networks: this.get('networks').toJSON(),
networking_parameters: this.get('networking_parameters').toJSON()
};
},
isNew: function() {
return false;
},
validate: function(attrs) {
var errors = {};
var networksErrors = {};
var networkingParametersErrors = {};
// validate networks
attrs.networks.each(function(network) {
if (network.get('meta').configurable) {
var networkErrors = {};
if (network.get('meta').notation == 'ip_ranges') {
var ipRangesErrors = utils.validateIpRanges(network.get('ip_ranges'), network.get('cidr'));
if (ipRangesErrors.length) {
networkErrors.ip_ranges = ipRangesErrors;
}
}
_.extend(networkErrors, utils.validateCidr(network.get('cidr')));
if (network.get('meta').use_gateway) {
if (utils.validateIP(network.get('gateway'))) {
networkErrors.gateway = $.t('cluster_page.network_tab.validation.invalid_gateway');
} else if (!utils.validateIpCorrespondsToCIDR(network.get('cidr'), network.get('gateway'))) {
networkErrors.gateway = $.t('cluster_page.network_tab.validation.gateway_is_out_of_ip_range');
}
}
var forbiddenVlans = attrs.networks.map(function(net) {return net.id != network.id ? net.get('vlan_start') : null;});
_.extend(networkErrors, utils.validateVlan(network.get('vlan_start'), forbiddenVlans, 'vlan_start'));
if (!_.isEmpty(networkErrors)) {
networksErrors[network.id] = networkErrors;
}
}
}, this);
if (!_.isEmpty(networksErrors)) {
errors.networks = networksErrors;
}
// validate networking parameters
var novaNetManager = attrs.networking_parameters.get('net_manager');
if (novaNetManager) {
networkingParametersErrors = _.extend(networkingParametersErrors, utils.validateCidr(attrs.networking_parameters.get('fixed_networks_cidr'), 'fixed_networks_cidr'));
var fixedAmount = attrs.networking_parameters.get('fixed_networks_amount');
var fixedVlan = attrs.networking_parameters.get('fixed_networks_vlan_start');
if (!utils.isNaturalNumber(fixedAmount)) {
networkingParametersErrors.fixed_networks_amount = $.t('cluster_page.network_tab.validation.invalid_amount');
}
var vlanErrors = utils.validateVlan(fixedVlan, attrs.networks.pluck('vlan_start'), 'fixed_networks_vlan_start', novaNetManager == 'VlanManager');
_.extend(networkingParametersErrors, vlanErrors);
if (_.isEmpty(vlanErrors)) {
if (!networkingParametersErrors.fixed_networks_amount && fixedAmount > 4095 - fixedVlan) {
networkingParametersErrors.fixed_networks_amount = $.t('cluster_page.network_tab.validation.need_more_vlan');
}
var vlanIntersection = false;
_.each(_.compact(attrs.networks.pluck('vlan_start')), function(vlan) {
if (utils.validateVlanRange(fixedVlan, fixedVlan + fixedAmount - 1, vlan)) {
vlanIntersection = true;
}
});
if (vlanIntersection) {
networkingParametersErrors.fixed_networks_vlan_start = $.t('cluster_page.network_tab.validation.vlan_intersection');
}
}
} else {
var idRangeErrors = ['', ''];
var segmentation = attrs.networking_parameters.get('segmentation_type');
var idRangeAttr = segmentation == 'gre' ? 'gre_id_range' : 'vlan_range';
var maxId = segmentation == 'gre' ? 65535 : 4094;
var idRange = attrs.networking_parameters.get(idRangeAttr);
var idStart = Number(idRange[0]), idEnd = Number(idRange[1]);
if (!utils.isNaturalNumber(idStart) || idStart < 2 || idStart > maxId) {
idRangeErrors[0] = $.t('cluster_page.network_tab.validation.invalid_id_start');
} else if (!utils.isNaturalNumber(idEnd) || idEnd < 2 || idEnd > maxId) {
idRangeErrors[1 ] = $.t('cluster_page.network_tab.validation.invalid_id_end');
} else if (idStart > idEnd) {
idRangeErrors[0] = idRangeErrors[1] = $.t('cluster_page.network_tab.validation.invalid_id_range');
} else if (segmentation == 'vlan') {
_.each(_.compact(attrs.networks.pluck('vlan_start')), function(vlan) {
if (utils.validateVlanRange(idStart, idEnd, vlan)) {
idRangeErrors[0] = $.t('cluster_page.network_tab.validation.vlan_intersection');
}
return idRangeErrors[0];
});
}
if (_.compact(idRangeErrors).length) {
networkingParametersErrors[idRangeAttr] = idRangeErrors;
}
if (!attrs.networking_parameters.get('base_mac').match(utils.regexes.mac)) {
networkingParametersErrors.base_mac = $.t('cluster_page.network_tab.validation.invalid_mac');
}
var cidr = attrs.networking_parameters.get('internal_cidr');
networkingParametersErrors = _.extend(networkingParametersErrors, utils.validateCidr(cidr, 'internal_cidr'));
var gateway = attrs.networking_parameters.get('internal_gateway');
if (utils.validateIP(gateway)) {
networkingParametersErrors.internal_gateway = $.t('cluster_page.network_tab.validation.invalid_gateway');
} else if (!utils.validateIpCorrespondsToCIDR(cidr, gateway)) {
networkingParametersErrors.internal_gateway = $.t('cluster_page.network_tab.validation.gateway_is_out_of_internal_ip_range');
}
}
var networkWithFloatingRange = attrs.networks.filter(function(network){ return network.get('meta').floating_range_var; })[0];
var floatingRangesErrors = utils.validateIpRanges(attrs.networking_parameters.get('floating_ranges'), networkWithFloatingRange ? networkWithFloatingRange.get('cidr') : null);
if (floatingRangesErrors.length) {
networkingParametersErrors.floating_ranges = floatingRangesErrors;
}
var nameserverErrors = [];
_.each(attrs.networking_parameters.get('dns_nameservers'), function(nameserver, i) {
nameserverErrors.push(utils.validateIP(nameserver) ? $.t('cluster_page.network_tab.validation.invalid_nameserver') : null);
});
if (_.compact(nameserverErrors).length) {
networkingParametersErrors.dns_nameservers = nameserverErrors;
}
if (!_.isEmpty(networkingParametersErrors)) {
errors.networking_parameters = networkingParametersErrors;
}
return _.isEmpty(errors) ? null : errors;
}
});
_.extend(models.NetworkConfiguration.prototype, cacheMixin);
models.LogSource = Backbone.Model.extend({
constructorName: 'LogSource',
urlRoot: '/api/logs/sources'
});
models.LogSources = Backbone.Collection.extend({
constructorName: 'LogSources',
model: models.LogSource,
url: '/api/logs/sources'
});
models.RedHatAccount = Backbone.Model.extend({
constructorName: 'RedHatAccount',
urlRoot: '/api/redhat/account',
validate: function(attrs) {
var errors = {};
var regexes = {
username: /^[A-z0-9\._%\+\-@]+$/,
password: /^[\x21-\x7E]+$/,
satellite: /(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)/,
activation_key: /^[A-z0-9\*\.\+\-]+$/
};
var messages = {
username: 'Invalid username',
password: 'Invalid password',
satellite: 'Only valid fully qualified domain name is allowed for the hostname field',
activation_key: 'Invalid activation key'
};
var fields = ['username', 'password'];
if (attrs.license_type == 'rhn') {
fields = _.union(fields, ['satellite', 'activation_key']);
}
_.each(fields, function(attr) {
if (!regexes[attr].test(attrs[attr])) {
errors[attr] = messages[attr];
}
});
return _.isEmpty(errors) ? null : errors;
}
});
models.TestSet = Backbone.Model.extend({
constructorName: 'TestSet',
urlRoot: '/ostf/testsets'
});
models.TestSets = Backbone.Collection.extend({
constructorName: 'TestSets',
model: models.TestSet,
url: '/ostf/testsets'
});
models.Test = Backbone.Model.extend({
constructorName: 'Test',
urlRoot: '/ostf/tests'
});
models.Tests = Backbone.Collection.extend({
constructorName: 'Tests',
model: models.Test,
url: '/ostf/tests'
});
models.TestRun = Backbone.Model.extend({
constructorName: 'TestRun',
urlRoot: '/ostf/testruns'
});
models.TestRuns = Backbone.Collection.extend({
constructorName: 'TestRuns',
model: models.TestRun,
url: '/ostf/testruns'
});
models.OSTFClusterMetadata = Backbone.Model.extend({
constructorName: 'OSTFClusterMetadata',
urlRoot: '/api/ostf'
});
models.OSTFCredentials = Backbone.Model.extend({
constructorName: 'OSTFCredentials',
update: function(settings) {
var accessSettings = settings.get('access');
this.set({
username: accessSettings.user.value,
password: accessSettings.password.value,
tenant: accessSettings.tenant.value
});
}
});
models.FuelKey = Backbone.Model.extend({
constructorName: 'FuelKey',
urlRoot: '/api/registration/key'
});
models.FuelVersion = Backbone.Model.extend({
constructorName: 'FuelVersion',
urlRoot: '/api/version',
authExempt: true
});
models.User = Backbone.Model.extend({
constructorName: 'User',
locallyStoredAttributes: ['username', 'password'],
initialize: function() {
_.each(this.locallyStoredAttributes, function(attribute) {
var locallyStoredValue = localStorage.getItem(attribute);
if (locallyStoredValue) {
this.set(attribute, locallyStoredValue);
}
this.on('change:' + attribute, function(model, value) {
if (_.isUndefined(value)) {
localStorage.removeItem(attribute);
} else {
localStorage.setItem(attribute, value);
}
});
}, this);
}
});
models.LogsPackage = Backbone.Model.extend({
constructorName: 'LogsPackage',
urlRoot: '/api/logs/package'
});
models.CapacityLog = Backbone.Model.extend({
constructorName: 'CapacityLog',
urlRoot: '/api/capacity'
});
models.WizardModel = Backbone.DeepModel.extend({
constructorName: 'WizardModel',
parseConfig: function(config) {
var result = {};
_.each(config, _.bind(function(paneConfig, paneName) {
result[paneName] = {};
_.each(paneConfig, function(attributeConfig, attribute) {
var attributeConfigValue = attributeConfig.value;
if (_.isUndefined(attributeConfigValue)) {
switch (attributeConfig.type) {
case 'checkbox':
attributeConfigValue = false;
break;
case 'radio':
attributeConfigValue = _.first(attributeConfig.values).data;
break;
case 'password':
case 'text':
attributeConfigValue = "";
break;
}
}
result[paneName][attribute] = attributeConfigValue;
});
}, this));
return result;
},
processConfig: function(config) {
this.set(this.parseConfig(config));
},
restoreDefaultValues: function(panesToRestore) {
var result = {};
_.each(this.defaults, _.bind(function(paneConfig, paneName) {
if (_.contains(panesToRestore, paneName)) {
result[paneName] = this.defaults[paneName];
}
}, this));
this.set(result);
},
validate: function(attrs, options) {
var errors = [];
_.each(options.config, function(attributeConfig, attribute) {
if (!(attributeConfig.regex && attributeConfig.regex.source)) { return; }
var hasNoSatisfiedRestrictions = _.every(_.reject(attributeConfig.restrictions, {action: 'none'}), function(restriction) {
// this probably will be changed when other controls need validation
return !utils.evaluateExpression(restriction.condition, {default: this}).value;
}, this);
if (hasNoSatisfiedRestrictions) {
var regExp = new RegExp(attributeConfig.regex.source);
if (!this.get(options.paneName + '.' + attribute).match(regExp)) {
errors.push({
field: attribute,
message: $.t(attributeConfig.regex.error)
});
}
}
}, this);
return errors.length ? errors : null;
},
initialize: function(config) {
this.defaults = this.parseConfig(config);
}
});
return models;
});