diff --git a/.eslintrc b/.eslintrc index ff30a10c4..1c5540356 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,7 +13,6 @@ # to be fixed and enabled eqeqeq: 0 - max-len: [0, 120] # extra rules no-unexpected-multiline: 2 diff --git a/gulp/i18n.js b/gulp/i18n.js index 25a6c608e..bfb5a0b77 100644 --- a/gulp/i18n.js +++ b/gulp/i18n.js @@ -26,12 +26,15 @@ function validate(translations, locales) { }); function compareLocales(locale1, locale2) { - return _.without.apply(null, [processedTranslations[locale1]].concat(processedTranslations[locale2])); + return _.without.apply(null, [processedTranslations[locale1]] + .concat(processedTranslations[locale2])); } _.each(_.without(locales, baseLocale), function(locale) { - gutil.log(gutil.colors.red('The list of keys present in', baseLocale, 'but absent in', locale, ':\n') + compareLocales(baseLocale, locale).join('\n')); - gutil.log(gutil.colors.red('The list of keys missing in', baseLocale, ':\n') + compareLocales(locale, baseLocale).join('\n')); + gutil.log(gutil.colors.red('The list of keys present in', + baseLocale, 'but absent in', locale, ':\n') + compareLocales(baseLocale, locale).join('\n')); + gutil.log(gutil.colors.red('The list of keys missing in', baseLocale, ':\n') + + compareLocales(locale, baseLocale).join('\n')); }); } diff --git a/gulpfile.js b/gulpfile.js index 460721b77..28a6255a6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -80,7 +80,8 @@ gulp.task('selenium', ['selenium:fetch'], function(cb) { if (err) throw err; child.on('exit', function() { if (seleniumProcess) { - gutil.log(gutil.colors.yellow('Selenium process died unexpectedly. Probably port', port, 'is already in use.')); + gutil.log(gutil.colors.yellow('Selenium process died unexpectedly. Probably port', + port, 'is already in use.')); } }); ['exit', 'uncaughtException', 'SIGTERM', 'SIGINT'].forEach(function(event) { @@ -127,7 +128,9 @@ function runIntern(params) { }; } -gulp.task('intern:functional', runIntern({functionalSuites: argv.suites || 'static/tests/functional/**/test_*.js'})); +gulp.task('intern:functional', runIntern({ + functionalSuites: argv.suites || 'static/tests/functional/**/test_*.js' +})); gulp.task('unit-tests', function(cb) { runSequence('selenium', 'karma', function(err) { @@ -161,7 +164,8 @@ gulp.task('license', function(cb) { _.each(data, function(moduleInfo) { var name = moduleInfo.name; var version = moduleInfo.version; - var license = _.pluck(moduleInfo.licenseSources.package.sources, 'license').join(', ') || 'unknown'; + var license = _.pluck(moduleInfo.licenseSources.package.sources, 'license').join(', ') || + 'unknown'; var licenseOk = license.match(licenseRegexp); if (!licenseOk) errors.push({libraryName: name, license: license}); gutil.log( @@ -260,10 +264,11 @@ gulp.task('dev-server', function() { ] }; _.extend(options, config.output); - new WebpackDevServer(webpack(config), options).listen(devServerPort, devServerHost, function(err) { - if (err) throw err; - gutil.log('Development server started at ' + devServerUrl); - }); + new WebpackDevServer(webpack(config), options).listen(devServerPort, devServerHost, + function(err) { + if (err) throw err; + gutil.log('Development server started at ' + devServerUrl); + }); }); gulp.task('build', function(cb) { @@ -301,7 +306,8 @@ gulp.task('build', function(cb) { rimraf.sync(config.output.path); var compiler = webpack(config); - var run = config.watch ? compiler.watch.bind(compiler, config.watchOptions) : compiler.run.bind(compiler); + var run = config.watch ? compiler.watch.bind(compiler, config.watchOptions) : + compiler.run.bind(compiler); run(function(err, stats) { if (err) return cb(err); diff --git a/static/app.js b/static/app.js index 39c3952c5..72b5b8eb3 100644 --- a/static/app.js +++ b/static/app.js @@ -70,11 +70,14 @@ class Router extends Backbone.Router { var specialRoutes = [ {name: 'login', condition: () => { var result = app.version.get('auth_required') && !app.user.get('authenticated'); - if (result && currentUrl != 'login' && currentUrl != 'logout') this.returnUrl = currentUrl; + if (result && currentUrl != 'login' && currentUrl != 'logout') { + this.returnUrl = currentUrl; + } return result; }}, {name: 'welcome', condition: (previousUrl) => { - return previousUrl != 'logout' && !app.fuelSettings.get('statistics.user_choice_saved.value'); + return previousUrl != 'logout' && + !app.fuelSettings.get('statistics.user_choice_saved.value'); }} ]; _.each(specialRoutes, (route) => { @@ -153,7 +156,8 @@ class App { constructor() { this.initialized = false; - // this is needed for IE, which caches requests resulting in wrong results (e.g /ostf/testruns/last/1) + // this is needed for IE, + // which caches requests resulting in wrong results (e.g /ostf/testruns/last/1) $.ajaxSetup({cache: false}); this.router = new Router(); @@ -217,10 +221,11 @@ class App { } loadPage(Page, options = []) { - return (Page.fetchData ? Page.fetchData(...options) : $.Deferred().resolve()).done((pageOptions) => { - if (!this.rootComponent) this.renderLayout(); - this.setPage(Page, pageOptions); - }); + return (Page.fetchData ? Page.fetchData(...options) : $.Deferred().resolve()) + .done((pageOptions) => { + if (!this.rootComponent) this.renderLayout(); + this.setPage(Page, pageOptions); + }); } setPage(Page, options) { diff --git a/static/component_mixins.js b/static/component_mixins.js index 17141f498..537fd1f24 100644 --- a/static/component_mixins.js +++ b/static/component_mixins.js @@ -38,7 +38,8 @@ export function dispatcherMixin(events, callback) { export var unsavedChangesMixin = { onBeforeunloadEvent() { - if (this.hasChanges()) return _.result(this, 'getStayMessage') || i18n('dialog.dismiss_settings.default_message'); + if (this.hasChanges()) return _.result(this, 'getStayMessage') || + i18n('dialog.dismiss_settings.default_message'); }, componentWillMount() { this.eventName = _.uniqueId('unsavedchanges'); @@ -71,13 +72,15 @@ export function pollingMixin(updateInterval, delayedStart) { updateInterval = updateInterval * 1000; return { scheduleDataFetch() { - var shouldDataBeFetched = !_.isFunction(this.shouldDataBeFetched) || this.shouldDataBeFetched(); + var shouldDataBeFetched = !_.isFunction(this.shouldDataBeFetched) || + this.shouldDataBeFetched(); if (this.isMounted() && !this.activeTimeout && shouldDataBeFetched) { this.activeTimeout = _.delay(this.startPolling, updateInterval); } }, startPolling(force) { - var shouldDataBeFetched = force || !_.isFunction(this.shouldDataBeFetched) || this.shouldDataBeFetched(); + var shouldDataBeFetched = force || !_.isFunction(this.shouldDataBeFetched) || + this.shouldDataBeFetched(); if (shouldDataBeFetched) { this.stopPolling(); return this.fetchData().always(this.scheduleDataFetch); diff --git a/static/expression.js b/static/expression.js index 293ef51e3..15d668559 100644 --- a/static/expression.js +++ b/static/expression.js @@ -43,7 +43,8 @@ class Expression { getCompiledExpression() { var cacheEntry = expressionCache[this.expressionText]; if (!cacheEntry) { - cacheEntry = expressionCache[this.expressionText] = ExpressionParser.parse(this.expressionText); + cacheEntry = expressionCache[this.expressionText] = + ExpressionParser.parse(this.expressionText); } return cacheEntry; } diff --git a/static/expression/objects.js b/static/expression/objects.js index 5e728a659..5fb947363 100644 --- a/static/expression/objects.js +++ b/static/expression/objects.js @@ -90,7 +90,10 @@ export class ModelPathWrapper { var result = this.modelPath.get(); if (_.isUndefined(result)) { if (expression.strict) { - throw new TypeError('Value of ' + this.modelPathText + ' is undefined. Set options.strict to false to allow undefined values.'); + throw new TypeError( + 'Value of ' + this.modelPathText + + ' is undefined. Set options.strict to false to allow undefined values.' + ); } result = null; } diff --git a/static/keystone_client.js b/static/keystone_client.js index 4eb434110..5c503d40c 100644 --- a/static/keystone_client.js +++ b/static/keystone_client.js @@ -29,7 +29,11 @@ class KeystoneClient { authenticate(username, password, options = {}) { if (this.tokenUpdateRequest) return this.tokenUpdateRequest; - if (!options.force && this.tokenUpdateTime && (this.cacheTokenFor > (new Date() - this.tokenUpdateTime))) { + if ( + !options.force && + this.tokenUpdateTime && + (this.cacheTokenFor > (new Date() - this.tokenUpdateTime)) + ) { return $.Deferred().resolve(); } var data = {auth: {}}; diff --git a/static/models.js b/static/models.js index 4240b90b5..7a2225811 100644 --- a/static/models.js +++ b/static/models.js @@ -72,11 +72,13 @@ _.each(collectionMethods, (method) => { }); var BaseModel = models.BaseModel = Backbone.Model.extend(superMixin); -var BaseCollection = models.BaseCollection = Backbone.Collection.extend(collectionMixin).extend(superMixin); +var BaseCollection = models.BaseCollection = + Backbone.Collection.extend(collectionMixin).extend(superMixin); var cacheMixin = { fetch(options) { - if (this.cacheFor && options && options.cache && this.lastSyncTime && (this.cacheFor > (new Date() - this.lastSyncTime))) { + if (this.cacheFor && options && options.cache && this.lastSyncTime && + (this.cacheFor > (new Date() - this.lastSyncTime))) { return $.Deferred().resolve(); } return this._super('fetch', arguments); @@ -98,7 +100,8 @@ models.cacheMixin = cacheMixin; var restrictionMixin = models.restrictionMixin = { checkRestrictions(models, action, setting) { - var restrictions = _.map(setting ? setting.restrictions : this.get('restrictions'), utils.expandRestriction); + var restrictions = _.map(setting ? setting.restrictions : this.get('restrictions'), + utils.expandRestriction); if (action) { restrictions = _.where(restrictions, {action: action}); } @@ -125,7 +128,8 @@ var restrictionMixin = models.restrictionMixin = { * and validate current model checking the possibility of adding/removing node * So if max = 1 and we have 1 node then: * - the model is valid as is (return true) -- case for checkLimitIsReached = true - * - there can be no more nodes added (return false) -- case for checkLimitIsReached = false + * - there can be no more nodes added (return false) -- case for + * checkLimitIsReached = false * limitType -- array of limit types to check. Possible choices are 'min', 'max', 'recommended' **/ @@ -177,14 +181,16 @@ var restrictionMixin = models.restrictionMixin = { comparator = (a, b) => a < b; } limitValue = parseInt(evaluateExpressionHelper(obj[limitType], models).value, 10); - // Update limitValue with overrides, this way at the end we have a flattened limitValues with overrides having priority + // Update limitValue with overrides, this way at the end we have a flattened + // limitValues with overrides having priority limitValues[limitType] = limitValue; checkedLimitTypes[limitType] = true; if (comparator(count, limitValue)) { return { type: limitType, value: limitValue, - message: obj.message || i18n('common.role_limits.' + limitType, {limitValue: limitValue, count: count, roleName: label}) + message: obj.message || i18n('common.role_limits.' + limitType, + {limitValue: limitValue, count: count, roleName: label}) }; } }; @@ -291,7 +297,9 @@ models.Roles = BaseCollection.extend(restrictionMixin).extend({ _.each(role.conflicts, (conflictRoleName) => { var conflictingRole = this.findWhere({name: conflictRoleName}); - if (conflictingRole) conflictingRole.conflicts = _.uniq(_.union(conflictingRole.conflicts || [], [roleName])); + if (conflictingRole) { + conflictingRole.conflicts = _.uniq(_.union(conflictingRole.conflicts || [], [roleName])); + } }); }); } @@ -343,7 +351,8 @@ models.Cluster = BaseModel.extend({ return this.get('tasks') && this.get('tasks').filterTasks(filters); }, needsRedeployment() { - return this.get('nodes').any({pending_addition: false, status: 'error'}) && this.get('status') != 'update_error'; + return this.get('nodes').any({pending_addition: false, status: 'error'}) && + this.get('status') != 'update_error'; }, fetchRelated(related, options) { return this.get(related).fetch(_.extend({data: {cluster_id: this.id}}, options)); @@ -354,7 +363,8 @@ models.Cluster = BaseModel.extend({ isDeploymentPossible() { var nodes = this.get('nodes'); return this.get('release').get('state') != 'unavailable' && !!nodes.length && - (nodes.hasChanges() || this.needsRedeployment()) && !this.task({group: 'deployment', active: true}); + (nodes.hasChanges() || this.needsRedeployment()) && + !this.task({group: 'deployment', active: true}); } }); @@ -388,7 +398,9 @@ models.Node = BaseModel.extend({ } else if (resourceName == 'ht_cores') { resource = this.get('meta').cpu.total; } else if (resourceName == 'hdd') { - resource = _.reduce(this.get('meta').disks, (hdd, disk) => _.isNumber(disk.size) ? hdd + disk.size : hdd, 0); + resource = _.reduce(this.get('meta').disks, (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') { @@ -412,7 +424,8 @@ models.Node = BaseModel.extend({ return this.get('status') != 'removing'; }, hasRole(role, onlyDeployedRoles) { - var roles = onlyDeployedRoles ? this.get('roles') : _.union(this.get('roles'), this.get('pending_roles')); + var roles = onlyDeployedRoles ? this.get('roles') : + _.union(this.get('roles'), this.get('pending_roles')); return _.contains(roles, role); }, hasChanges() { @@ -505,7 +518,8 @@ models.Nodes = BaseCollection.extend({ var roles = _.union(this.at(0).get('roles'), this.at(0).get('pending_roles')); var disks = this.at(0).resource('disks'); return !this.any((node) => { - var roleConflict = _.difference(roles, _.union(node.get('roles'), node.get('pending_roles'))).length; + var roleConflict = _.difference(roles, _.union(node.get('roles'), + node.get('pending_roles'))).length; return roleConflict || !_.isEqual(disks, node.resource('disks')); }); }, @@ -556,10 +570,12 @@ models.Task = BaseModel.extend({ match(filters) { filters = filters || {}; if (!_.isEmpty(filters)) { - if ((filters.group || filters.name) && !_.contains(this.extendGroups(filters), this.get('name'))) { + if ((filters.group || filters.name) && + !_.contains(this.extendGroups(filters), this.get('name'))) { return false; } - if ((filters.status || _.isBoolean(filters.active)) && !_.contains(this.extendStatuses(filters), this.get('status'))) { + if ((filters.status || _.isBoolean(filters.active)) && + !_.contains(this.extendStatuses(filters), this.get('status'))) { return false; } } @@ -607,121 +623,134 @@ models.Notifications = BaseCollection.extend({ } }); -models.Settings = Backbone.DeepModel.extend(superMixin).extend(cacheMixin).extend(restrictionMixin).extend({ - constructorName: 'Settings', - urlRoot: '/api/clusters/', - root: 'editable', - cacheFor: 60 * 1000, - groupList: ['general', 'security', 'compute', 'network', 'storage', 'logging', 'openstack_services', 'other'], - isNew() { - return false; - }, - isPlugin(section) { - return (section.metadata || {}).class == 'plugin'; - }, - parse(response) { - return response[this.root]; - }, - mergePluginSettings() { - _.each(this.attributes, (section, sectionName) => { - if (this.isPlugin(section)) { - var chosenVersionData = section.metadata.versions.find( - (version) => version.metadata.plugin_id == section.metadata.chosen_id - ); - // merge metadata of a chosen plugin version - _.extend(section.metadata, _.omit(chosenVersionData.metadata, 'plugin_id', 'plugin_version')); - // merge settings of a chosen plugin version - this.attributes[sectionName] = _.extend(_.pick(section, 'metadata'), _.omit(chosenVersionData, 'metadata')); - } - }, this); - }, - toJSON() { - var settings = this._super('toJSON', arguments); - if (!this.root) return settings; +models.Settings = Backbone.DeepModel + .extend(superMixin) + .extend(cacheMixin) + .extend(restrictionMixin) + .extend({ + constructorName: 'Settings', + urlRoot: '/api/clusters/', + root: 'editable', + cacheFor: 60 * 1000, + groupList: ['general', 'security', 'compute', 'network', 'storage', + 'logging', 'openstack_services', 'other'], + isNew() { + return false; + }, + isPlugin(section) { + return (section.metadata || {}).class == 'plugin'; + }, + parse(response) { + return response[this.root]; + }, + mergePluginSettings() { + _.each(this.attributes, (section, sectionName) => { + if (this.isPlugin(section)) { + var chosenVersionData = section.metadata.versions.find( + (version) => version.metadata.plugin_id == section.metadata.chosen_id + ); + // merge metadata of a chosen plugin version + _.extend(section.metadata, + _.omit(chosenVersionData.metadata, 'plugin_id', 'plugin_version')); + // merge settings of a chosen plugin version + this.attributes[sectionName] = _.extend(_.pick(section, 'metadata'), + _.omit(chosenVersionData, 'metadata')); + } + }, this); + }, + toJSON() { + var settings = this._super('toJSON', arguments); + if (!this.root) return settings; - // update plugin settings - _.each(settings, (section, sectionName) => { - if (this.isPlugin(section)) { - var chosenVersionData = section.metadata.versions.find( - (version) => version.metadata.plugin_id == section.metadata.chosen_id - ); - section.metadata = _.omit(section.metadata, _.without(_.keys(chosenVersionData.metadata), 'plugin_id', 'plugin_version')); - _.each(section, (setting, settingName) => { - if (settingName != 'metadata') chosenVersionData[settingName].value = setting.value; - }); - settings[sectionName] = _.pick(section, 'metadata'); - } - }); - return {[this.root]: settings}; - }, - initialize() { - this.once('change', this.mergePluginSettings, this); - }, - validate(attrs, options) { - var errors = {}; - var models = options ? options.models : {}; - var checkRestrictions = (setting) => this.checkRestrictions(models, null, setting); - _.each(attrs, (group, groupName) => { - if ((group.metadata || {}).enabled === false || checkRestrictions(group.metadata).result) return; - _.each(group, (setting, settingName) => { - if (checkRestrictions(setting).result) return; - var path = this.makePath(groupName, settingName); - // support of custom controls - var CustomControl = customControls[setting.type]; - if (CustomControl) { - var error = CustomControl.validate(setting, models); - if (error) errors[path] = error; - return; + // update plugin settings + _.each(settings, (section, sectionName) => { + if (this.isPlugin(section)) { + var chosenVersionData = section.metadata.versions.find( + (version) => version.metadata.plugin_id == section.metadata.chosen_id + ); + section.metadata = _.omit(section.metadata, + _.without(_.keys(chosenVersionData.metadata), 'plugin_id', 'plugin_version')); + _.each(section, (setting, settingName) => { + if (settingName != 'metadata') chosenVersionData[settingName].value = setting.value; + }); + settings[sectionName] = _.pick(section, 'metadata'); } + }); + return {[this.root]: settings}; + }, + initialize() { + this.once('change', this.mergePluginSettings, this); + }, + validate(attrs, options) { + var errors = {}; + var models = options ? options.models : {}; + var checkRestrictions = (setting) => this.checkRestrictions(models, null, setting); + _.each(attrs, (group, groupName) => { + if ((group.metadata || {}).enabled === false || + checkRestrictions(group.metadata).result) return; + _.each(group, (setting, settingName) => { + if (checkRestrictions(setting).result) return; + var path = this.makePath(groupName, settingName); + // support of custom controls + var CustomControl = customControls[setting.type]; + if (CustomControl) { + var error = CustomControl.validate(setting, models); + if (error) errors[path] = error; + return; + } - if (!(setting.regex || {}).source) return; - if (!setting.value.match(new RegExp(setting.regex.source))) errors[path] = setting.regex.error; - }); - }); - return _.isEmpty(errors) ? null : errors; - }, - makePath(...args) { - return args.join('.'); - }, - getValueAttribute(settingName) { - return settingName == 'metadata' ? 'enabled' : 'value'; - }, - hasChanges(initialAttributes, models) { - return _.any(this.attributes, (section, sectionName) => { - var metadata = section.metadata; - var result = false; - if (metadata) { - if (this.checkRestrictions(models, null, metadata).result) return result; - if (!_.isUndefined(metadata.enabled)) { - result = metadata.enabled != initialAttributes[sectionName].metadata.enabled; - } - if (!result && this.isPlugin(section)) { - result = metadata.chosen_id != initialAttributes[sectionName].metadata.chosen_id; - } - } - return result || (metadata || {}).enabled !== false && _.any(section, (setting, settingName) => { - if (this.checkRestrictions(models, null, setting).result) return false; - return !_.isEqual(setting.value, (initialAttributes[sectionName][settingName] || {}).value); - }); - }); - }, - sanitizeGroup(group) { - return _.contains(this.groupList, group) ? group : 'other'; - }, - getGroupList() { - var groups = []; - _.each(this.attributes, (section) => { - if (section.metadata.group) { - groups.push(this.sanitizeGroup(section.metadata.group)); - } else { - _.each(section, (setting, settingName) => { - if (settingName != 'metadata') groups.push(this.sanitizeGroup(setting.group)); + if (!(setting.regex || {}).source) return; + if (!setting.value.match(new RegExp(setting.regex.source))) { + errors[path] = setting.regex.error; + } }); - } - }); - return _.intersection(this.groupList, groups); - } -}); + }); + return _.isEmpty(errors) ? null : errors; + }, + makePath(...args) { + return args.join('.'); + }, + getValueAttribute(settingName) { + return settingName == 'metadata' ? 'enabled' : 'value'; + }, + hasChanges(initialAttributes, models) { + return _.any(this.attributes, (section, sectionName) => { + var metadata = section.metadata; + var result = false; + if (metadata) { + if (this.checkRestrictions(models, null, metadata).result) return result; + if (!_.isUndefined(metadata.enabled)) { + result = metadata.enabled != initialAttributes[sectionName].metadata.enabled; + } + if (!result && this.isPlugin(section)) { + result = metadata.chosen_id != initialAttributes[sectionName].metadata.chosen_id; + } + } + return result || (metadata || {}).enabled !== false && + _.any(section, (setting, settingName) => { + if (this.checkRestrictions(models, null, setting).result) return false; + return !_.isEqual(setting.value, + (initialAttributes[sectionName][settingName] || {}).value); + }); + }); + }, + sanitizeGroup(group) { + return _.contains(this.groupList, group) ? group : 'other'; + }, + getGroupList() { + var groups = []; + _.each(this.attributes, (section) => { + if (section.metadata.group) { + groups.push(this.sanitizeGroup(section.metadata.group)); + } else { + _.each(section, (setting, settingName) => { + if (settingName != 'metadata') groups.push(this.sanitizeGroup(setting.group)); + }); + } + }); + return _.intersection(this.groupList, groups); + } + }); models.FuelSettings = models.Settings.extend({ constructorName: 'FuelSettings', @@ -741,7 +770,8 @@ models.Disk = BaseModel.extend({ return response; }, toJSON(options) { - return _.extend(this.constructor.__super__.toJSON.call(this, options), {volumes: this.get('volumes').toJSON()}); + return _.extend(this.constructor.__super__.toJSON.call(this, options), + {volumes: this.get('volumes').toJSON()}); }, getUnallocatedSpace(options) { options = options || {}; @@ -755,7 +785,8 @@ models.Disk = BaseModel.extend({ var error; var unallocatedSpace = this.getUnallocatedSpace({volumes: attrs.volumes}); if (unallocatedSpace < 0) { - error = i18n('cluster_page.nodes_tab.configure_disks.validation_error', {size: utils.formatNumber(unallocatedSpace * -1)}); + error = i18n('cluster_page.nodes_tab.configure_disks.validation_error', + {size: utils.formatNumber(unallocatedSpace * -1)}); } return error; } @@ -776,7 +807,8 @@ models.Volume = BaseModel.extend({ var groupAllocatedSpace = 0; if (currentDisk && currentDisk.collection) groupAllocatedSpace = currentDisk.collection.reduce((sum, disk) => { - return disk.id == currentDisk.id ? sum : sum + disk.get('volumes').findWhere({name: this.get('name')}).get('size'); + return disk.id == currentDisk.id ? sum : sum + + disk.get('volumes').findWhere({name: this.get('name')}).get('size'); }, 0); return minimum - groupAllocatedSpace; }, @@ -790,7 +822,8 @@ models.Volume = BaseModel.extend({ validate(attrs, options) { var min = this.getMinimalSize(options.minimum); if (attrs.size < min) { - return i18n('cluster_page.nodes_tab.configure_disks.volume_error', {size: utils.formatNumber(min)}); + return i18n('cluster_page.nodes_tab.configure_disks.volume_error', + {size: utils.formatNumber(min)}); } return null; } @@ -826,11 +859,15 @@ models.Interface = BaseModel.extend({ }, validate(attrs) { var errors = []; - var networks = new models.Networks(this.get('assigned_networks').invoke('getFullNetwork', attrs.networks)); - var untaggedNetworks = networks.filter((network) => _.isNull(network.getVlanRange(attrs.networkingParameters))); + var networks = new models.Networks(this.get('assigned_networks') + .invoke('getFullNetwork', attrs.networks)); + var untaggedNetworks = networks.filter((network) => { + return _.isNull(network.getVlanRange(attrs.networkingParameters)); + }); var ns = 'cluster_page.nodes_tab.configure_interfaces.validation.'; // public and floating networks are allowed to be assigned to the same interface - var maxUntaggedNetworksCount = networks.any({name: 'public'}) && networks.any({name: 'floating'}) ? 2 : 1; + var maxUntaggedNetworksCount = networks.any({name: 'public'}) && + networks.any({name: 'floating'}) ? 2 : 1; if (untaggedNetworks.length > maxUntaggedNetworksCount) { errors.push(i18n(ns + 'too_many_untagged_networks')); } @@ -853,7 +890,8 @@ models.Interface = BaseModel.extend({ if ( _.any(vlanRanges, (currentRange) => _.any(vlanRanges, - (range) => !_.isEqual(currentRange, range) && range[1] >= currentRange[0] && range[0] <= currentRange[1] + (range) => !_.isEqual(currentRange, range) && + range[1] >= currentRange[0] && range[0] <= currentRange[1] ) ) ) errors.push(i18n(ns + 'vlan_range_intersection')); @@ -877,7 +915,8 @@ models.Interfaces = BaseCollection.extend({ } }); -var networkPreferredOrder = ['public', 'floating', 'storage', 'management', 'private', 'fixed', 'baremetal']; +var networkPreferredOrder = ['public', 'floating', 'storage', 'management', + 'private', 'fixed', 'baremetal']; models.InterfaceNetwork = BaseModel.extend({ constructorName: 'InterfaceNetwork', @@ -899,8 +938,11 @@ models.Network = BaseModel.extend({ getVlanRange(networkingParameters) { if (!this.get('meta').neutron_vlan_range) { var externalNetworkData = this.get('meta').ext_net_data; - var vlanStart = externalNetworkData ? networkingParameters.get(externalNetworkData[0]) : this.get('vlan_start'); - return _.isNull(vlanStart) ? vlanStart : [vlanStart, externalNetworkData ? vlanStart + networkingParameters.get(externalNetworkData[1]) - 1 : vlanStart]; + var vlanStart = externalNetworkData ? + networkingParameters.get(externalNetworkData[0]) : this.get('vlan_start'); + return _.isNull(vlanStart) ? vlanStart : + [vlanStart, externalNetworkData ? + vlanStart + networkingParameters.get(externalNetworkData[1]) - 1 : vlanStart]; } return networkingParameters.get('vlan_range'); } @@ -923,7 +965,9 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ cacheFor: 60 * 1000, parse(response) { response.networks = new models.Networks(response.networks); - response.networking_parameters = new models.NetworkingParameters(response.networking_parameters); + response.networking_parameters = new models.NetworkingParameters( + response.networking_parameters + ); return response; }, toJSON() { @@ -982,7 +1026,8 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ var forbiddenVlans = novaNetManager ? networksToCheck.map((net) => { return net.id != network.id ? net.get('vlan_start') : null; }) : []; - _.extend(networkErrors, utils.validateVlan(network.get('vlan_start'), forbiddenVlans, 'vlan_start')); + _.extend(networkErrors, + utils.validateVlan(network.get('vlan_start'), forbiddenVlans, 'vlan_start')); if (!_.isEmpty(networkErrors)) { nodeNetworkGroupErrors[network.id] = networkErrors; @@ -995,7 +1040,9 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ } else if (!cidrError && !utils.validateIpCorrespondsToCIDR(cidr, baremetalGateway)) { networkingParametersErrors.baremetal_gateway = i18n(ns + 'gateway_does_not_match_cidr'); } - var baremetalRangeErrors = utils.validateIPRanges([networkParameters.get('baremetal_range')], cidrError ? null : cidr); + var baremetalRangeErrors = + utils.validateIPRanges([networkParameters.get('baremetal_range')], cidrError ? + null : cidr); if (baremetalRangeErrors.length) { var [{start, end}] = baremetalRangeErrors; networkingParametersErrors.baremetal_range = [start, end]; @@ -1014,13 +1061,15 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ // validate networking parameters if (novaNetManager) { - networkingParametersErrors = _.extend(networkingParametersErrors, utils.validateCidr(networkParameters.get('fixed_networks_cidr'), 'fixed_networks_cidr')); + networkingParametersErrors = _.extend(networkingParametersErrors, + utils.validateCidr(networkParameters.get('fixed_networks_cidr'), 'fixed_networks_cidr')); var fixedAmount = networkParameters.get('fixed_networks_amount'); var fixedVlan = networkParameters.get('fixed_networks_vlan_start'); if (!utils.isNaturalNumber(parseInt(fixedAmount, 10))) { networkingParametersErrors.fixed_networks_amount = i18n(ns + 'invalid_amount'); } - var vlanErrors = utils.validateVlan(fixedVlan, networks.pluck('vlan_start'), 'fixed_networks_vlan_start', novaNetManager == 'VlanManager'); + var vlanErrors = utils.validateVlan(fixedVlan, networks.pluck('vlan_start'), + 'fixed_networks_vlan_start', novaNetManager == 'VlanManager'); _.extend(networkingParametersErrors, vlanErrors); if (_.isEmpty(vlanErrors)) { if (!networkingParametersErrors.fixed_networks_amount && fixedAmount > 4095 - fixedVlan) { @@ -1071,7 +1120,8 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ networkingParametersErrors.base_mac = i18n(ns + 'invalid_mac'); } var cidr = networkParameters.get('internal_cidr'); - networkingParametersErrors = _.extend(networkingParametersErrors, utils.validateCidr(cidr, 'internal_cidr')); + networkingParametersErrors = _.extend(networkingParametersErrors, + utils.validateCidr(cidr, 'internal_cidr')); var gateway = networkParameters.get('internal_gateway'); if (!utils.validateIP(gateway)) { networkingParametersErrors.internal_gateway = i18n(ns + 'invalid_gateway'); @@ -1100,22 +1150,29 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({ var networkToCheckFloatingRangeData = networkToCheckFloatingRange ? { cidr: networkToCheckFloatingRange.get('cidr'), network: _.capitalize(networkToCheckFloatingRange.get('name')), - nodeNetworkGroup: nodeNetworkGroups.get(networkToCheckFloatingRange.get('group_id')).get('name') + nodeNetworkGroup: nodeNetworkGroups + .get(networkToCheckFloatingRange.get('group_id')) + .get('name') } : {}; - var networkToCheckFloatingRangeIPRanges = networkToCheckFloatingRange ? _.filter(networkToCheckFloatingRange.get('ip_ranges'), (range, index) => { - var ipRangeError = false; - try { - ipRangeError = !_.all(range) || !!_.find(errors.networks[networkToCheckFloatingRange.get('group_id')][networkToCheckFloatingRange.id].ip_ranges, {index: index}); - } catch (error) {} - return !ipRangeError; - }) : []; + var networkToCheckFloatingRangeIPRanges = networkToCheckFloatingRange ? + _.filter(networkToCheckFloatingRange.get('ip_ranges'), (range, index) => { + var ipRangeError = false; + try { + ipRangeError = !_.all(range) || + !!_.find(errors + .networks[networkToCheckFloatingRange + .get('group_id')][networkToCheckFloatingRange.id].ip_ranges, {index: index}); + } catch (error) {} + return !ipRangeError; + }) : []; floatingRangesErrors = utils.validateIPRanges( floatingRanges, networkToCheckFloatingRangeData.cidr, networkToCheckFloatingRangeIPRanges, { - IP_RANGES_INTERSECTION: i18n(ns + 'floating_and_public_ip_ranges_intersection', networkToCheckFloatingRangeData), + IP_RANGES_INTERSECTION: i18n(ns + 'floating_and_public_ip_ranges_intersection', + networkToCheckFloatingRangeData), IP_RANGE_IS_NOT_IN_PUBLIC_CIDR: i18n(ns + 'floating_range_is_not_in_public_cidr') } ); @@ -1268,7 +1325,8 @@ models.WizardModel = Backbone.DeepModel.extend({ var errors = []; _.each(options.config, (attributeConfig, attribute) => { if (!(attributeConfig.regex && attributeConfig.regex.source)) return; - var hasNoSatisfiedRestrictions = _.every(_.reject(attributeConfig.restrictions, {action: 'none'}), (restriction) => { + var hasNoSatisfiedRestrictions = _.every(_.reject(attributeConfig.restrictions, + {action: 'none'}), (restriction) => { // this probably will be changed when other controls need validation return !utils.evaluateExpression(restriction.condition, {default: this}).value; }); @@ -1291,14 +1349,17 @@ models.WizardModel = Backbone.DeepModel.extend({ models.MirantisCredentials = Backbone.DeepModel.extend(superMixin).extend({ constructorName: 'MirantisCredentials', - baseUrl: 'https://software.mirantis.com/wp-content/themes/mirantis_responsive_v_1_0/scripts/fuel_forms_api/', + baseUrl: 'https://software.mirantis.com/wp-content/themes/' + + 'mirantis_responsive_v_1_0/scripts/fuel_forms_api/', validate(attrs) { var errors = {}; _.each(attrs, (group, groupName) => { _.each(group, (setting, settingName) => { var path = this.makePath(groupName, settingName); if (!setting.regex || !setting.regex.source) return; - if (!setting.value.match(new RegExp(setting.regex.source))) errors[path] = setting.regex.error; + if (!setting.value.match(new RegExp(setting.regex.source))) { + errors[path] = setting.regex.error; + } }); }); return _.isEmpty(errors) ? null : errors; @@ -1414,7 +1475,8 @@ models.ComponentModel = BaseModel.extend({ var expandProperty = (propertyName, components) => { var expandedComponents = []; _.each(this.get(propertyName), (patternDescription) => { - var patternName = _.isString(patternDescription) ? patternDescription : patternDescription.name; + var patternName = _.isString(patternDescription) ? patternDescription : + patternDescription.name; var pattern = new ComponentPattern(patternName); components.each((component) => { if (pattern.match(component.id)) { diff --git a/static/plugins/vmware/vmware_models.js b/static/plugins/vmware/vmware_models.js index 9b031632e..75da1cc68 100644 --- a/static/plugins/vmware/vmware_models.js +++ b/static/plugins/vmware/vmware_models.js @@ -36,67 +36,74 @@ function testRegex(regexText, value) { return regexCache[regexText].test(value); } -var BaseModel = Backbone.Model.extend(models.superMixin).extend(models.cacheMixin).extend(models.restrictionMixin).extend({ - constructorName: 'BaseModel', - cacheFor: 60 * 1000, - toJSON() { - return _.omit(this.attributes, 'metadata'); - }, - validate() { - var result = {}; - _.each(this.attributes.metadata, (field) => { - if (!VmWareModels.isRegularField(field) || field.type == 'checkbox') { - return; - } - var isDisabled = this.checkRestrictions(restrictionModels, undefined, field); - if (isDisabled.result) { - return; - } - var value = this.get(field.name); - if (field.regex) { - if (!testRegex(field.regex.source, value)) { - result[field.name] = field.regex.error; +var BaseModel = Backbone.Model + .extend(models.superMixin) + .extend(models.cacheMixin) + .extend(models.restrictionMixin) + .extend({ + constructorName: 'BaseModel', + cacheFor: 60 * 1000, + toJSON() { + return _.omit(this.attributes, 'metadata'); + }, + validate() { + var result = {}; + _.each(this.attributes.metadata, (field) => { + if (!VmWareModels.isRegularField(field) || field.type == 'checkbox') { + return; } - } - }); - return _.isEmpty(result) ? null : result; - }, - testRestrictions() { - var results = { - hide: {}, - disable: {} - }; - var metadata = this.get('metadata'); - _.each(metadata, (field) => { - var disableResult = this.checkRestrictions(restrictionModels, undefined, field); - results.disable[field.name] = disableResult; + var isDisabled = this.checkRestrictions(restrictionModels, undefined, field); + if (isDisabled.result) { + return; + } + var value = this.get(field.name); + if (field.regex) { + if (!testRegex(field.regex.source, value)) { + result[field.name] = field.regex.error; + } + } + }); + return _.isEmpty(result) ? null : result; + }, + testRestrictions() { + var results = { + hide: {}, + disable: {} + }; + var metadata = this.get('metadata'); + _.each(metadata, (field) => { + var disableResult = this.checkRestrictions(restrictionModels, undefined, field); + results.disable[field.name] = disableResult; - var hideResult = this.checkRestrictions(restrictionModels, 'hide', field); - results.hide[field.name] = hideResult; - }); - return results; - } -}); + var hideResult = this.checkRestrictions(restrictionModels, 'hide', field); + results.hide[field.name] = hideResult; + }); + return results; + } + }); -var BaseCollection = Backbone.Collection.extend(models.superMixin).extend(models.cacheMixin).extend({ - constructorName: 'BaseCollection', - model: BaseModel, - cacheFor: 60 * 1000, - isValid() { - this.validationError = this.validate(); - return this.validationError; - }, - validate() { - var errors = _.compact(this.models.map((model) => { - model.isValid(); - return model.validationError; - })); - return _.isEmpty(errors) ? null : errors; - }, - testRestrictions() { - _.invoke(this.models, 'testRestrictions', restrictionModels); - } -}); +var BaseCollection = Backbone.Collection + .extend(models.superMixin) + .extend(models.cacheMixin) + .extend({ + constructorName: 'BaseCollection', + model: BaseModel, + cacheFor: 60 * 1000, + isValid() { + this.validationError = this.validate(); + return this.validationError; + }, + validate() { + var errors = _.compact(this.models.map((model) => { + model.isValid(); + return model.validationError; + })); + return _.isEmpty(errors) ? null : errors; + }, + testRestrictions() { + _.invoke(this.models, 'testRestrictions', restrictionModels); + } + }); VmWareModels.NovaCompute = BaseModel.extend({ constructorName: 'NovaCompute', @@ -209,7 +216,8 @@ VmWareModels.Glance = BaseModel.extend({constructorName: 'Glance'}); VmWareModels.VCenter = BaseModel.extend({ constructorName: 'VCenter', url() { - return '/api/v1/clusters/' + this.id + '/vmware_attributes' + (this.loadDefaults ? '/defaults' : ''); + return '/api/v1/clusters/' + this.id + '/vmware_attributes' + + (this.loadDefaults ? '/defaults' : ''); }, parse(response) { if (!response.editable || !response.editable.metadata || !response.editable.value) { @@ -289,7 +297,8 @@ VmWareModels.VCenter = BaseModel.extend({ }); }); var unassignedNodes = restrictionModels.cluster.get('nodes').filter((node) => { - return _.contains(node.get('pending_roles'), 'compute-vmware') && !assignedNodes[node.get('hostname')]; + return _.contains(node.get('pending_roles'), 'compute-vmware') && + !assignedNodes[node.get('hostname')]; }); if (unassignedNodes.length > 0) { errors.unassigned_nodes = unassignedNodes; diff --git a/static/plugins/vmware/vmware_tab.js b/static/plugins/vmware/vmware_tab.js index 748110397..6b3c0e7e5 100644 --- a/static/plugins/vmware/vmware_tab.js +++ b/static/plugins/vmware/vmware_tab.js @@ -236,7 +236,13 @@ var AvailabilityZones = React.createClass({ } {this.props.collection.map((model) => { - return ; + return ; })} ); @@ -310,7 +316,8 @@ var VmWareTab = React.createClass({ this.model.setModels({ cluster: this.props.cluster, settings: this.props.cluster.get('settings'), - networking_parameters: this.props.cluster.get('networkConfiguration').get('networking_parameters') + networking_parameters: this.props.cluster.get('networkConfiguration') + .get('networking_parameters') }); this.onModelSync(); // eslint-disable-line no-sync @@ -419,13 +426,25 @@ var VmWareTab = React.createClass({
- - -
diff --git a/static/tests/functional/helpers.js b/static/tests/functional/helpers.js index a34d9b439..469e567b5 100644 --- a/static/tests/functional/helpers.js +++ b/static/tests/functional/helpers.js @@ -125,7 +125,8 @@ define([ var dragAndDrop = (function() { var dispatchEvent, createEvent; - // Setup methods to call the proper event creation and dispatch functions for the current platform. + // Setup methods to call the proper event creation and + // dispatch functions for the current platform. if (document.createEvent) { dispatchEvent = function(element, eventName, event) { element.dispatchEvent(event); @@ -215,8 +216,8 @@ define([ try { event = createEvent('MouseEvent'); - event.initMouseEvent(eventName, true, true, window, 0, screenX, screenY, clientX, clientY, - false, false, false, false, 0, null); + event.initMouseEvent(eventName, true, true, window, 0, screenX, screenY, clientX, + clientY, false, false, false, false, 0, null); } catch (error) { event = createCustomEvent(eventName, screenX, screenY, clientX, clientY); } @@ -230,7 +231,8 @@ define([ function simulateEvent(element, eventName, dragStartEvent, options) { var dataTransfer = dragStartEvent ? dragStartEvent.dataTransfer : null; - var createEvent = eventName.indexOf('mouse') !== -1 ? createMouseEvent : createDragEvent; + var createEvent = eventName.indexOf('mouse') !== -1 ? createMouseEvent : + createDragEvent; var event = createEvent(eventName, options, dataTransfer); return dispatchEvent(element, eventName, event); } diff --git a/static/tests/functional/pages/common.js b/static/tests/functional/pages/common.js index 2d0a9d18d..36575ed30 100644 --- a/static/tests/functional/pages/common.js +++ b/static/tests/functional/pages/common.js @@ -86,7 +86,9 @@ function(_, assert, Helpers, pollUntil, LoginPage, WelcomePage, ClusterPage, Clu return self.clusterPage.removeCluster(clusterName); }) .catch(function(e) { - if (!suppressErrors) throw new Error('Unable to delete cluster ' + clusterName + ': ' + e); + if (!suppressErrors) { + throw new Error('Unable to delete cluster ' + clusterName + ': ' + e); + } }); }, doesClusterExist: function(clusterName) { @@ -115,7 +117,8 @@ function(_, assert, Helpers, pollUntil, LoginPage, WelcomePage, ClusterPage, Clu .clickByCssSelector('button.btn-add-nodes') .waitForCssSelector('.node', 3000) .then(pollUntil(function() { - return window.$('.node-list-management-buttons').is(':visible') && window.$('.role-panel').is(':visible') || null; + return window.$('.node-list-management-buttons').is(':visible') && + window.$('.role-panel').is(':visible') || null; }, 3000)) .then(function() { if (nodeNameFilter) return self.clusterPage.searchForNode(nodeNameFilter); diff --git a/static/tests/functional/pages/healthcheck.js b/static/tests/functional/pages/healthcheck.js index 82194f763..58e1c0e27 100644 --- a/static/tests/functional/pages/healthcheck.js +++ b/static/tests/functional/pages/healthcheck.js @@ -51,7 +51,8 @@ define([ duration: '20s', message: null, id: 'fuel_health.tests.check_disk', - description: 'Target component: Nova Scenario: 1. Check outage on controller and compute nodes' + description: 'Target component: Nova ' + + 'Scenario: 1. Check outage on controller and compute nodes' }, { status: null, @@ -73,7 +74,8 @@ define([ duration: '30s.', message: null, id: 'fuel_health.tests.general', - description: 'Target component: Logging Scenario: 1. Check logrotate cron job on all controller and compute nodes' + description: 'Target component: Logging ' + + 'Scenario: 1. Check logrotate cron job on all controller and compute nodes' }, { status: null, @@ -84,7 +86,8 @@ define([ duration: '1sec', message: null, id: 'fuel_health.tests.credentials', - description: 'Target component: Configuration Scenario: 1. Check user can not ssh on master node with default credentials. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check user can not ssh on master node with default credentials.' }, { status: null, @@ -95,7 +98,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_change', - description: 'Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if default credentials for OpenStack cluster have changed.' }, { status: null, @@ -117,7 +121,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_erros', - description: 'Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' }] ) ]); @@ -154,7 +159,8 @@ define([ duration: '20s', message: null, id: 'fuel_health.tests.check_disk', - description: 'Target component: Nova Scenario: 1. Check outage on controller and compute nodes' + description: 'Target component: Nova ' + + 'Scenario: 1. Check outage on controller and compute nodes' }, { status: 'stopped', @@ -176,7 +182,8 @@ define([ duration: '30s.', message: 'Fast fail with message', id: 'fuel_health.tests.general', - description: 'Target component: Logging Scenario: 1. Check logrotate cron job on all controller and compute nodes' + description: 'Target component: Logging ' + + 'Scenario: 1. Check logrotate cron job on all controller and compute nodes' }, { status: 'wait_running', @@ -187,7 +194,8 @@ define([ duration: '1sec', message: 'failure text message', id: 'fuel_health.tests.credentials', - description: 'Target component: Configuration Scenario: 1. Check user can not ssh on master node with default credentials. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check user can not ssh on master node with default credentials.' }, { status: 'running', @@ -198,7 +206,8 @@ define([ duration: '', message: 'Error message', id: 'fuel_health.tests.credentials_change', - description: ' Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: ' Target component: Configuration ' + + 'Scenario: 1. Check if default credentials for OpenStack cluster have changed.' }, { status: 'wait_running', @@ -220,7 +229,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_erros', - description: 'Target component: Configuration Scenario: 1. Check if error credentials for OpenStack cluster not suit.' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if error credentials for OpenStack cluster not suit.' }] ) ]); @@ -244,7 +254,8 @@ define([ duration: '20s', message: null, id: 'fuel_health.tests.check_disk', - description: 'Target component: Nova Scenario: 1. Check outage on controller and compute nodes' + description: 'Target component: Nova ' + + 'Scenario: 1. Check outage on controller and compute nodes' }, { status: 'stopped', @@ -266,7 +277,8 @@ define([ duration: '30s.', message: 'Fast fail with message', id: 'fuel_health.tests.general', - description: 'Target component: Logging Scenario: 1. Check logrotate cron job on all controller and compute nodes' + description: 'Target component: Logging ' + + 'Scenario: 1. Check logrotate cron job on all controller and compute nodes' }, { status: 'wait_running', @@ -277,7 +289,8 @@ define([ duration: '1sec', message: 'failure text message', id: 'fuel_health.tests.credentials', - description: 'Target component: Configuration Scenario: 1. Check user can not ssh on master node with default credentials. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check user can not ssh on master node with default credentials.' }, { status: 'running', @@ -288,7 +301,9 @@ define([ duration: '', message: 'Error message', id: 'fuel_health.tests.credentials_change', - description: ' Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: ' Target component: Configuration ' + + 'Scenario: ' + + '1. Check if default credentials for OpenStack cluster have changed.' }, { status: 'wait_running', @@ -310,7 +325,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_erros', - description: 'Target component: Configuration Scenario: 1. Check if error credentials for OpenStack cluster not suit.' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if error credentials for OpenStack cluster not suit.' } ] }] @@ -345,7 +361,8 @@ define([ duration: '20s', message: null, id: 'fuel_health.tests.check_disk', - description: 'Target component: Nova Scenario: 1. Check outage on controller and compute nodes' + description: 'Target component: Nova ' + + 'Scenario: 1. Check outage on controller and compute nodes' }, { status: 'stopped', @@ -367,7 +384,9 @@ define([ duration: '30s.', message: 'Fast fail with message', id: 'fuel_health.tests.general', - description: 'Target component: Logging Scenario: 1. Check logrotate cron job on all controller and compute nodes' + description: 'Target component: Logging ' + + 'Scenario: ' + + '1. Check logrotate cron job on all controller and compute nodes' }, { status: 'skipped', @@ -378,7 +397,8 @@ define([ duration: '1sec', message: 'failure text message', id: 'fuel_health.tests.credentials', - description: 'Target component: Configuration Scenario: 1. Check user can not ssh on master node with default credentials. ' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check user can not ssh on master node with default credentials.' }, { status: 'success', @@ -389,7 +409,9 @@ define([ duration: '', message: 'Error message', id: 'fuel_health.tests.credentials_change', - description: ' Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: ' Target component: Configuration ' + + 'Scenario: ' + + '1. Check if default credentials for OpenStack cluster have changed. ' }, { status: 'failure', @@ -411,7 +433,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_erros', - description: 'Target component: Configuration Scenario: 1. Check if error credentials for OpenStack cluster not suit.' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if error credentials for OpenStack cluster not suit.' } ]) ]); @@ -435,7 +458,8 @@ define([ duration: '20s', message: null, id: 'fuel_health.tests.check_disk', - description: 'Target component: Nova Scenario: 1. Check outage on controller and compute nodes' + description: 'Target component: Nova ' + + 'Scenario: 1. Check outage on controller and compute nodes' }, { status: 'stopped', @@ -457,7 +481,9 @@ define([ duration: '30s.', message: 'Fast fail with message', id: 'fuel_health.tests.general', - description: 'Target component: Logging Scenario: 1. Check logrotate cron job on all controller and compute nodes' + description: 'Target component: Logging ' + + 'Scenario: ' + + '1. Check logrotate cron job on all controller and compute nodes' }, { status: 'skipped', @@ -468,7 +494,9 @@ define([ duration: '1sec', message: 'failure text message', id: 'fuel_health.tests.credentials', - description: 'Target component: Configuration Scenario: 1. Check user can not ssh on master node with default credentials. ' + description: 'Target component: Configuration ' + + 'Scenario: ' + + '1. Check user can not ssh on master node with default credentials. ' }, { status: 'success', @@ -479,7 +507,9 @@ define([ duration: '', message: 'Error message', id: 'fuel_health.tests.credentials_change', - description: ' Target component: Configuration Scenario: 1. Check if default credentials for OpenStack cluster have changed. ' + description: ' Target component: Configuration ' + + 'Scenario: ' + + '1. Check if default credentials for OpenStack cluster have changed. ' }, { status: 'failure', @@ -501,7 +531,8 @@ define([ duration: '', message: null, id: 'fuel_health.tests.credentials_erros', - description: 'Target component: Configuration Scenario: 1. Check if error credentials for OpenStack cluster not suit.' + description: 'Target component: Configuration ' + + 'Scenario: 1. Check if error credentials for OpenStack cluster not suit.' } ] }] diff --git a/static/tests/functional/pages/interfaces.js b/static/tests/functional/pages/interfaces.js index 193c59e82..983a73449 100644 --- a/static/tests/functional/pages/interfaces.js +++ b/static/tests/functional/pages/interfaces.js @@ -133,7 +133,8 @@ define([ return bondElement .findAllByCssSelector('.ifc-name') .then(function(ifcNamesElements) { - assert.equal(ifcNamesElements.length, ifcsNames.length, 'Unexpected number of interfaces in bond'); + assert.equal(ifcNamesElements.length, ifcsNames.length, + 'Unexpected number of interfaces in bond'); return ifcNamesElements.forEach( function(ifcNameElement) { diff --git a/static/tests/functional/pages/modal.js b/static/tests/functional/pages/modal.js index c80583952..5e8d0e908 100644 --- a/static/tests/functional/pages/modal.js +++ b/static/tests/functional/pages/modal.js @@ -35,7 +35,8 @@ define([ }, checkTitle: function(expectedTitle) { return this.remote - .assertElementContainsText(this.modalSelector + ' h4.modal-title', expectedTitle, 'Unexpected modal window title'); + .assertElementContainsText(this.modalSelector + ' h4.modal-title', expectedTitle, + 'Unexpected modal window title'); }, close: function() { var self = this; diff --git a/static/tests/functional/test_cluster_dashboard.js b/static/tests/functional/test_cluster_dashboard.js index 48338934f..129f9cfcb 100644 --- a/static/tests/functional/test_cluster_dashboard.js +++ b/static/tests/functional/test_cluster_dashboard.js @@ -86,8 +86,10 @@ define([ .then(function() { return dashboardPage.setClusterName(initialName); }) - .assertElementAppears('.rename-block.has-error', 1000, 'Error style for duplicate name is applied') - .assertElementTextEquals('.rename-block .text-danger', 'Environment with this name already exists', + .assertElementAppears('.rename-block.has-error', 1000, + 'Error style for duplicate name is applied') + .assertElementTextEquals('.rename-block .text-danger', + 'Environment with this name already exists', 'Duplicate name error text appears' ) .findByCssSelector(renameInputSelector) @@ -129,7 +131,8 @@ define([ return clusterPage.goToTab('Dashboard'); }) .assertElementContainsText('.warnings-block', - 'Please verify your network settings before deployment', 'Network verification warning is shown') + 'Please verify your network settings before deployment', + 'Network verification warning is shown') .then(function() { return dashboardPage.discardChanges(); }); @@ -143,7 +146,8 @@ define([ .then(function() { return clusterPage.goToTab('Dashboard'); }) - .assertElementDisabled(dashboardPage.deployButtonSelector, 'No deployment should be possible without controller nodes added') + .assertElementDisabled(dashboardPage.deployButtonSelector, + 'No deployment should be possible without controller nodes added') .assertElementExists('div.instruction.invalid', 'Invalid configuration message is shown') .assertElementContainsText('.environment-alerts ul.text-danger li', 'At least 1 Controller nodes are required (0 selected currently).', @@ -178,7 +182,8 @@ define([ var operatingSystemNodes = 1; var virtualNodes = 1; var valueSelector = '.statistics-block .cluster-info-value'; - var total = controllerNodes + storageCinderNodes + computeNodes + operatingSystemNodes + virtualNodes; + var total = controllerNodes + storageCinderNodes + computeNodes + operatingSystemNodes + + virtualNodes; return this.remote .then(function() { return common.addNodesToCluster(controllerNodes, ['Controller']); @@ -201,11 +206,13 @@ define([ .assertElementTextEquals(valueSelector + '.total', total, 'The number of Total nodes in statistics is updated according to added nodes') .assertElementTextEquals(valueSelector + '.controller', controllerNodes, - 'The number of controllerNodes nodes in statistics is updated according to added nodes') + 'The number of controllerNodes nodes in statistics is updated according to ' + + 'added nodes') .assertElementTextEquals(valueSelector + '.compute', computeNodes, 'The number of Compute nodes in statistics is updated according to added nodes') .assertElementTextEquals(valueSelector + '.base-os', operatingSystemNodes, - 'The number of Operating Systems nodes in statistics is updated according to added nodes') + 'The number of Operating Systems nodes in statistics is updated according to ' + + 'added nodes') .assertElementTextEquals(valueSelector + '.virt', virtualNodes, 'The number of Virtual nodes in statistics is updated according to added nodes') .assertElementTextEquals(valueSelector + '.offline', 1, @@ -213,7 +220,8 @@ define([ .assertElementTextEquals(valueSelector + '.error', 1, 'The number of Error nodes in statistics is updated according to added nodes') .assertElementTextEquals(valueSelector + '.pending_addition', total, - 'The number of Pending Addition nodes in statistics is updated according to added nodes') + 'The number of Pending Addition nodes in statistics is updated according to ' + + 'added nodes') .then(function() { return dashboardPage.discardChanges(); }); @@ -232,8 +240,10 @@ define([ .then(function() { return dashboardPage.startDeployment(); }) - .assertElementDisappears('.dashboard-block .progress', 60000, 'Progress bar disappears after deployment') - .assertElementAppears('.dashboard-tab .alert strong', 1000, 'Error message is shown when adding error node') + .assertElementDisappears('.dashboard-block .progress', 60000, + 'Progress bar disappears after deployment') + .assertElementAppears('.dashboard-tab .alert strong', 1000, + 'Error message is shown when adding error node') .assertElementTextEquals('.dashboard-tab .alert strong', 'Error', 'Deployment failed in case of adding offline nodes') .then(function() { diff --git a/static/tests/functional/test_cluster_deployment.js b/static/tests/functional/test_cluster_deployment.js index ece80b45d..7c4a1e390 100644 --- a/static/tests/functional/test_cluster_deployment.js +++ b/static/tests/functional/test_cluster_deployment.js @@ -58,7 +58,8 @@ define([ }, 'No deployment button when there are no nodes added': function() { return this.remote - .assertElementNotExists(dashboardPage.deployButtonSelector, 'No deployment should be possible without nodes added'); + .assertElementNotExists(dashboardPage.deployButtonSelector, + 'No deployment should be possible without nodes added'); }, 'Discard changes': function() { return this.remote @@ -73,14 +74,16 @@ define([ .then(function() { return modal.waitToOpen(); }) - .assertElementContainsText('h4.modal-title', 'Discard Changes', 'Discard Changes confirmation modal expected') + .assertElementContainsText('h4.modal-title', 'Discard Changes', + 'Discard Changes confirmation modal expected') .then(function() { return modal.clickFooterButton('Discard'); }) .then(function() { return modal.waitToClose(); }) - .assertElementAppears('.dashboard-block a.btn-add-nodes', 2000, 'All changes discarded, add nodes button gets visible in deploy readiness block'); + .assertElementAppears('.dashboard-block a.btn-add-nodes', 2000, + 'All changes discarded, add nodes button gets visible in deploy readiness block'); }, 'Start/stop deployment': function() { this.timeout = 100000; @@ -96,14 +99,18 @@ define([ return dashboardPage.startDeployment(); }) .assertElementAppears('div.deploy-process div.progress', 2000, 'Deployment started') - .assertElementAppears('button.stop-deployment-btn:not(:disabled)', 5000, 'Stop button appears') + .assertElementAppears('button.stop-deployment-btn:not(:disabled)', 5000, + 'Stop button appears') .then(function() { return dashboardPage.stopDeployment(); }) .assertElementDisappears('div.deploy-process div.progress', 20000, 'Deployment stopped') - .assertElementAppears(dashboardPage.deployButtonSelector, 1000, 'Deployment button available') - .assertElementContainsText('div.alert-warning strong', 'Success', 'Deployment successfully stopped alert is expected') - .assertElementNotExists('.go-to-healthcheck', 'Healthcheck link is not visible after stopped deploy') + .assertElementAppears(dashboardPage.deployButtonSelector, 1000, + 'Deployment button available') + .assertElementContainsText('div.alert-warning strong', 'Success', + 'Deployment successfully stopped alert is expected') + .assertElementNotExists('.go-to-healthcheck', + 'Healthcheck link is not visible after stopped deploy') // Reset environment button is available .then(function() { return clusterPage.resetEnvironment(clusterName); @@ -134,7 +141,8 @@ define([ .then(function() { return dashboardPage.startDeployment(); }) - .assertElementDisappears('.dashboard-block .progress', 60000, 'Progress bar disappears after deployment') + .assertElementDisappears('.dashboard-block .progress', 60000, + 'Progress bar disappears after deployment') .assertElementAppears('.links-block', 5000, 'Deployment completed') .assertElementExists('.go-to-healthcheck', 'Healthcheck link is visible after deploy') .findByLinkText('Horizon') @@ -149,7 +157,8 @@ define([ .then(function(isLocked) { assert.isTrue(isLocked, 'Networks tab should turn locked after deployment'); }) - .assertElementEnabled('.add-nodegroup-btn', 'Add Node network group button is enabled after cluster deploy') + .assertElementEnabled('.add-nodegroup-btn', + 'Add Node network group button is enabled after cluster deploy') .then(function() { return clusterPage.isTabLocked('Settings'); }) diff --git a/static/tests/functional/test_cluster_healthcheck.js b/static/tests/functional/test_cluster_healthcheck.js index 51c35065f..055e062b9 100644 --- a/static/tests/functional/test_cluster_healthcheck.js +++ b/static/tests/functional/test_cluster_healthcheck.js @@ -64,11 +64,16 @@ define([ return clusterPage.goToTab('Health Check'); }) .assertElementsAppear('.healthcheck-table', 5000, 'Healthcheck tables are rendered') - .assertElementDisabled('.custom-tumbler input[type=checkbox]', 'Test checkbox is disabled') - .assertElementContainsText('.alert-warning', 'Before you can test an OpenStack environment, you must deploy the OpenStack environment', + .assertElementDisabled('.custom-tumbler input[type=checkbox]', + 'Test checkbox is disabled') + .assertElementContainsText('.alert-warning', + 'Before you can test an OpenStack environment, ' + + 'you must deploy the OpenStack environment', 'Warning to deploy cluster is shown') - .assertElementNotExists('.run-tests-btn', 'Run tests button is not shown in new OpenStack environment') - .assertElementNotExists('.stop-tests-btn', 'Stop tests button is not shown in new OpenStack environment'); + .assertElementNotExists('.run-tests-btn', + 'Run tests button is not shown in new OpenStack environment') + .assertElementNotExists('.stop-tests-btn', + 'Stop tests button is not shown in new OpenStack environment'); }, //@TODO (morale): imitate tests stop 'Check Healthcheck tab manipulations after deploy': function() { @@ -86,9 +91,11 @@ define([ .then(function() { return clusterPage.goToTab('Health Check'); }) - .assertElementEnabled('.custom-tumbler input[type=checkbox]', 'Test checkbox is enabled after deploy') + .assertElementEnabled('.custom-tumbler input[type=checkbox]', + 'Test checkbox is enabled after deploy') // 'run tests' button interactions - .assertElementDisabled('.run-tests-btn', 'Run tests button is disabled if no tests checked') + .assertElementDisabled('.run-tests-btn', + 'Run tests button is disabled if no tests checked') .assertElementNotExists('.stop-tests-btn', 'Stop tests button is not visible if no tests checked') .assertElementExists('.toggle-credentials', 'Toggle credentials button is visible') @@ -120,7 +127,8 @@ define([ .assertElementNotExists('.run-tests-btn', 'Run tests button is not shown if tests are running') .assertElementEnabled('.stop-tests-btn', 'Stop tests button is enabled during tests run') - .assertElementsAppear('.glyphicon-refresh.animate-spin', 1000, 'Running status is reflected') + .assertElementsAppear('.glyphicon-refresh.animate-spin', 1000, + 'Running status is reflected') .assertElementsAppear('.glyphicon-time', 1000, 'Waiting to run status is reflected') .assertElementsAppear('.healthcheck-status-skipped', 1000, 'Skipped status is reflected') .assertElementsAppear('.healthcheck-status-stopped', 1000, 'Stopped status is reflected'); @@ -140,9 +148,11 @@ define([ .then(function() { return clusterPage.goToTab('Health Check'); }) - .assertElementNotExists('.stop-tests-btn', 'Stop tests button is not shown if tests are finished') + .assertElementNotExists('.stop-tests-btn', + 'Stop tests button is not shown if tests are finished') .assertElementsAppear('.glyphicon-ok', 1000, 'Success status is reflected') - .assertElementsAppear('.glyphicon-remove', 1000, 'Error and Failure statuses are reflected'); + .assertElementsAppear('.glyphicon-remove', 1000, + 'Error and Failure statuses are reflected'); } }; }); diff --git a/static/tests/functional/test_cluster_logs.js b/static/tests/functional/test_cluster_logs.js index 6f9baa9e7..e16ab42e9 100644 --- a/static/tests/functional/test_cluster_logs.js +++ b/static/tests/functional/test_cluster_logs.js @@ -50,13 +50,16 @@ define([ '"Show" button availability and logs displaying': function() { var showLogsButtonSelector = '.sticker button'; return this.remote - .assertElementsExist('.sticker select[name=source] > option', 'Check if "Source" dropdown exist') - .assertElementDisabled(showLogsButtonSelector, '"Show" button is disabled until source change') + .assertElementsExist('.sticker select[name=source] > option', + 'Check if "Source" dropdown exist') + .assertElementDisabled(showLogsButtonSelector, + '"Show" button is disabled until source change') // Change the selected value for the "Source" dropdown to Rest API .clickByCssSelector('.sticker select[name=source] option[value=api]') // Change the selected value for the "Level" dropdown to DEBUG .clickByCssSelector('.sticker select[name=level] option[value=DEBUG]') - .assertElementEnabled(showLogsButtonSelector, '"Show" button is enabled after source change') + .assertElementEnabled(showLogsButtonSelector, + '"Show" button is enabled after source change') .execute(function() { window.fakeServer = sinon.fakeServer.create(); window.fakeServer.autoRespond = true; @@ -70,7 +73,8 @@ define([ ]); }) .clickByCssSelector(showLogsButtonSelector) - .assertElementDisappears('.logs-tab div.progress', 5000, 'Wait till Progress bar disappears') + .assertElementDisappears('.logs-tab div.progress', 5000, + 'Wait till Progress bar disappears') .assertElementsAppear('.log-entries > tbody > tr', 5000, 'Log entries are shown') .execute(function() { window.fakeServer.restore(); diff --git a/static/tests/functional/test_cluster_network.js b/static/tests/functional/test_cluster_network.js index a9019419b..9fc7e5cad 100644 --- a/static/tests/functional/test_cluster_network.js +++ b/static/tests/functional/test_cluster_network.js @@ -100,10 +100,13 @@ define([ return this.remote .clickByCssSelector('.subtab-link-default') .assertElementAppears('.storage', 2000, 'Storage network is shown') - .assertElementSelected('.storage .cidr input[type=checkbox]', 'Storage network has "cidr" notation by default') - .assertElementNotExists('.storage .ip_ranges input[type=text]:not(:disabled)', 'It is impossible to configure IP ranges for network with "cidr" notation') + .assertElementSelected('.storage .cidr input[type=checkbox]', + 'Storage network has "cidr" notation by default') + .assertElementNotExists('.storage .ip_ranges input[type=text]:not(:disabled)', + 'It is impossible to configure IP ranges for network with "cidr" notation') .clickByCssSelector('.storage .cidr input[type=checkbox]') - .assertElementNotExists('.storage .ip_ranges input[type=text]:disabled', 'Network notation was changed to "ip_ranges"'); + .assertElementNotExists('.storage .ip_ranges input[type=text]:disabled', + 'Network notation was changed to "ip_ranges"'); }, 'Testing cluster networks: save network changes': function() { var cidrElementSelector = '.storage .cidr input[type=text]'; @@ -112,12 +115,14 @@ define([ .clickByCssSelector(applyButtonSelector) .assertElementsAppear('input:not(:disabled)', 2000, 'Inputs are not disabled') .assertElementNotExists('.alert-error', 'Correct settings were saved successfully') - .assertElementDisabled(applyButtonSelector, 'Save changes button is disabled again after successful settings saving'); + .assertElementDisabled(applyButtonSelector, + 'Save changes button is disabled again after successful settings saving'); }, 'Testing cluster networks: verification': function() { return this.remote .clickByCssSelector('.subtab-link-network_verification') - .assertElementDisabled('.verify-networks-btn', 'Verification button is disabled in case of no nodes') + .assertElementDisabled('.verify-networks-btn', + 'Verification button is disabled in case of no nodes') .assertElementTextEquals('.alert-warning', 'At least two online nodes are required to verify environment network configuration', 'Not enough nodes warning is shown') @@ -133,17 +138,20 @@ define([ .clickByCssSelector('.subtab-link-network_verification') .clickByCssSelector('.verify-networks-btn') .assertElementAppears('.alert-danger.network-alert', 4000, 'Verification error is shown') - .assertElementAppears('.alert-danger.network-alert', 'Address intersection', 'Verification result is shown in case of address intersection') + .assertElementAppears('.alert-danger.network-alert', 'Address intersection', + 'Verification result is shown in case of address intersection') // Testing cluster networks: verification task deletion .clickByCssSelector('.subtab-link-default') .setInputValue('.public input[name=gateway]', '172.16.0.5') .clickByCssSelector('.subtab-link-network_verification') - .assertElementNotExists('.page-control-box .alert', 'Verification task was removed after settings has been changed') + .assertElementNotExists('.page-control-box .alert', + 'Verification task was removed after settings has been changed') .clickByCssSelector('.btn-revert-changes') .clickByCssSelector('.verify-networks-btn') .waitForElementDeletion('.animation-box .success.connect-1', 6000) .assertElementAppears('.alert-success', 6000, 'Success verification message appears') - .assertElementContainsText('.alert-success', 'Verification succeeded', 'Success verification message appears with proper text') + .assertElementContainsText('.alert-success', 'Verification succeeded', + 'Success verification message appears with proper text') .clickByCssSelector('.btn-revert-changes') .then(function() { return clusterPage.goToTab('Dashboard'); @@ -185,7 +193,8 @@ define([ var rangeSelector = '.public .ip_ranges '; return this.remote .clickByCssSelector(rangeSelector + '.ip-ranges-add') - .assertElementsExist(rangeSelector + '.ip-ranges-delete', 2, 'Remove ranges controls appear') + .assertElementsExist(rangeSelector + '.ip-ranges-delete', 2, + 'Remove ranges controls appear') .clickByCssSelector(applyButtonSelector) .assertElementsExist(rangeSelector + '.range-row', 'Empty range row is removed after saving changes') @@ -216,7 +225,8 @@ define([ .then(function() { return clusterPage.goToTab('Networks'); }) - .assertElementNotExists('.private', 'Private Network is not visible for vlan segmentation type') + .assertElementNotExists('.private', + 'Private Network is not visible for vlan segmentation type') .assertElementTextEquals('.segmentation-type', '(Neutron with VLAN segmentation)', 'Segmentation type is correct for VLAN segmentation'); }, @@ -277,7 +287,8 @@ define([ .then(function() { return modal.waitToOpen(); }) - .assertElementContainsText('h4.modal-title', 'Add New Node Network Group', 'Add New Node Network Group modal expected') + .assertElementContainsText('h4.modal-title', 'Add New Node Network Group', + 'Add New Node Network Group modal expected') .setInputValue('[name=node-network-group-name]', 'Node_Network_Group_1') .then(function() { return modal.clickFooterButton('Add Group'); @@ -285,9 +296,11 @@ define([ .then(function() { return modal.waitToClose(); }) - .assertElementAppears('.node-network-groups-list', 2000, 'Node network groups title appears') + .assertElementAppears('.node-network-groups-list', 2000, + 'Node network groups title appears') .assertElementDisplayed('.subtab-link-Node_Network_Group_1', 'New subtab is shown') - .assertElementTextEquals('.network-group-name .btn-link', 'Node_Network_Group_1', 'New Node Network group title is shown'); + .assertElementTextEquals('.network-group-name .btn-link', 'Node_Network_Group_1', + 'New Node Network group title is shown'); }, 'Verification is disabled for multirack': function() { return this.remote @@ -306,26 +319,30 @@ define([ // Enter .type('\uE007') .end() - .assertElementDisplayed('.subtab-link-Node_Network_Group_2', 'Node network group was successfully renamed'); + .assertElementDisplayed('.subtab-link-Node_Network_Group_2', + 'Node network group was successfully renamed'); }, 'Node network group deletion': function() { return this.remote .clickByCssSelector('.subtab-link-default') - .assertElementNotExists('.glyphicon-remove', 'It is not possible to delete default node network group') + .assertElementNotExists('.glyphicon-remove', + 'It is not possible to delete default node network group') .clickByCssSelector('.subtab-link-Node_Network_Group_2') .assertElementAppears('.glyphicon-remove', 1000, 'Remove icon is shown') .clickByCssSelector('.glyphicon-remove') .then(function() { return modal.waitToOpen(); }) - .assertElementContainsText('h4.modal-title', 'Remove Node Network Group', 'Remove Node Network Group modal expected') + .assertElementContainsText('h4.modal-title', 'Remove Node Network Group', + 'Remove Node Network Group modal expected') .then(function() { return modal.clickFooterButton('Delete'); }) .then(function() { return modal.waitToClose(); }) - .assertElementDisappears('.subtab-link-Node_Network_Group_2', 2000, 'Node network groups title disappears'); + .assertElementDisappears('.subtab-link-Node_Network_Group_2', 2000, + 'Node network groups title disappears'); }, 'Node network group renaming in deployed environment': function() { this.timeout = 100000; @@ -344,9 +361,11 @@ define([ return clusterPage.goToTab('Networks'); }) .clickByCssSelector('.subtab-link-default') - .assertElementNotExists('.glyphicon-pencil', 'Renaming of a node network group is fobidden in deployed environment') + .assertElementNotExists('.glyphicon-pencil', + 'Renaming of a node network group is fobidden in deployed environment') .clickByCssSelector('.network-group-name .name') - .assertElementNotExists('.network-group-name input[type=text]', 'Renaming is not started on a node network group name click'); + .assertElementNotExists('.network-group-name input[type=text]', + 'Renaming is not started on a node network group name click'); } }; }); diff --git a/static/tests/functional/test_cluster_page.js b/static/tests/functional/test_cluster_page.js index c8357ed14..bf849952b 100644 --- a/static/tests/functional/test_cluster_page.js +++ b/static/tests/functional/test_cluster_page.js @@ -49,24 +49,31 @@ define([ }, 'Add Cluster Nodes': function() { return this.remote - .assertElementExists('.node-list .alert-warning', 'Node list shows warning if there are no nodes in environment') + .assertElementExists('.node-list .alert-warning', + 'Node list shows warning if there are no nodes in environment') .clickByCssSelector('.btn-add-nodes') .assertElementsAppear('.node', 2000, 'Unallocated nodes loaded') - .assertElementDisabled(applyButtonSelector, 'Apply button is disabled until both roles and nodes chosen') - .assertElementDisabled('.role-panel [type=checkbox][name=mongo]', 'Unavailable role has locked checkbox') - .assertElementExists('.role-panel .mongo i.tooltip-icon', 'Unavailable role has warning tooltip') + .assertElementDisabled(applyButtonSelector, + 'Apply button is disabled until both roles and nodes chosen') + .assertElementDisabled('.role-panel [type=checkbox][name=mongo]', + 'Unavailable role has locked checkbox') + .assertElementExists('.role-panel .mongo i.tooltip-icon', + 'Unavailable role has warning tooltip') .then(function() { return clusterPage.checkNodeRoles(['Controller', 'Storage - Cinder']); }) - .assertElementDisabled('.role-panel [type=checkbox][name=compute]', 'Compute role can not be added together with selected roles') - .assertElementDisabled(applyButtonSelector, 'Apply button is disabled until both roles and nodes chosen') + .assertElementDisabled('.role-panel [type=checkbox][name=compute]', + 'Compute role can not be added together with selected roles') + .assertElementDisabled(applyButtonSelector, + 'Apply button is disabled until both roles and nodes chosen') .then(function() { return clusterPage.checkNodes(nodesAmount); }) .clickByCssSelector(applyButtonSelector) .waitForElementDeletion(applyButtonSelector, 2000) .assertElementAppears('.nodes-group', 2000, 'Cluster node list loaded') - .assertElementsExist('.node-list .node', nodesAmount, nodesAmount + ' nodes were successfully added to the cluster') + .assertElementsExist('.node-list .node', nodesAmount, nodesAmount + + ' nodes were successfully added to the cluster') .assertElementExists('.nodes-group', 'One node group is present'); }, 'Edit cluster node roles': function() { @@ -78,17 +85,22 @@ define([ // select all nodes .clickByCssSelector('.select-all label') .clickByCssSelector('.btn-edit-roles') - .assertElementDisappears('.btn-edit-roles', 2000, 'Cluster nodes screen unmounted') - .assertElementNotExists('.node-box [type=checkbox]:not(:disabled)', 'Node selection is locked on Edit Roles screen') - .assertElementNotExists('[name=select-all]:not(:disabled)', 'Select All checkboxes are locked on Edit Roles screen') - .assertElementExists('.role-panel [type=checkbox][name=controller]:indeterminate', 'Controller role checkbox has indeterminate state') + .assertElementDisappears('.btn-edit-roles', 2000, + 'Cluster nodes screen unmounted') + .assertElementNotExists('.node-box [type=checkbox]:not(:disabled)', + 'Node selection is locked on Edit Roles screen') + .assertElementNotExists('[name=select-all]:not(:disabled)', + 'Select All checkboxes are locked on Edit Roles screen') + .assertElementExists('.role-panel [type=checkbox][name=controller]:indeterminate', + 'Controller role checkbox has indeterminate state') .then(function() { // uncheck Cinder role return clusterPage.checkNodeRoles(['Storage - Cinder', 'Storage - Cinder']); }) .clickByCssSelector(applyButtonSelector) .assertElementDisappears('.btn-apply', 2000, 'Role editing screen unmounted') - .assertElementsExist('.node-list .node', nodesAmount, 'One node was removed from cluster after editing roles'); + .assertElementsExist('.node-list .node', nodesAmount, + 'One node was removed from cluster after editing roles'); }, 'Remove Cluster': function() { return this.remote diff --git a/static/tests/functional/test_cluster_settings.js b/static/tests/functional/test_cluster_settings.js index e7a63d80e..c74d92a3a 100644 --- a/static/tests/functional/test_cluster_settings.js +++ b/static/tests/functional/test_cluster_settings.js @@ -56,7 +56,8 @@ define([ }, 'Settings tab is rendered correctly': function() { return this.remote - .assertElementNotExists('.nav .subtab-link-network', 'Subtab for Network settings is not presented in navigation') + .assertElementNotExists('.nav .subtab-link-network', + 'Subtab for Network settings is not presented in navigation') .assertElementEnabled('.btn-load-defaults', 'Load defaults button is enabled') .assertElementDisabled('.btn-revert-changes', 'Cancel Changes button is disabled') .assertElementDisabled('.btn-apply-changes', 'Save Settings button is disabled'); @@ -65,10 +66,12 @@ define([ return this.remote // introduce change .clickByCssSelector('input[type=checkbox]') - .assertElementAppears('.btn-apply-changes:not(:disabled)', 200, 'Save Settings button is enabled if there are changes') + .assertElementAppears('.btn-apply-changes:not(:disabled)', 200, + 'Save Settings button is enabled if there are changes') // reset the change .clickByCssSelector('input[type=checkbox]') - .assertElementAppears('.btn-apply-changes:disabled', 200, 'Save Settings button is disabled if there are no changes'); + .assertElementAppears('.btn-apply-changes:disabled', 200, + 'Save Settings button is disabled if there are no changes'); }, 'Check Cancel Changes button': function() { return this.remote @@ -86,7 +89,8 @@ define([ }) // reset changes .clickByCssSelector('.btn-revert-changes') - .assertElementDisabled('.btn-apply-changes', 'Save Settings button is disabled after changes were cancelled'); + .assertElementDisabled('.btn-apply-changes', + 'Save Settings button is disabled after changes were cancelled'); }, 'Check changes saving': function() { return this.remote @@ -97,7 +101,8 @@ define([ .then(function() { return settingsPage.waitForRequestCompleted(); }) - .assertElementDisabled('.btn-revert-changes', 'Cancel Changes button is disabled after changes were saved successfully'); + .assertElementDisabled('.btn-revert-changes', + 'Cancel Changes button is disabled after changes were saved successfully'); }, 'Check loading of defaults': function() { return this.remote @@ -106,12 +111,15 @@ define([ .then(function() { return settingsPage.waitForRequestCompleted(); }) - .assertElementEnabled('.btn-apply-changes', 'Save Settings button is enabled after defaults were loaded') - .assertElementEnabled('.btn-revert-changes', 'Cancel Changes button is enabled after defaults were loaded') + .assertElementEnabled('.btn-apply-changes', + 'Save Settings button is enabled after defaults were loaded') + .assertElementEnabled('.btn-revert-changes', + 'Cancel Changes button is enabled after defaults were loaded') // revert the change .clickByCssSelector('.btn-revert-changes'); }, - 'The choice of subgroup is preserved when user navigates through the cluster tabs': function() { + 'The choice of subgroup is preserved when user navigates through the cluster tabs': + function() { return this.remote .clickLinkByText('Logging') .then(function() { @@ -120,20 +128,26 @@ define([ .then(function() { return clusterPage.goToTab('Settings'); }) - .assertElementExists('.nav-pills li.active a.subtab-link-logging', 'The choice of subgroup is preserved when user navigates through the cluster tabs'); + .assertElementExists('.nav-pills li.active a.subtab-link-logging', + 'The choice of subgroup is preserved when user navigates through the cluster tabs'); }, 'The page reacts on invalid input': function() { return this.remote .clickLinkByText('General') // "nova" is forbidden username .setInputValue('[type=text][name=user]', 'nova') - .assertElementAppears('.setting-section .form-group.has-error', 200, 'Invalid field marked as error') - .assertElementExists('.settings-tab .nav-pills > li.active i.glyphicon-danger-sign', 'Subgroup with invalid field marked as invalid') - .assertElementDisabled('.btn-apply-changes', 'Save Settings button is disabled in case of validation error') + .assertElementAppears('.setting-section .form-group.has-error', 200, + 'Invalid field marked as error') + .assertElementExists('.settings-tab .nav-pills > li.active i.glyphicon-danger-sign', + 'Subgroup with invalid field marked as invalid') + .assertElementDisabled('.btn-apply-changes', + 'Save Settings button is disabled in case of validation error') // revert the change .clickByCssSelector('.btn-revert-changes') - .assertElementNotExists('.setting-section .form-group.has-error', 'Validation error is cleared after resetting changes') - .assertElementNotExists('.settings-tab .nav-pills > li.active i.glyphicon-danger-sign', 'Subgroup menu has default layout after resetting changes'); + .assertElementNotExists('.setting-section .form-group.has-error', + 'Validation error is cleared after resetting changes') + .assertElementNotExists('.settings-tab .nav-pills > li.active i.glyphicon-danger-sign', + 'Subgroup menu has default layout after resetting changes'); }, 'Test repositories custom control': function() { var repoAmount; @@ -146,18 +160,22 @@ define([ repoAmount = elements.length; }) .end() - .assertElementNotExists('.repos .form-inline:nth-of-type(1) .btn-link', 'The first repo can not be deleted') + .assertElementNotExists('.repos .form-inline:nth-of-type(1) .btn-link', + 'The first repo can not be deleted') // delete some repo .clickByCssSelector('.repos .form-inline .btn-link') .then(function() { - return self.remote.assertElementsExist('.repos .form-inline', repoAmount - 1, 'Repo was deleted'); + return self.remote.assertElementsExist('.repos .form-inline', repoAmount - 1, + 'Repo was deleted'); }) // add new repo .clickByCssSelector('.btn-add-repo') .then(function() { - return self.remote.assertElementsExist('.repos .form-inline', repoAmount, 'New repo placeholder was added'); + return self.remote.assertElementsExist('.repos .form-inline', repoAmount, + 'New repo placeholder was added'); }) - .assertElementExists('.repos .form-inline .repo-name.has-error', 'Empty repo marked as invalid') + .assertElementExists('.repos .form-inline .repo-name.has-error', + 'Empty repo marked as invalid') // revert the change .clickByCssSelector('.btn-revert-changes'); } diff --git a/static/tests/functional/test_equipment_page.js b/static/tests/functional/test_equipment_page.js index bcecf9686..700a1001c 100644 --- a/static/tests/functional/test_equipment_page.js +++ b/static/tests/functional/test_equipment_page.js @@ -69,18 +69,25 @@ define([ 'Check action buttons': function() { return this.remote .assertElementNotExists('.node .btn-discard', 'No discard changes button on a node') - .assertElementExists('.node.offline .node-remove-button', 'Removing of offline nodes is available on the page') + .assertElementExists('.node.offline .node-remove-button', + 'Removing of offline nodes is available on the page') .clickByCssSelector('.node.pending_addition > label') - .assertElementNotExists('.control-buttons-box .btn', 'No management buttons for selected node') - .assertElementExists('.node-list-management-buttons .btn-labels:not(:disabled)', 'Nodes can be labelled on the page') - .assertElementsExist('.node.pending_addition .btn-view-logs', 4, 'View logs button is presented for assigned to any environment nodes') - .assertElementNotExists('.node:not(.pending_addition) .btn-view-logs', 'View logs button is not presented for unallocated nodes') + .assertElementNotExists('.control-buttons-box .btn', + 'No management buttons for selected node') + .assertElementExists('.node-list-management-buttons .btn-labels:not(:disabled)', + 'Nodes can be labelled on the page') + .assertElementsExist('.node.pending_addition .btn-view-logs', 4, + 'View logs button is presented for assigned to any environment nodes') + .assertElementNotExists('.node:not(.pending_addition) .btn-view-logs', + 'View logs button is not presented for unallocated nodes') .clickByCssSelector('.node .node-settings') .then(function() { return modal.waitToOpen(); }) - .assertElementNotExists('.btn-edit-disks', 'No disks configuration buttons in node pop-up') - .assertElementNotExists('.btn-edit-networks', 'No interfaces configuration buttons in node pop-up') + .assertElementNotExists('.btn-edit-disks', + 'No disks configuration buttons in node pop-up') + .assertElementNotExists('.btn-edit-networks', + 'No interfaces configuration buttons in node pop-up') .then(function() { return modal.close(); }) @@ -88,7 +95,8 @@ define([ .then(function() { return node.openCompactNodeExtendedView(); }) - .assertElementNotExists('.node-popover .node-buttons .btn:not(.btn-view-logs)', 'No action buttons in node extended view in compact mode'); + .assertElementNotExists('.node-popover .node-buttons .btn:not(.btn-view-logs)', + 'No action buttons in node extended view in compact mode'); } }; }); diff --git a/static/tests/functional/test_login_logout.js b/static/tests/functional/test_login_logout.js index 4789a2f9e..4873b5bc0 100644 --- a/static/tests/functional/test_login_logout.js +++ b/static/tests/functional/test_login_logout.js @@ -42,14 +42,16 @@ define([ .then(function() { return loginPage.login('login', '*****'); }) - .assertElementAppears('div.login-error', 1000, 'Error message is expected to get displayed'); + .assertElementAppears('div.login-error', 1000, + 'Error message is expected to get displayed'); }, 'Login with proper credentials': function() { return this.remote .then(function() { return loginPage.login(); }) - .assertElementDisappears('.login-btn', 2000, 'Login button disappears after successful login'); + .assertElementDisappears('.login-btn', 2000, + 'Login button disappears after successful login'); } }; }); diff --git a/static/tests/functional/test_node_disk.js b/static/tests/functional/test_node_disk.js index c5bac48b1..f933ee9bb 100644 --- a/static/tests/functional/test_node_disk.js +++ b/static/tests/functional/test_node_disk.js @@ -88,9 +88,13 @@ define([ }); }) .end() - .assertElementExists(sdaDisk + ' .disk-visual [data-volume=image] .close-btn', 'Button Close for Image Storage volume is present') - .assertElementNotExists(sdaDisk + ' .disk-visual [data-volume=os] .close-btn', 'Button Close for Base system volume is not present') - .assertElementExists(sdaDisk + ' .disk-details [data-volume=os] .volume-group-notice.text-info', 'Notice about "Minimal size" is present'); + .assertElementExists(sdaDisk + ' .disk-visual [data-volume=image] .close-btn', + 'Button Close for Image Storage volume is present') + .assertElementNotExists(sdaDisk + ' .disk-visual [data-volume=os] .close-btn', + 'Button Close for Base system volume is not present') + .assertElementExists(sdaDisk + + ' .disk-details [data-volume=os] .volume-group-notice.text-info', + 'Notice about "Minimal size" is present'); }, 'Testing Apply and Load Defaults buttons behaviour': function() { return this.remote @@ -101,7 +105,8 @@ define([ .assertElementDisappears('.btn-load-defaults:disabled', 2000, 'Wait for changes applied') .clickByCssSelector(loadDefaultsButtonSelector) .assertElementDisappears('.btn-load-defaults:disabled', 2000, 'Wait for defaults loaded') - .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', initialImageSize, 'Image Storage size restored to default') + .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', + initialImageSize, 'Image Storage size restored to default') .assertElementEnabled(cancelButtonSelector, 'Cancel button is enabled') .assertElementEnabled(applyButtonSelector, 'Apply button is enabled') .clickByCssSelector(applyButtonSelector); @@ -113,7 +118,8 @@ define([ .then(function(element) { return element.getSize() .then(function(sizes) { - assert.isTrue(sizes.width > 0, 'Expected positive width for Image Storage visual'); + assert.isTrue(sizes.width > 0, + 'Expected positive width for Image Storage visual'); }); }) .end() @@ -128,18 +134,21 @@ define([ }); }) .end() - .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', 0, 'Image Storage volume was removed successfully') + .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', 0, + 'Image Storage volume was removed successfully') .findByCssSelector(sdaDisk + ' .disk-visual [data-volume=unallocated]') // check that there is unallocated space after Image Storage removal .then(function(element) { return element.getSize() .then(function(sizes) { - assert.isTrue(sizes.width > 0, 'There is unallocated space after Image Storage removal'); + assert.isTrue(sizes.width > 0, + 'There is unallocated space after Image Storage removal'); }); }) .end() .clickByCssSelector(cancelButtonSelector) - .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', initialImageSize, 'Image Storage volume control contains correct value') + .assertElementPropertyEquals(sdaDisk + ' input[type=number][name=image]', 'value', + initialImageSize, 'Image Storage volume control contains correct value') .assertElementDisabled(applyButtonSelector, 'Apply button is disabled'); }, 'Test volume size validation': function() { @@ -148,8 +157,11 @@ define([ .setInputValue(sdaDisk + ' input[type=number][name=image]', '5') // set Base OS volume size lower than required .setInputValue(sdaDisk + ' input[type=number][name=os]', '5') - .assertElementExists(sdaDisk + ' .disk-details [data-volume=os] .volume-group-notice.text-danger', 'Validation error exists if volume size is less than required.') - .assertElementDisabled(applyButtonSelector, 'Apply button is disabled in case of validation error') + .assertElementExists(sdaDisk + + ' .disk-details [data-volume=os] .volume-group-notice.text-danger', + 'Validation error exists if volume size is less than required.') + .assertElementDisabled(applyButtonSelector, + 'Apply button is disabled in case of validation error') .clickByCssSelector(cancelButtonSelector); } }; diff --git a/static/tests/functional/test_node_interfaces.js b/static/tests/functional/test_node_interfaces.js index 47d52aa6c..44039c824 100644 --- a/static/tests/functional/test_node_interfaces.js +++ b/static/tests/functional/test_node_interfaces.js @@ -68,7 +68,8 @@ define([ .then(function() { return interfacesPage.assignNetworkToInterface('Public', 'eth0'); }) - .assertElementExists('div.ifc-error', 'Untagged networks can not be assigned to the same interface message should appear'); + .assertElementExists('div.ifc-error', + 'Untagged networks can not be assigned to the same interface message should appear'); }, 'Bond interfaces with different speeds': function() { return this.remote @@ -78,7 +79,8 @@ define([ .then(function() { return interfacesPage.selectInterface('eth3'); }) - .assertElementExists('div.alert.alert-warning', 'Interfaces with different speeds bonding not recommended message should appear') + .assertElementExists('div.alert.alert-warning', + 'Interfaces with different speeds bonding not recommended message should appear') .assertElementEnabled('.btn-bond', 'Bonding button should still be enabled'); }, 'Interfaces bonding': function() { @@ -137,7 +139,9 @@ define([ return interfacesPage.selectInterface('bond1'); }) .assertElementDisabled('.btn-bond', 'Making sure bond button is disabled') - .assertElementContainsText('.alert.alert-warning', ' network interface is already bonded with other network interfaces.', 'Warning message should appear when intended to bond bonds'); + .assertElementContainsText('.alert.alert-warning', + ' network interface is already bonded with other network interfaces.', + 'Warning message should appear when intended to bond bonds'); } }; }); diff --git a/static/tests/functional/test_node_management_panel.js b/static/tests/functional/test_node_management_panel.js index 33afb6efc..a93edf745 100644 --- a/static/tests/functional/test_node_management_panel.js +++ b/static/tests/functional/test_node_management_panel.js @@ -50,10 +50,14 @@ define([ }, 'Test management controls state in new environment': function() { return this.remote - .assertElementDisabled(searchButtonSelector, 'Search button is locked if there are no nodes in environment') - .assertElementDisabled(sortingButtonSelector, 'Sorting button is locked if there are no nodes in environment') - .assertElementDisabled(filtersButtonSelector, 'Filters button is locked if there are no nodes in environment') - .assertElementNotExists('.active-sorters-filters', 'Applied sorters and filters are not shown for empty environment'); + .assertElementDisabled(searchButtonSelector, + 'Search button is locked if there are no nodes in environment') + .assertElementDisabled(sortingButtonSelector, + 'Sorting button is locked if there are no nodes in environment') + .assertElementDisabled(filtersButtonSelector, + 'Filters button is locked if there are no nodes in environment') + .assertElementNotExists('.active-sorters-filters', + 'Applied sorters and filters are not shown for empty environment'); }, 'Test management controls behaviour': { setup: function() { @@ -87,12 +91,15 @@ define([ .sleep(300) .assertElementsExist('.node-list .node', 3, 'Search was successfull') .clickByCssSelector('.page-title') - .assertElementNotExists(searchButtonSelector, 'Active search control remains open when clicking outside the input') + .assertElementNotExists(searchButtonSelector, + 'Active search control remains open when clicking outside the input') .clickByCssSelector('.node-management-panel .btn-clear-search') .assertElementsExist('.node-list .node', 4, 'Search was reset') - .assertElementNotExists(searchButtonSelector, 'Search input is still shown after search reset') + .assertElementNotExists(searchButtonSelector, + 'Search input is still shown after search reset') .clickByCssSelector('.node-list') - .assertElementExists(searchButtonSelector, 'Empty search control is closed when clicking outside the input'); + .assertElementExists(searchButtonSelector, + 'Empty search control is closed when clicking outside the input'); }, 'Test node list sorting': function() { var activeSortersPanelSelector = '.active-sorters'; @@ -100,13 +107,18 @@ define([ var firstNodeName; var self = this; return this.remote - .assertElementExists(activeSortersPanelSelector, 'Active sorters panel is shown if there are nodes in cluster') - .assertElementNotExists(activeSortersPanelSelector + '.btn-reset-sorting', 'Default sorting can not be reset from active sorters panel') + .assertElementExists(activeSortersPanelSelector, + 'Active sorters panel is shown if there are nodes in cluster') + .assertElementNotExists(activeSortersPanelSelector + '.btn-reset-sorting', + 'Default sorting can not be reset from active sorters panel') .clickByCssSelector(sortingButtonSelector) - .assertElementExists('.sorters .sorter-control', 'Cluster node list has one sorting by default') + .assertElementExists('.sorters .sorter-control', + 'Cluster node list has one sorting by default') .assertElementExists('.sorters .sort-by-roles-asc', 'Check default sorting by roles') - .assertElementNotExists('.sorters .sorter-control .btn-remove-sorting', 'Node list should have at least one applied sorting') - .assertElementNotExists('.sorters .btn-reset-sorting', 'Default sorting can not be reset') + .assertElementNotExists('.sorters .sorter-control .btn-remove-sorting', + 'Node list should have at least one applied sorting') + .assertElementNotExists('.sorters .btn-reset-sorting', + 'Default sorting can not be reset') .findByCssSelector('.node-list .node-name .name p') .getVisibleText().then(function(text) { firstNodeName = text; @@ -115,20 +127,24 @@ define([ .clickByCssSelector('.sorters .sort-by-roles-asc button') .findByCssSelector('.node-list .node-name .name p') .getVisibleText().then(function(text) { - assert.notEqual(text, firstNodeName, 'Order of sorting by roles was changed to desc'); + assert.notEqual(text, firstNodeName, + 'Order of sorting by roles was changed to desc'); }) .end() .clickByCssSelector('.sorters .sort-by-roles-desc button') .then(function() { - return self.remote.assertElementTextEquals('.node-list .node-name .name p', firstNodeName, 'Order of sorting by roles was changed to asc (default)'); + return self.remote.assertElementTextEquals('.node-list .node-name .name p', + firstNodeName, 'Order of sorting by roles was changed to asc (default)'); }) .clickByCssSelector(moreControlSelector + ' button') - .assertElementsExist(moreControlSelector + ' .popover .checkbox-group', 12, 'Standard node sorters are presented') + .assertElementsExist(moreControlSelector + ' .popover .checkbox-group', 12, + 'Standard node sorters are presented') // add sorting by CPU (real) .clickByCssSelector(moreControlSelector + ' .popover [name=cores]') // add sorting by manufacturer .clickByCssSelector(moreControlSelector + ' .popover [name=manufacturer]') - .assertElementsExist('.nodes-group', 4, 'New sorting was applied and nodes were grouped') + .assertElementsExist('.nodes-group', 4, + 'New sorting was applied and nodes were grouped') // remove sorting by manufacturer .clickByCssSelector('.sorters .sort-by-manufacturer-asc .btn-remove-sorting') .assertElementsExist('.nodes-group', 3, 'Particular sorting removal works') @@ -144,15 +160,20 @@ define([ var activeFiltersPanelSelector = '.active-filters'; var moreControlSelector = '.filters .more-control'; return this.remote - .assertElementNotExists(activeFiltersPanelSelector, 'Environment has no active filters by default') + .assertElementNotExists(activeFiltersPanelSelector, + 'Environment has no active filters by default') .clickByCssSelector(filtersButtonSelector) - .assertElementsExist('.filters .filter-control', 2, 'Filters panel has 2 default filters') + .assertElementsExist('.filters .filter-control', 2, + 'Filters panel has 2 default filters') .clickByCssSelector('.filter-by-roles') - .assertElementNotExists('.filter-by-roles [type=checkbox]:checked', 'There are no active options in Roles filter') - .assertElementNotExists('.filters .filter-control .btn-remove-filter', 'Default filters can not be deleted from filters panel') + .assertElementNotExists('.filter-by-roles [type=checkbox]:checked', + 'There are no active options in Roles filter') + .assertElementNotExists('.filters .filter-control .btn-remove-filter', + 'Default filters can not be deleted from filters panel') .assertElementNotExists('.filters .btn-reset-filters', 'No filters to be reset') .clickByCssSelector(moreControlSelector + ' button') - .assertElementsExist(moreControlSelector + ' .popover .checkbox-group', 8, 'Standard node filters are presented') + .assertElementsExist(moreControlSelector + ' .popover .checkbox-group', 8, + 'Standard node filters are presented') .clickByCssSelector(moreControlSelector + ' [name=cores]') .assertElementsExist('.filters .filter-control', 3, 'New Cores (real) filter was added') .assertElementExists('.filter-by-cores .popover-content', 'New filter is open') @@ -160,10 +181,13 @@ define([ .assertElementsExist('.filters .filter-control', 2, 'Particular filter removal works') .clickByCssSelector(moreControlSelector + ' button') .clickByCssSelector(moreControlSelector + ' [name=disks_amount]') - .assertElementsExist('.filters .filter-by-disks_amount input[type=number]:not(:disabled)', 2, 'Number filter has 2 fields to set min and max value') + .assertElementsExist('.filters ' + + '.filter-by-disks_amount input[type=number]:not(:disabled)', 2, + 'Number filter has 2 fields to set min and max value') // set min value more than max value .setInputValue('.filters .filter-by-disks_amount input[type=number][name=start]', '100') - .assertElementsAppear('.filters .filter-by-disks_amount .form-group.has-error', 2000, 'Validation works for Number range filter') + .assertElementsAppear('.filters .filter-by-disks_amount .form-group.has-error', 2000, + 'Validation works for Number range filter') .assertElementNotExists('.node-list .node', 'No nodes match invalid filter') .clickByCssSelector('.filters .btn-reset-filters') .assertElementsExist('.node-list .node', 4, 'Node filtration was successfully reset') @@ -173,8 +197,10 @@ define([ .clickByCssSelector('.filters .filter-by-status [name=pending_addition]') .assertElementsExist('.node-list .node', 4, 'All nodes shown') .clickByCssSelector(filtersButtonSelector) - .assertElementExists(activeFiltersPanelSelector, 'Applied filter is reflected in active filters panel') - .assertElementExists('.active-filters .btn-reset-filters', 'Reset filters button exists in active filters panel'); + .assertElementExists(activeFiltersPanelSelector, + 'Applied filter is reflected in active filters panel') + .assertElementExists('.active-filters .btn-reset-filters', + 'Reset filters button exists in active filters panel'); } } }; diff --git a/static/tests/functional/test_node_view.js b/static/tests/functional/test_node_view.js index 91433c062..c80cbff0d 100644 --- a/static/tests/functional/test_node_view.js +++ b/static/tests/functional/test_node_view.js @@ -57,7 +57,8 @@ define([ .clickByCssSelector('.node input[type=checkbox]') .assertElementExists('.node.selected', 'Node gets selected upon clicking') .assertElementExists('button.btn-delete-nodes:not(:disabled)', 'Delete Nodes and ...') - .assertElementExists('button.btn-edit-roles:not(:disabled)', '... Edit Roles buttons appear upon node selection') + .assertElementExists('button.btn-edit-roles:not(:disabled)', + '... Edit Roles buttons appear upon node selection') .then(function() { return node.renameNode(nodeNewName); }) @@ -82,9 +83,11 @@ define([ .then(function() { return node.openNodePopup(); }) - .assertElementTextEquals('.modal-header h4.modal-title', nodeNewName, 'Node pop-up has updated node name') + .assertElementTextEquals('.modal-header h4.modal-title', nodeNewName, + 'Node pop-up has updated node name') .assertElementExists('.modal .btn-edit-disks', 'Disks can be configured for cluster node') - .assertElementExists('.modal .btn-edit-networks', 'Interfaces can be configured for cluster node') + .assertElementExists('.modal .btn-edit-networks', + 'Interfaces can be configured for cluster node') .clickByCssSelector('.change-hostname .btn-link') // change the hostname .findByCssSelector('.change-hostname [type=text]') @@ -92,8 +95,10 @@ define([ .type(newHostname) .pressKeys('\uE007') .end() - .assertElementDisappears('.change-hostname [type=text]', 2000, 'Hostname input disappears after submit') - .assertElementTextEquals('span.node-hostname', newHostname, 'Node hostname has been updated') + .assertElementDisappears('.change-hostname [type=text]', 2000, + 'Hostname input disappears after submit') + .assertElementTextEquals('span.node-hostname', newHostname, + 'Node hostname has been updated') .then(function() { return modal.close(); }); @@ -107,8 +112,10 @@ define([ .assertElementExists('i.glyphicon-ok', 'Self node is selectable') .end() .clickByCssSelector('.compact-node .node-name p') - .assertElementNotExists('.compact-node .node-name-input', 'Node can not be renamed from compact panel') - .assertElementNotExists('.compact-node .role-list', 'Role list is not shown on node compact panel'); + .assertElementNotExists('.compact-node .node-name-input', + 'Node can not be renamed from compact panel') + .assertElementNotExists('.compact-node .role-list', + 'Role list is not shown on node compact panel'); }, 'Compact node extended view': function() { var newName = 'Node new new name'; @@ -117,7 +124,8 @@ define([ return node.openCompactNodeExtendedView(); }) .clickByCssSelector('.node-popover .node-name input[type=checkbox]') - .assertElementExists('.compact-node .node-checkbox i.glyphicon-ok', 'Node compact panel is checked') + .assertElementExists('.compact-node .node-checkbox i.glyphicon-ok', + 'Node compact panel is checked') .then(function() { return node.openNodePopup(true); }) @@ -131,12 +139,14 @@ define([ }) .findByCssSelector('.node-popover') .assertElementExists('.role-list', 'Role list is shown in cluster node extended view') - .assertElementExists('.node-buttons', 'Cluster node action buttons are presented in extended view') + .assertElementExists('.node-buttons', + 'Cluster node action buttons are presented in extended view') .end() .then(function() { return node.renameNode(newName, true); }) - .assertElementTextEquals('.node-popover .name p', newName, 'Node name has been updated from extended view') + .assertElementTextEquals('.node-popover .name p', newName, + 'Node name has been updated from extended view') .then(function() { return node.discardNode(true); }) @@ -152,13 +162,17 @@ define([ .then(function() { return node.openCompactNodeExtendedView(); }) - .assertElementNotExists('.node-popover .role-list', 'Unallocated node does not have roles assigned') - .assertElementNotExists('.node-popover .node-buttons .btn', 'There are no action buttons in unallocated node extended view') + .assertElementNotExists('.node-popover .role-list', + 'Unallocated node does not have roles assigned') + .assertElementNotExists('.node-popover .node-buttons .btn', + 'There are no action buttons in unallocated node extended view') .then(function() { return node.openNodePopup(true); }) - .assertElementNotExists('.modal .btn-edit-disks', 'Disks can not be configured for unallocated node') - .assertElementNotExists('.modal .btn-edit-networks', 'Interfaces can not be configured for unallocated node') + .assertElementNotExists('.modal .btn-edit-disks', + 'Disks can not be configured for unallocated node') + .assertElementNotExists('.modal .btn-edit-networks', + 'Interfaces can not be configured for unallocated node') .then(function() { return modal.close(); }); diff --git a/static/tests/functional/test_notifications.js b/static/tests/functional/test_notifications.js index e8f3c3d1f..82617b087 100644 --- a/static/tests/functional/test_notifications.js +++ b/static/tests/functional/test_notifications.js @@ -38,14 +38,18 @@ define([ }, 'Notification Page': function() { return this.remote - .assertElementDisplayed('.notifications-icon .badge', 'Badge notification indicator is shown in navigation') + .assertElementDisplayed('.notifications-icon .badge', + 'Badge notification indicator is shown in navigation') // Go to Notification page .clickByCssSelector('.notifications-icon') .clickLinkByText('View all') .assertElementAppears('.notifications-page', 2000, 'Notification page is rendered') - .assertElementExists('.notifications-page .notification', 'There is the start notification on the page') - .assertElementTextEquals('.notification-group .title', 'Today', 'Notification group has "Today" label') - .assertElementNotDisplayed('.notifications-icon .badge', 'Badge notification indicator is hidden'); + .assertElementExists('.notifications-page .notification', + 'There is the start notification on the page') + .assertElementTextEquals('.notification-group .title', 'Today', + 'Notification group has "Today" label') + .assertElementNotDisplayed('.notifications-icon .badge', + 'Badge notification indicator is hidden'); }, 'Notification badge behaviour': function() { var clusterName = common.pickRandomName('Test Cluster'); @@ -61,9 +65,11 @@ define([ .then(function() { return common.removeCluster(clusterName); }) - .assertElementAppears('.notifications-icon .badge.visible', 3000, 'New notification appear after the cluster removal') + .assertElementAppears('.notifications-icon .badge.visible', 3000, + 'New notification appear after the cluster removal') .clickByCssSelector('.notifications-icon') - .assertElementAppears('.notifications-popover .notification.clickable', 20000, 'Discovered node notification uploaded') + .assertElementAppears('.notifications-popover .notification.clickable', 20000, + 'Discovered node notification uploaded') // Check if Node Information dialog is shown .clickByCssSelector('.notifications-popover .notification.clickable p') .then(function() { diff --git a/static/tests/functional/test_plugins.js b/static/tests/functional/test_plugins.js index c1831fa4e..bfc6a3326 100644 --- a/static/tests/functional/test_plugins.js +++ b/static/tests/functional/test_plugins.js @@ -62,9 +62,12 @@ define([ var self = this; var zabbixInitialVersion, zabbixTextInputValue; return this.remote - .assertElementEnabled(zabbixSectionSelector + 'h3 input[type=checkbox]', 'Plugin is changeable') - .assertElementNotSelected(zabbixSectionSelector + 'h3 input[type=checkbox]', 'Plugin is not actvated') - .assertElementNotExists(zabbixSectionSelector + '> div input:not(:disabled)', 'Inactive plugin attributes can not be changes') + .assertElementEnabled(zabbixSectionSelector + 'h3 input[type=checkbox]', + 'Plugin is changeable') + .assertElementNotSelected(zabbixSectionSelector + 'h3 input[type=checkbox]', + 'Plugin is not actvated') + .assertElementNotExists(zabbixSectionSelector + '> div input:not(:disabled)', + 'Inactive plugin attributes can not be changes') // activate plugin .clickByCssSelector(zabbixSectionSelector + 'h3 input[type=checkbox]') // save changes @@ -85,9 +88,12 @@ define([ }) .end() // change plugin version - .clickByCssSelector(zabbixSectionSelector + '.plugin-versions input[type=radio]:not(:checked)') - .assertElementPropertyNotEquals(zabbixSectionSelector + '[name=zabbix_text_1]', 'value', zabbixTextInputValue, 'Plugin version was changed') - .assertElementExists('.subtab-link-other .glyphicon-danger-sign', 'Plugin atributes validation works') + .clickByCssSelector(zabbixSectionSelector + + '.plugin-versions input[type=radio]:not(:checked)') + .assertElementPropertyNotEquals(zabbixSectionSelector + '[name=zabbix_text_1]', 'value', + zabbixTextInputValue, 'Plugin version was changed') + .assertElementExists('.subtab-link-other .glyphicon-danger-sign', + 'Plugin atributes validation works') // fix validation error .setInputValue(zabbixSectionSelector + '[name=zabbix_text_with_regex]', 'aa-aa') .waitForElementDeletion('.subtab-link-other .glyphicon-danger-sign', 1000) @@ -95,7 +101,9 @@ define([ // reset plugin version change .clickByCssSelector('.btn-revert-changes') .then(function() { - return self.remote.assertElementPropertyEquals(zabbixSectionSelector + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, 'Plugin version change can be reset'); + return self.remote.assertElementPropertyEquals(zabbixSectionSelector + + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, + 'Plugin version change can be reset'); }); }, 'Check plugin in deployed environment': function() { @@ -124,8 +132,12 @@ define([ .end() // activate plugin .clickByCssSelector(zabbixSectionSelector + 'h3 input[type=checkbox]') - .assertElementExists(zabbixSectionSelector + '.plugin-versions input[type=radio]:not(:disabled)', 'Some plugin versions are hotluggable') - .assertElementPropertyNotEquals(zabbixSectionSelector + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, 'Plugin hotpluggable version is automatically chosen') + .assertElementExists(zabbixSectionSelector + + '.plugin-versions input[type=radio]:not(:disabled)', + 'Some plugin versions are hotluggable') + .assertElementPropertyNotEquals(zabbixSectionSelector + + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, + 'Plugin hotpluggable version is automatically chosen') // fix validation error .setInputValue(zabbixSectionSelector + '[name=zabbix_text_with_regex]', 'aa-aa') .waitForElementDeletion('.subtab-link-other .glyphicon-danger-sign', 1000) @@ -133,7 +145,9 @@ define([ // deactivate plugin .clickByCssSelector(zabbixSectionSelector + 'h3 input[type=checkbox]') .then(function() { - return self.remote.assertElementPropertyEquals(zabbixSectionSelector + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, 'Initial plugin version is set for deactivated plugin'); + return self.remote.assertElementPropertyEquals(zabbixSectionSelector + + '.plugin-versions input[type=radio]:checked', 'value', zabbixInitialVersion, + 'Initial plugin version is set for deactivated plugin'); }) .assertElementDisabled('.btn-apply-changes', 'The change as reset successfully'); }, @@ -144,12 +158,16 @@ define([ .clickByCssSelector(loggingSectionSelector + 'h3 input[type=checkbox]') // activate Zabbix plugin .clickByCssSelector(zabbixSectionSelector + 'h3 input[type=checkbox]') - .assertElementEnabled(loggingSectionSelector + '[name=logging_text]', 'No conflict with default Zabix plugin version') + .assertElementEnabled(loggingSectionSelector + '[name=logging_text]', + 'No conflict with default Zabix plugin version') // change Zabbix plugin version - .clickByCssSelector(zabbixSectionSelector + '.plugin-versions input[type=radio]:not(:checked)') - .assertElementNotSelected(zabbixSectionSelector + '[name=zabbix_checkbox]', 'Zabbix checkbox is not activated') + .clickByCssSelector(zabbixSectionSelector + + '.plugin-versions input[type=radio]:not(:checked)') + .assertElementNotSelected(zabbixSectionSelector + '[name=zabbix_checkbox]', + 'Zabbix checkbox is not activated') .clickByCssSelector(zabbixSectionSelector + '[name=zabbix_checkbox]') - .assertElementDisabled(loggingSectionSelector + '[name=logging_text]', 'Conflict with Zabbix checkbox') + .assertElementDisabled(loggingSectionSelector + '[name=logging_text]', + 'Conflict with Zabbix checkbox') // reset changes .clickByCssSelector('.btn-revert-changes'); } diff --git a/static/tests/functional/test_support_page.js b/static/tests/functional/test_support_page.js index 4be56dbb8..6877dd14f 100644 --- a/static/tests/functional/test_support_page.js +++ b/static/tests/functional/test_support_page.js @@ -48,7 +48,8 @@ define([ .assertElementExists('.capacity-audit', 'Capacity Audit block is present') .assertElementExists('.tracking', 'Statistics block is present') .assertElementSelected(sendStatisticsCheckbox, 'Save Staticstics checkbox is checked') - .assertElementDisabled(saveStatisticsSettingsButton, '"Save changes" button is disabled until statistics checkbox uncheck'); + .assertElementDisabled(saveStatisticsSettingsButton, + '"Save changes" button is disabled until statistics checkbox uncheck'); }, 'Diagnostic snapshot link generation': function() { return this.remote @@ -59,9 +60,12 @@ define([ return this.remote // Uncheck "Send usage statistics" checkbox .clickByCssSelector(sendStatisticsCheckbox) - .assertElementEnabled(saveStatisticsSettingsButton, '"Save changes" button is enabled after changing "Send usage statistics" checkbox value') + .assertElementEnabled(saveStatisticsSettingsButton, + '"Save changes" button is enabled after changing "Send usage statistics" ' + + 'checkbox value') .clickByCssSelector(saveStatisticsSettingsButton) - .assertElementDisabled(saveStatisticsSettingsButton, '"Save changes" button is disabled after saving changes'); + .assertElementDisabled(saveStatisticsSettingsButton, + '"Save changes" button is disabled after saving changes'); }, 'Discard changes': function() { return this.remote @@ -87,7 +91,8 @@ define([ .assertElementAppears('.clusters-page', 1000, 'Redirecting to Environments') // Go back to Support Page and ... .clickLinkByText('Support') - .assertElementSelected(sendStatisticsCheckbox, 'Changes saved successfully and save staticstics checkbox is checked') + .assertElementSelected(sendStatisticsCheckbox, + 'Changes saved successfully and save staticstics checkbox is checked') // Uncheck the "Send usage statistics" checkbox value .clickByCssSelector(sendStatisticsCheckbox) // Go to another page with not saved changes @@ -105,7 +110,8 @@ define([ .assertElementAppears('.clusters-page', 1000, 'Redirecting to Environments') // Go back to Support Page and ... .clickLinkByText('Support') - .assertElementSelected(sendStatisticsCheckbox, 'Changes was not saved and save staticstics checkbox is checked') + .assertElementSelected(sendStatisticsCheckbox, + 'Changes was not saved and save staticstics checkbox is checked') // Uncheck the "Send usage statistics" checkbox value .clickByCssSelector(sendStatisticsCheckbox) // Go to another page with not saved changes @@ -120,7 +126,8 @@ define([ .then(function() { return modal.waitToClose(); }) - .assertElementNotSelected(sendStatisticsCheckbox, 'We are still on the Support page, and checkbox is unchecked'); + .assertElementNotSelected(sendStatisticsCheckbox, + 'We are still on the Support page, and checkbox is unchecked'); } }; }); diff --git a/static/tests/functional/test_wizard.js b/static/tests/functional/test_wizard.js index ef8ce3d06..10f532d53 100644 --- a/static/tests/functional/test_wizard.js +++ b/static/tests/functional/test_wizard.js @@ -52,7 +52,8 @@ define([ }, 'Test steps manipulations': function() { return this.remote - .assertElementExists('.wizard-step.active', 'There is only one active and available step at the beginning') + .assertElementExists('.wizard-step.active', + 'There is only one active and available step at the beginning') // Compute .pressKeys('\uE007') // Network diff --git a/static/tests/unit/expression.js b/static/tests/unit/expression.js index 228bcf191..5840802c3 100644 --- a/static/tests/unit/expression.js +++ b/static/tests/unit/expression.js @@ -68,7 +68,8 @@ suite('Expression', () => { ['"unknown-role" in release:roles', false], ['settings:common.libvirt_type.value', hypervisor], ['settings:common.libvirt_type.value == "' + hypervisor + '"', true], - ['cluster:mode == "ha_compact" and not (settings:common.libvirt_type.value != "' + hypervisor + '")', true], + ['cluster:mode == "ha_compact" and not (settings:common.libvirt_type.value != "' + + hypervisor + '")', true], // test nonexistent keys ['cluster:nonexistentkey', Error], ['cluster:nonexistentkey == null', true, false], @@ -86,9 +87,11 @@ suite('Expression', () => { _.each(testCases, ([expression, result, strict]) => { var options = {strict}; if (result === Error) { - assert.throws(_.partial(evaluate, expression, options), Error, '', expression + ' throws an error'); + assert.throws(_.partial(evaluate, expression, options), Error, '', + expression + ' throws an error'); } else { - assert.strictEqual(evaluate(expression, options), result, expression + ' evaluates correctly'); + assert.strictEqual(evaluate(expression, options), result, + expression + ' evaluates correctly'); } }); }); diff --git a/static/tests/unit/file_control.js b/static/tests/unit/file_control.js index 54c5e175f..bb4e310e0 100644 --- a/static/tests/unit/file_control.js +++ b/static/tests/unit/file_control.js @@ -36,7 +36,8 @@ suite('File Control', () => { var initialState = input.getInitialState(); assert.equal(input.props.type, 'file', 'Input type should be equal to file'); - assert.equal(initialState.fileName, 'certificate.crt', 'Default file name must correspond to provided one'); + assert.equal(initialState.fileName, 'certificate.crt', + 'Default file name must correspond to provided one'); assert.equal(initialState.content, 'CERTIFICATE', 'Content should be equal to the default'); }); @@ -48,7 +49,8 @@ suite('File Control', () => { }); input.pickFile(); - assert.ok(clickSpy.calledOnce, 'When icon clicked input control should be clicked too to open select file dialog'); + assert.ok(clickSpy.calledOnce, + 'When icon clicked input control should be clicked too to open select file dialog'); }); test('File fetching', () => { diff --git a/static/tests/unit/models.js b/static/tests/unit/models.js index 30c5ec383..0eb08e47d 100644 --- a/static/tests/unit/models.js +++ b/static/tests/unit/models.js @@ -24,39 +24,48 @@ suite('Test models', () => { filters = {status: []}; result = ['running', 'pending', 'ready', 'error']; - assert.deepEqual(task.extendStatuses(filters), result, 'All task statuses are acceptable if "status" filter not specified'); + assert.deepEqual(task.extendStatuses(filters), result, + 'All task statuses are acceptable if "status" filter not specified'); filters = {status: 'ready'}; result = ['ready']; - assert.deepEqual(task.extendStatuses(filters), result, '"status" filter can have string as a value'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" filter can have string as a value'); filters = {status: ['ready', 'running']}; result = ['ready', 'running']; - assert.deepEqual(task.extendStatuses(filters), result, '"status" filter can have list of strings as a value'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" filter can have list of strings as a value'); filters = {status: ['ready'], active: true}; result = []; - assert.deepEqual(task.extendStatuses(filters), result, '"status" and "active" filters are not intersected'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" and "active" filters are not intersected'); filters = {status: ['running'], active: true}; result = ['running']; - assert.deepEqual(task.extendStatuses(filters), result, '"status" and "active" filters have intersection'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" and "active" filters have intersection'); filters = {status: ['running'], active: false}; result = []; - assert.deepEqual(task.extendStatuses(filters), result, '"status" and "active" filters are not intersected'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" and "active" filters are not intersected'); filters = {status: ['ready', 'running'], active: false}; result = ['ready']; - assert.deepEqual(task.extendStatuses(filters), result, '"status" and "active" filters have intersection'); + assert.deepEqual(task.extendStatuses(filters), result, + '"status" and "active" filters have intersection'); filters = {active: true}; result = ['running', 'pending']; - assert.deepEqual(task.extendStatuses(filters), result, 'True value of "active" filter parsed correctly'); + assert.deepEqual(task.extendStatuses(filters), result, + 'True value of "active" filter parsed correctly'); filters = {active: false}; result = ['ready', 'error']; - assert.deepEqual(task.extendStatuses(filters), result, 'False value of \'active\' filter parsed correctly'); + assert.deepEqual(task.extendStatuses(filters), result, + 'False value of \'active\' filter parsed correctly'); }); test('Test extendGroups method', () => { @@ -66,39 +75,48 @@ suite('Test models', () => { filters = {name: []}; result = allTaskNames; - assert.deepEqual(task.extendGroups(filters), result, 'All task names are acceptable if "name" filter not specified'); + assert.deepEqual(task.extendGroups(filters), result, + 'All task names are acceptable if "name" filter not specified'); filters = {group: []}; result = allTaskNames; - assert.deepEqual(task.extendGroups(filters), result, 'All task names are acceptable if "group" filter not specified'); + assert.deepEqual(task.extendGroups(filters), result, + 'All task names are acceptable if "group" filter not specified'); filters = {name: 'deploy'}; result = ['deploy']; - assert.deepEqual(task.extendGroups(filters), result, '"name" filter can have string as a value'); + assert.deepEqual(task.extendGroups(filters), result, + '"name" filter can have string as a value'); filters = {name: 'dump'}; result = ['dump']; - assert.deepEqual(task.extendGroups(filters), result, 'Tasks, that are not related to any task group, handled properly'); + assert.deepEqual(task.extendGroups(filters), result, + 'Tasks, that are not related to any task group, handled properly'); filters = {name: ['deploy', 'check_networks']}; result = ['deploy', 'check_networks']; - assert.deepEqual(task.extendGroups(filters), result, '"name" filter can have list of strings as a value'); + assert.deepEqual(task.extendGroups(filters), result, + '"name" filter can have list of strings as a value'); filters = {group: 'deployment'}; result = task.groups.deployment; - assert.deepEqual(task.extendGroups(filters), result, '"group" filter can have string as a value'); + assert.deepEqual(task.extendGroups(filters), result, + '"group" filter can have string as a value'); filters = {group: ['deployment', 'network']}; result = allTaskNames; - assert.deepEqual(task.extendGroups(filters), result, '"group" filter can have list of strings as a value'); + assert.deepEqual(task.extendGroups(filters), result, + '"group" filter can have list of strings as a value'); filters = {name: 'deploy', group: 'deployment'}; result = ['deploy']; - assert.deepEqual(task.extendGroups(filters), result, '"name" and "group" filters have intersection'); + assert.deepEqual(task.extendGroups(filters), result, + '"name" and "group" filters have intersection'); filters = {name: 'deploy', group: 'network'}; result = []; - assert.deepEqual(task.extendGroups(filters), result, '"name" and "group" filters are not intersected'); + assert.deepEqual(task.extendGroups(filters), result, + '"name" and "group" filters are not intersected'); }); }); }); diff --git a/static/tests/unit/node_interfaces_offloading_modes.js b/static/tests/unit/node_interfaces_offloading_modes.js index 527b5dee0..1f1c8d77b 100644 --- a/static/tests/unit/node_interfaces_offloading_modes.js +++ b/static/tests/unit/node_interfaces_offloading_modes.js @@ -13,17 +13,20 @@ * License for the specific language governing permissions and limitations * under the License. **/ -import OffloadingModes from 'views/cluster_page_tabs/nodes_tab_screens/offloading_modes_control'; +import OffloadingModes from + 'views/cluster_page_tabs/nodes_tab_screens/offloading_modes_control'; var offloadingModesConrol, TestMode22, TestMode31, fakeOffloadingModes; var fakeInterface = { offloading_modes: fakeOffloadingModes, get(key) { - assert.equal(key, 'offloading_modes', '"offloading_modes" interface property should be used to get data'); + assert.equal(key, 'offloading_modes', + '"offloading_modes" interface property should be used to get data'); return fakeOffloadingModes; }, set(key, value) { - assert.equal(key, 'offloading_modes', '"offloading_modes" interface property should be used to set data'); + assert.equal(key, 'offloading_modes', + '"offloading_modes" interface property should be used to set data'); fakeOffloadingModes = value; } }; @@ -70,18 +73,21 @@ suite('Offloadning Modes control', () => { test('Set submodes states logic', () => { var mode = offloadingModesConrol.findMode('TestName1', fakeOffloadingModes); offloadingModesConrol.setModeState(mode, false); - assert.strictEqual(TestMode31.state, false, 'Parent state changing leads to all child modes states changing'); + assert.strictEqual(TestMode31.state, false, + 'Parent state changing leads to all child modes states changing'); }); test('Disabled reversed logic', () => { var mode = offloadingModesConrol.findMode('TestName2', fakeOffloadingModes); offloadingModesConrol.setModeState(TestMode22, true); offloadingModesConrol.checkModes(null, fakeOffloadingModes); - assert.strictEqual(mode.state, null, 'Parent state changing leads to all child modes states changing'); + assert.strictEqual(mode.state, null, + 'Parent state changing leads to all child modes states changing'); }); test('All Modes option logic', () => { var enableAllModes = offloadingModesConrol.onModeStateChange('All Modes', true); enableAllModes(); var mode = offloadingModesConrol.findMode('TestName2', fakeOffloadingModes); - assert.strictEqual(mode.state, true, 'All Modes option state changing leads to all parent modes states changing'); + assert.strictEqual(mode.state, true, + 'All Modes option state changing leads to all parent modes states changing'); }); }); diff --git a/static/tests/unit/utils.js b/static/tests/unit/utils.js index 3684d39af..c8e05e67d 100644 --- a/static/tests/unit/utils.js +++ b/static/tests/unit/utils.js @@ -25,19 +25,24 @@ suite('Test utils', () => { var serverUnavailableMessage = i18n('dialog.error_dialog.server_unavailable'); response = {status: 500, responseText: 'Server error occured'}; - assert.equal(getResponseText(response), serverErrorMessage, 'HTTP 500 is treated as a server error'); + assert.equal(getResponseText(response), serverErrorMessage, + 'HTTP 500 is treated as a server error'); response = {status: 502, responseText: 'Bad gateway'}; - assert.equal(getResponseText(response), serverUnavailableMessage, 'HTTP 502 is treated as server unavailability'); + assert.equal(getResponseText(response), serverUnavailableMessage, + 'HTTP 502 is treated as server unavailability'); response = {status: 0, responseText: 'error'}; - assert.equal(getResponseText(response), serverUnavailableMessage, 'XHR object with no status is treated as server unavailability'); + assert.equal(getResponseText(response), serverUnavailableMessage, + 'XHR object with no status is treated as server unavailability'); response = {status: 400, responseText: 'Bad request'}; - assert.equal(getResponseText(response), serverErrorMessage, 'HTTP 400 with plain text response is treated as a server error'); + assert.equal(getResponseText(response), serverErrorMessage, + 'HTTP 400 with plain text response is treated as a server error'); response = {status: 400, responseText: JSON.stringify({message: '123'})}; - assert.equal(getResponseText(response), '123', 'HTTP 400 with JSON response is treated correctly'); + assert.equal(getResponseText(response), '123', + 'HTTP 400 with JSON response is treated correctly'); }); test('Test comparison', () => { @@ -67,15 +72,20 @@ suite('Test utils', () => { assert.equal(compare(model1, model1, {attr: 'number'}), 0, 'Number comparison a=b'); - assert.equal(compare(model1, model2, {attr: 'boolean'}), -1, 'Boolean comparison true and false'); + assert.equal(compare(model1, model2, {attr: 'boolean'}), -1, + 'Boolean comparison true and false'); - assert.equal(compare(model2, model1, {attr: 'boolean'}), 1, 'Boolean comparison false and true'); + assert.equal(compare(model2, model1, {attr: 'boolean'}), 1, + 'Boolean comparison false and true'); - assert.equal(compare(model1, model1, {attr: 'boolean'}), 0, 'Boolean comparison true and true'); + assert.equal(compare(model1, model1, {attr: 'boolean'}), 0, + 'Boolean comparison true and true'); - assert.equal(compare(model2, model2, {attr: 'boolean'}), 0, 'Boolean comparison false and false'); + assert.equal(compare(model2, model2, {attr: 'boolean'}), 0, + 'Boolean comparison false and false'); - assert.equal(compare(model1, model2, {attr: 'booleanFlagWithNull'}), 0, 'Comparison null and false'); + assert.equal(compare(model1, model2, {attr: 'booleanFlagWithNull'}), 0, + 'Comparison null and false'); }); test('Test highlightTestStep', () => { @@ -136,17 +146,22 @@ suite('Test utils', () => { assert.equal(getGateway('172.16.0.0/24'), '172.16.0.1', 'Getting default gateway for CIDR'); assert.equal(getGateway('192.168.0.0/10'), '192.128.0.1', 'Getting default gateway for CIDR'); - assert.equal(getGateway('172.16.0.0/31'), '', 'No gateway returned for inappropriate CIDR (network is too small)'); + assert.equal(getGateway('172.16.0.0/31'), '', + 'No gateway returned for inappropriate CIDR (network is too small)'); assert.equal(getGateway('172.16.0.0/'), '', 'No gateway returned for invalid CIDR'); }); test('Test getDefaultIPRangeForCidr', () => { var getRange = utils.getDefaultIPRangeForCidr; - assert.deepEqual(getRange('172.16.0.0/24'), [['172.16.0.1', '172.16.0.254']], 'Getting default IP range for CIDR'); - assert.deepEqual(getRange('192.168.0.0/10', true), [['192.128.0.2', '192.191.255.254']], 'Gateway address excluded from default IP range'); - assert.deepEqual(getRange('172.16.0.0/31'), [['', '']], 'No IP range returned for inappropriate CIDR (network is too small)'); - assert.deepEqual(getRange('172.16.0.0/', true), [['', '']], 'No IP range returned for invalid CIDR'); + assert.deepEqual(getRange('172.16.0.0/24'), [['172.16.0.1', '172.16.0.254']], + 'Getting default IP range for CIDR'); + assert.deepEqual(getRange('192.168.0.0/10', true), [['192.128.0.2', '192.191.255.254']], + 'Gateway address excluded from default IP range'); + assert.deepEqual(getRange('172.16.0.0/31'), [['', '']], + 'No IP range returned for inappropriate CIDR (network is too small)'); + assert.deepEqual(getRange('172.16.0.0/', true), [['', '']], + 'No IP range returned for invalid CIDR'); }); test('Test validateIpCorrespondsToCIDR', () => { @@ -156,6 +171,7 @@ suite('Test utils', () => { assert.ok(validate('172.16.0.5/24', '172.16.0.2'), 'Check IP, that corresponds to CIDR'); assert.notOk(validate('172.16.0.0/20', '172.16.15.255'), 'Check broadcast address'); assert.notOk(validate('172.16.0.0/20', '172.16.0.0'), 'Check network address'); - assert.notOk(validate('192.168.0.0/10', '192.231.255.254'), 'Check IP, that does not correspond to CIDR'); + assert.notOk(validate('192.168.0.0/10', '192.231.255.254'), + 'Check IP, that does not correspond to CIDR'); }); }); diff --git a/static/utils.js b/static/utils.js index b3b4862fc..edde63eec 100644 --- a/static/utils.js +++ b/static/utils.js @@ -26,12 +26,14 @@ import {ErrorDialog} from 'views/dialogs'; import models from 'models'; var utils = { + /*eslint-disable max-len*/ regexes: { url: /(?:https?:\/\/([\-\w\.]+)+(:\d+)?(\/([\w\/_\-\.]*(\?[\w\/_\-\.&%]*)?(#[\w\/_\-\.&%]*)?)?)?)/, ip: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/, mac: /^([0-9a-f]{1,2}[\.:-]){5}([0-9a-f]{1,2})$/, cidr: /^(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([1-9]|[1-2]\d|3[0-2])$/ }, + /*eslint-enable max-len*/ serializeTabOptions(options) { return _.map(options, (value, key) => key + ':' + value).join(';'); }, @@ -55,14 +57,16 @@ var utils = { return '' + url + ''; }, urlify(text) { - return utils.linebreaks(text).replace(new RegExp(utils.regexes.url.source, 'g'), utils.composeLink); + return utils.linebreaks(text).replace(new RegExp(utils.regexes.url.source, 'g'), + utils.composeLink); }, composeList(value) { return _.isUndefined(value) ? [] : _.isArray(value) ? value : [value]; }, // FIXME(vkramskikh): moved here from healthcheck_tab to make testable highlightTestStep(text, step) { - return text.replace(new RegExp('(^|\\s*)(' + step + '\\.[\\s\\S]*?)(\\s*\\d+\\.|$)'), '$1$2$3'); + return text.replace(new RegExp('(^|\\s*)(' + step + '\\.[\\s\\S]*?)(\\s*\\d+\\.|$)'), + '$1$2$3'); }, classNames: classNames, parseModelPath(path, models) { @@ -129,7 +133,8 @@ var utils = { break; } } - return (result ? result.toFixed(1) : result) + ' ' + i18n('common.size.' + unit, {count: result}); + return (result ? result.toFixed(1) : result) + ' ' + i18n('common.size.' + unit, + {count: result}); }, showMemorySize(bytes) { return utils.showSize(bytes, 1024); @@ -142,7 +147,8 @@ var utils = { return Math.pow(2, 32 - parseInt(_.last(cidr.split('/')), 10)); }, formatNumber(n) { - return String(n).replace(/\d/g, (c, i, a) => i > 0 && c !== '.' && (a.length - i) % 3 === 0 ? ',' + c : c); + return String(n).replace(/\d/g, (c, i, a) => i > 0 && c !== '.' && + (a.length - i) % 3 === 0 ? ',' + c : c); }, floor(n, decimals) { return Math.floor(n * Math.pow(10, decimals)) / Math.pow(10, decimals); @@ -152,7 +158,8 @@ var utils = { }, validateVlan(vlan, forbiddenVlans, field, disallowNullValue) { var error = {}; - if ((_.isNull(vlan) && disallowNullValue) || (!_.isNull(vlan) && (!utils.isNaturalNumber(vlan) || vlan < 1 || vlan > 4094))) { + if ((_.isNull(vlan) && disallowNullValue) || (!_.isNull(vlan) && + (!utils.isNaturalNumber(vlan) || vlan < 1 || vlan > 4094))) { error[field] = i18n('cluster_page.network_tab.validation.invalid_vlan'); return error; } @@ -218,7 +225,8 @@ var utils = { } else if (existingRanges.length) { var intersection = utils.checkIPRangesIntersection(range, existingRanges); if (intersection) { - error.start = error.end = warnings.IP_RANGES_INTERSECTION + intersection.join(' - '); + error.start = error.end = warnings.IP_RANGES_INTERSECTION + + intersection.join(' - '); } } } @@ -240,13 +248,16 @@ var utils = { checkIPRangesIntersection([startIP, endIP], existingRanges) { var startIPInt = IP.toLong(startIP); var endIPInt = IP.toLong(endIP); - return _.find(existingRanges, ([ip1, ip2]) => IP.toLong(ip2) >= startIPInt && IP.toLong(ip1) <= endIPInt); + return _.find(existingRanges, ([ip1, ip2]) => { + return IP.toLong(ip2) >= startIPInt && IP.toLong(ip1) <= endIPInt; + }); }, validateIpCorrespondsToCIDR(cidr, ip) { if (!cidr) return true; var networkData = IP.cidrSubnet(cidr); var ipInt = IP.toLong(ip); - return ipInt >= IP.toLong(networkData.firstAddress) && ipInt <= IP.toLong(networkData.lastAddress); + return ipInt >= IP.toLong(networkData.firstAddress) && + ipInt <= IP.toLong(networkData.lastAddress); }, validateVlanRange(vlanStart, vlanEnd, vlan) { return vlan >= vlanStart && vlan <= vlanEnd; diff --git a/static/views/cluster_page.js b/static/views/cluster_page.js index 3481e460b..206c635ba 100644 --- a/static/views/cluster_page.js +++ b/static/views/cluster_page.js @@ -62,10 +62,15 @@ var ClusterPage = React.createClass({ ['home', '#'], ['environments', '#clusters'], [cluster.get('name'), '#cluster/' + cluster.get('id'), {skipTranslation: true}], - [i18n('cluster_page.tabs.' + pageOptions.activeTab), '#cluster/' + cluster.get('id') + '/' + pageOptions.activeTab, {active: !addScreenBreadcrumb}] + [ + i18n('cluster_page.tabs.' + pageOptions.activeTab), + '#cluster/' + cluster.get('id') + '/' + pageOptions.activeTab, + {active: !addScreenBreadcrumb} + ] ]; if (addScreenBreadcrumb) { - breadcrumbs.push([i18n('cluster_page.nodes_tab.breadcrumbs.' + tabOptions), null, {active: true}]); + breadcrumbs.push([i18n('cluster_page.nodes_tab.breadcrumbs.' + tabOptions), null, + {active: true}]); } return breadcrumbs; }, @@ -94,7 +99,8 @@ var ClusterPage = React.createClass({ if (currentClusterId == id) { // just another tab has been chosen, do not load cluster again cluster = app.page.props.cluster; - promise = tab.fetchData ? tab.fetchData({cluster: cluster, tabOptions: tabOptions}) : $.Deferred().resolve(); + promise = tab.fetchData ? tab.fetchData({cluster: cluster, tabOptions: tabOptions}) : + $.Deferred().resolve(); } else { cluster = new models.Cluster({id: id}); @@ -111,7 +117,8 @@ var ClusterPage = React.createClass({ cluster.set({pluginLinks: pluginLinks}); cluster.get('nodes').fetch = function(options) { - return this.constructor.__super__.fetch.call(this, _.extend({data: {cluster_id: id}}, options)); + return this.constructor.__super__.fetch.call(this, + _.extend({data: {cluster_id: id}}, options)); }; promise = $.when( cluster.fetch(), @@ -124,12 +131,16 @@ var ClusterPage = React.createClass({ ) .then(() => { var networkConfiguration = new models.NetworkConfiguration(); - networkConfiguration.url = _.result(cluster, 'url') + '/network_configuration/' + cluster.get('net_provider'); + networkConfiguration.url = _.result(cluster, 'url') + '/network_configuration/' + + cluster.get('net_provider'); cluster.set({ networkConfiguration: networkConfiguration, release: new models.Release({id: cluster.get('release_id')}) }); - return $.when(cluster.get('networkConfiguration').fetch(), cluster.get('release').fetch()); + return $.when( + cluster.get('networkConfiguration').fetch(), + cluster.get('release').fetch() + ); }) .then(() => { var useVcenter = cluster.get('settings').get('common.use_vcenter.value'); @@ -141,7 +152,8 @@ var ClusterPage = React.createClass({ return vcenter.fetch(); }) .then(() => { - return tab.fetchData ? tab.fetchData({cluster: cluster, tabOptions: tabOptions}) : $.Deferred().resolve(); + return tab.fetchData ? tab.fetchData({cluster: cluster, tabOptions: tabOptions}) : + $.Deferred().resolve(); }); } return promise.then((data) => { @@ -232,7 +244,8 @@ var ClusterPage = React.createClass({ var selectedLogs; if (props.tabOptions[0]) { selectedLogs = utils.deserializeTabOptions(_.compact(props.tabOptions).join('/')); - selectedLogs.level = selectedLogs.level ? selectedLogs.level.toUpperCase() : props.defaultLogLevel; + selectedLogs.level = selectedLogs.level ? selectedLogs.level.toUpperCase() : + props.defaultLogLevel; this.setState({selectedLogs: selectedLogs}); } } @@ -283,7 +296,11 @@ var ClusterPage = React.createClass({

{cluster.get('name')} -
({i18n('common.node', {count: cluster.get('nodes').length})})
+
+ ({i18n('common.node', {count: cluster.get('nodes').length})}) +

@@ -292,7 +309,12 @@ var ClusterPage = React.createClass({ return (
diff --git a/static/views/cluster_page_tabs/dashboard_tab.js b/static/views/cluster_page_tabs/dashboard_tab.js index e63673166..1d241562d 100644 --- a/static/views/cluster_page_tabs/dashboard_tab.js +++ b/static/views/cluster_page_tabs/dashboard_tab.js @@ -21,14 +21,18 @@ import ReactDOM from 'react-dom'; import utils from 'utils'; import dispatcher from 'dispatcher'; import {Input, ProgressBar, Tooltip} from 'views/controls'; -import {DiscardNodeChangesDialog, DeployChangesDialog, ProvisionVMsDialog, RemoveClusterDialog, ResetEnvironmentDialog, StopDeploymentDialog} from 'views/dialogs'; +import { + DiscardNodeChangesDialog, DeployChangesDialog, ProvisionVMsDialog, + RemoveClusterDialog, ResetEnvironmentDialog, StopDeploymentDialog +} from 'views/dialogs'; import {backboneMixin, pollingMixin, renamingMixin} from 'component_mixins'; var namespace = 'cluster_page.dashboard_tab.'; var DashboardTab = React.createClass({ mixins: [ - // this is needed to somehow handle the case when verification is in progress and user pressed Deploy + // this is needed to somehow handle the case when verification + // is in progress and user pressed Deploy backboneMixin({ modelOrCollection: (props) => props.cluster.get('tasks'), renderOn: 'update change' @@ -254,9 +258,13 @@ var DeploymentResult = React.createClass({
-
+          
           
         
@@ -288,14 +296,29 @@ var DocumentationLinks = React.createClass({
{isMirantisIso ? [ - this.renderDocumentationLinks('https://www.mirantis.com/openstack-documentation/', 'mos_documentation'), - this.renderDocumentationLinks(utils.composeDocumentationLink('plugin-dev.html#plugin-dev'), 'plugin_documentation'), - this.renderDocumentationLinks('https://software.mirantis.com/mirantis-openstack-technical-bulletins/', 'technical_bulletins') + this.renderDocumentationLinks( + 'https://www.mirantis.com/openstack-documentation/', + 'mos_documentation' + ), + this.renderDocumentationLinks( + utils.composeDocumentationLink('plugin-dev.html#plugin-dev'), + 'plugin_documentation' + ), + this.renderDocumentationLinks( + 'https://software.mirantis.com/mirantis-openstack-technical-bulletins/', + 'technical_bulletins' + ) ] : [ - this.renderDocumentationLinks('http://docs.openstack.org/', 'openstack_documentation'), - this.renderDocumentationLinks('https://wiki.openstack.org/wiki/Fuel/Plugins', 'plugin_documentation') + this.renderDocumentationLinks( + 'http://docs.openstack.org/', + 'openstack_documentation' + ), + this.renderDocumentationLinks( + 'https://wiki.openstack.org/wiki/Fuel/Plugins', + 'plugin_documentation' + ) ] }
@@ -308,7 +331,8 @@ var DocumentationLinks = React.createClass({ // it should be refactored to provide proper logics separation and decoupling var DeployReadinessBlock = React.createClass({ mixins: [ - // this is needed to somehow handle the case when verification is in progress and user pressed Deploy + // this is needed to somehow handle the case when verification + // is in progress and user pressed Deploy backboneMixin({ modelOrCollection(props) { return props.cluster.get('tasks'); @@ -332,7 +356,8 @@ var DeployReadinessBlock = React.createClass({ validate(cluster) { return _.reduce( this.validations, - (accumulator, validator) => _.merge(accumulator, validator.call(this, cluster), (a, b) => a.concat(_.compact(b))), + (accumulator, validator) => _.merge(accumulator, validator.call(this, cluster), (a, b) => + a.concat(_.compact(b))), {blocker: [], error: [], warning: []} ); }, @@ -398,9 +423,16 @@ var DeployReadinessBlock = React.createClass({ function(cluster) { var configModels = this.getConfigModels(); var roleModels = cluster.get('roles'); - var validRoleModels = roleModels.filter((role) => !role.checkRestrictions(configModels).result); - var limitValidations = _.zipObject(validRoleModels.map((role) => [role.get('name'), role.checkLimits(configModels, cluster.get('nodes'))])); - var limitRecommendations = _.zipObject(validRoleModels.map((role) => [role.get('name'), role.checkLimits(configModels, cluster.get('nodes'), true, ['recommended'])])); + var validRoleModels = roleModels.filter((role) => { + return !role.checkRestrictions(configModels).result; + }); + var limitValidations = _.zipObject(validRoleModels.map((role) => { + return [role.get('name'), role.checkLimits(configModels, cluster.get('nodes'))]; + })); + var limitRecommendations = _.zipObject(validRoleModels.map((role) => { + return [role.get('name'), role.checkLimits(configModels, cluster.get('nodes'), true, + ['recommended'])]; + })); return { blocker: roleModels.map((role) => { var name = role.get('name'); @@ -461,7 +493,9 @@ var DeployReadinessBlock = React.createClass({ var nodes = cluster.get('nodes'); var alerts = this.validate(cluster); var isDeploymentPossible = cluster.isDeploymentPossible() && !alerts.blocker.length; - var isVMsProvisioningAvailable = nodes.any((node) => node.get('pending_addition') && node.hasRole('virt')); + var isVMsProvisioningAvailable = nodes.any((node) => { + return node.get('pending_addition') && node.hasRole('virt'); + }); return (
@@ -471,9 +505,18 @@ var DeployReadinessBlock = React.createClass({

{i18n(namespace + 'changes_header')}

    - {this.renderChangedNodesAmount(nodes.where({pending_addition: true}), 'added_node')} - {this.renderChangedNodesAmount(nodes.where({status: 'provisioned'}), 'provisioned_node')} - {this.renderChangedNodesAmount(nodes.where({pending_deletion: true}), 'deleted_node')} + {this.renderChangedNodesAmount( + nodes.where({pending_addition: true}), + 'added_node' + )} + {this.renderChangedNodesAmount( + nodes.where({status: 'provisioned'}), + 'provisioned_node' + )} + {this.renderChangedNodesAmount( + nodes.where({pending_deletion: true}), + 'deleted_node' + )}
} @@ -489,7 +532,10 @@ var DeployReadinessBlock = React.createClass({ ; + return ; }) }
diff --git a/static/views/cluster_page_tabs/network_tab.js b/static/views/cluster_page_tabs/network_tab.js index 8df27f0b1..560f1bb72 100644 --- a/static/views/cluster_page_tabs/network_tab.js +++ b/static/views/cluster_page_tabs/network_tab.js @@ -30,7 +30,10 @@ import CSSTransitionGroup from 'react-addons-transition-group'; var parametersNS = 'cluster_page.network_tab.networking_parameters.'; var networkTabNS = 'cluster_page.network_tab.'; -var defaultNetworkSubtabs = ['neutron_l2', 'neutron_l3', 'network_settings', 'network_verification', 'nova_configuration']; +var defaultNetworkSubtabs = [ + 'neutron_l2', 'neutron_l3', 'network_settings', + 'network_verification', 'nova_configuration' +]; var NetworkModelManipulationMixin = { setValue(attribute, value, options) { @@ -98,7 +101,8 @@ var NetworkInputsMixin = { var error; if (this.props.network) { try { - error = validationError.networks[this.props.currentNodeNetworkGroup.id][this.props.network.id][attribute]; + error = validationError + .networks[this.props.currentNodeNetworkGroup.id][this.props.network.id][attribute]; } catch (e) {} return error || null; } @@ -139,7 +143,11 @@ var Range = React.createClass({ componentDidUpdate() { // this glitch is needed to fix // when pressing '+' or '-' buttons button remains focused - if (this.props.extendable && this.state.elementToFocus && this.getModel().get(this.props.name).length) { + if ( + this.props.extendable && + this.state.elementToFocus && + this.getModel().get(this.props.name).length + ) { $(this.refs[this.state.elementToFocus].getInputDOMNode()).focus(); this.setState({elementToFocus: null}); } @@ -244,7 +252,10 @@ var Range = React.createClass({ onFocus={_.partial(this.autoCompleteIPRange, rangeError && rangeError.start, range[0])} disabled={this.props.disabled || !!this.props.autoIncreaseWith} placeholder={rangeError.end ? '' : this.props.placeholder} - extraContent={!this.props.hiddenControls && this.renderRangeControls(attributeName, index, ranges.length)} + extraContent={ + !this.props.hiddenControls && + this.renderRangeControls(attributeName, index, ranges.length) + } />
@@ -306,7 +317,8 @@ var Range = React.createClass({
{ - // TODO: renderExtendableRanges & renderRanges methods should be refactored to avoid copy-paste + // TODO: renderExtendableRanges & renderRanges methods + // should be refactored to avoid copy-paste this.props.extendable ? this.renderExtendableRanges({error, attributeName, ranges, verificationError}) : @@ -546,7 +558,8 @@ var NetworkTab = React.createClass({ configModels: { cluster: this.props.cluster, settings: settings, - networking_parameters: this.props.cluster.get('networkConfiguration').get('networking_parameters'), + networking_parameters: + this.props.cluster.get('networkConfiguration').get('networking_parameters'), version: app.version, release: this.props.cluster.get('release'), default: settings @@ -560,7 +573,11 @@ var NetworkTab = React.createClass({ componentDidMount() { this.props.cluster.get('networkConfiguration').isValid(); this.props.cluster.get('settings').isValid({models: this.state.configModels}); - this.props.cluster.get('tasks').on('change:status change:unsaved', this.destroyUnsavedNetworkVerificationTask, this); + this.props.cluster.get('tasks').on( + 'change:status change:unsaved', + this.destroyUnsavedNetworkVerificationTask, + this + ); }, componentWillUnmount() { this.loadInitialConfiguration(); @@ -583,10 +600,16 @@ var NetworkTab = React.createClass({ clusterTasks.each((task) => task.get('unsaved') && clusterTasks.remove(task)); }, isNetworkConfigurationChanged() { - return !_.isEqual(this.state.initialConfiguration, this.props.cluster.get('networkConfiguration').toJSON()); + return !_.isEqual( + this.state.initialConfiguration, + this.props.cluster.get('networkConfiguration').toJSON() + ); }, isNetworkSettingsChanged() { - return this.props.cluster.get('settings').hasChanges(this.state.initialSettingsAttributes, this.state.configModels); + return this.props.cluster.get('settings').hasChanges( + this.state.initialSettingsAttributes, + this.state.configModels + ); }, hasChanges() { return this.isNetworkConfigurationChanged() || this.isNetworkSettingsChanged(); @@ -602,17 +625,26 @@ var NetworkTab = React.createClass({ }, loadInitialConfiguration() { var networkConfiguration = this.props.cluster.get('networkConfiguration'); - networkConfiguration.get('networks').reset(_.cloneDeep(this.state.initialConfiguration.networks)); - networkConfiguration.get('networking_parameters').set(_.cloneDeep(this.state.initialConfiguration.networking_parameters)); + networkConfiguration.get('networks').reset( + _.cloneDeep(this.state.initialConfiguration.networks) + ); + networkConfiguration.get('networking_parameters').set( + _.cloneDeep(this.state.initialConfiguration.networking_parameters) + ); }, loadInitialSettings() { var settings = this.props.cluster.get('settings'); - settings.set(_.cloneDeep(this.state.initialSettingsAttributes), {silent: true, validate: false}); + settings.set( + _.cloneDeep(this.state.initialSettingsAttributes), + {silent: true, validate: false} + ); settings.mergePluginSettings(); settings.isValid({models: this.state.configModels}); }, updateInitialConfiguration() { - this.setState({initialConfiguration: _.cloneDeep(this.props.cluster.get('networkConfiguration').toJSON())}); + this.setState({ + initialConfiguration: _.cloneDeep(this.props.cluster.get('networkConfiguration').toJSON()) + }); }, isLocked() { return !!this.props.cluster.task({group: ['deployment', 'network'], active: true}) || @@ -630,13 +662,16 @@ var NetworkTab = React.createClass({ }); var floatingRanges = networkConfiguration.get('networking_parameters').get('floating_ranges'); if (floatingRanges) { - networkConfiguration.get('networking_parameters').set({floating_ranges: removeEmptyRanges(floatingRanges)}); + networkConfiguration.get('networking_parameters').set({ + floating_ranges: removeEmptyRanges(floatingRanges) + }); } }, onManagerChange(name, value) { var networkConfiguration = this.props.cluster.get('networkConfiguration'); var networkingParameters = networkConfiguration.get('networking_parameters'); - var fixedAmount = networkConfiguration.get('networking_parameters').get('fixed_networks_amount') || 1; + var fixedAmount = + networkConfiguration.get('networking_parameters').get('fixed_networks_amount') || 1; networkingParameters.set({ net_manager: value, fixed_networks_amount: value == 'FlatDHCPManager' ? 1 : fixedAmount @@ -770,7 +805,8 @@ var NetworkTab = React.createClass({ _.isNull(this.props.cluster.get('settings').validationError); }, renderButtons() { - var isCancelChangesDisabled = this.state.actionInProgress || !!this.props.cluster.task({group: 'deployment', active: true}) || !this.hasChanges(); + var isCancelChangesDisabled = this.state.actionInProgress || + !!this.props.cluster.task({group: 'deployment', active: true}) || !this.hasChanges(); return (
@@ -795,7 +831,8 @@ var NetworkTab = React.createClass({ ); }, getVerificationErrors() { - var task = this.state.hideVerificationResult ? null : this.props.cluster.task({group: 'network', status: 'error'}); + var task = this.state.hideVerificationResult ? null : + this.props.cluster.task({group: 'network', status: 'error'}); var fieldsWithVerificationErrors = []; // @TODO(morale): soon response format will be changed and this part should be rewritten if (task && task.get('result').length) { @@ -816,7 +853,9 @@ var NetworkTab = React.createClass({ showUnsavedChangesWarning: this.hasChanges() }) .done(() => { - this.props.setActiveNetworkSectionName(this.nodeNetworkGroups.find({is_default: true}).get('name')); + this.props.setActiveNetworkSectionName( + this.nodeNetworkGroups.find({is_default: true}).get('name') + ); return nodeNetworkGroup .destroy({wait: true}) .then( @@ -833,7 +872,11 @@ var NetworkTab = React.createClass({ if (hasChanges) { utils.showErrorDialog({ title: i18n(networkTabNS + 'node_network_group_creation_error'), - message:
{i18n(networkTabNS + 'save_changes_warning')}
+ message:
+ + {' '} + {i18n(networkTabNS + 'save_changes_warning')} +
}); return; } @@ -879,7 +922,8 @@ var NetworkTab = React.createClass({ row: true, 'changes-locked': isLocked }; - var nodeNetworkGroups = this.nodeNetworkGroups = new models.NodeNetworkGroups(this.props.nodeNetworkGroups.where({cluster_id: cluster.id})); + var nodeNetworkGroups = this.nodeNetworkGroups = + new models.NodeNetworkGroups(this.props.nodeNetworkGroups.where({cluster_id: cluster.id})); var isNovaEnvironment = cluster.get('net_provider') == 'nova_network'; var networks = networkConfiguration.get('networks'); var isMultiRack = nodeNetworkGroups.length > 1; @@ -922,7 +966,10 @@ var NetworkTab = React.createClass({ key='add_node_group' className='btn btn-default add-nodegroup-btn pull-right' onClick={_.partial(this.addNodeNetworkGroup, hasChanges)} - disabled={!!cluster.task({group: ['deployment', 'network'], active: true}) || this.state.actionInProgress} + disabled={ + !!cluster.task({group: ['deployment', 'network'], active: true}) || + this.state.actionInProgress + } > {hasChanges && } {i18n(networkTabNS + 'add_node_network_group')} @@ -1008,7 +1055,8 @@ var NetworkTab = React.createClass({
- {!this.state.hideVerificationResult && networkCheckTask && networkCheckTask.match({status: 'error'}) && + {!this.state.hideVerificationResult && networkCheckTask && + networkCheckTask.match({status: 'error'}) &&
{utils.renderMultilineText(networkCheckTask.get('message'))} @@ -1025,7 +1073,10 @@ var NetworkTab = React.createClass({ var NodeNetworkGroup = React.createClass({ render() { - var {cluster, networks, nodeNetworkGroup, nodeNetworkGroups, verificationErrors, validationError} = this.props; + var { + cluster, networks, nodeNetworkGroup, nodeNetworkGroups, + verificationErrors, validationError + } = this.props; return (
); @@ -1069,11 +1122,20 @@ var NetworkSubtabs = React.createClass({ // is one of predefined sections selected (networking_parameters) if (groupName == 'neutron_l2') { - isInvalid = !!_.intersection(NetworkingL2Parameters.renderedParameters, _.keys(networkParametersErrors)).length; + isInvalid = !!_.intersection( + NetworkingL2Parameters.renderedParameters, + _.keys(networkParametersErrors) + ).length; } else if (groupName == 'neutron_l3') { - isInvalid = !!_.intersection(NetworkingL3Parameters.renderedParameters, _.keys(networkParametersErrors)).length; + isInvalid = !!_.intersection( + NetworkingL3Parameters.renderedParameters, + _.keys(networkParametersErrors) + ).length; } else if (groupName == 'nova_configuration') { - isInvalid = !!_.intersection(NovaParameters.renderedParameters, _.keys(networkParametersErrors)).length; + isInvalid = !!_.intersection( + NovaParameters.renderedParameters, + _.keys(networkParametersErrors) + ).length; } else if (groupName == 'network_settings') { var settings = cluster.get('settings'); isInvalid = _.any(_.keys(settings.validationError), (settingPath) => { @@ -1084,7 +1146,8 @@ var NetworkSubtabs = React.createClass({ } if (isNetworkGroupPill) { - isInvalid = networksErrors && (isNovaEnvironment || !!networksErrors[nodeNetworkGroups.findWhere({name: groupName}).id]); + isInvalid = networksErrors && (isNovaEnvironment || + !!networksErrors[nodeNetworkGroups.findWhere({name: groupName}).id]); } else { tabLabel = i18n(networkTabNS + 'tabs.' + groupName); } @@ -1233,10 +1296,15 @@ var NodeNetworkGroupTitle = React.createClass({ } {isDeletionPossible && ( currentNodeNetworkGroup.get('is_default') ? - {i18n(networkTabNS + 'default_node_network_group_info')} + + {i18n(networkTabNS + 'default_node_network_group_info')} + : !this.state.isRenaming && - + )}
); @@ -1339,7 +1407,9 @@ var NovaParameters = React.createClass({ wrapperClassName='clearfix vlan-id-range' label={i18n(parametersNS + 'fixed_vlan_range')} extendable={false} - autoIncreaseWith={parseInt(networkingParameters.get('fixed_networks_amount'), 10) || 0} + autoIncreaseWith={ + parseInt(networkingParameters.get('fixed_networks_amount'), 10) || 0 + } integerValue placeholder='' mini @@ -1368,12 +1438,18 @@ var NetworkingL2Parameters = React.createClass({ ] }, render() { - var networkParameters = this.props.cluster.get('networkConfiguration').get('networking_parameters'); + var networkParameters = + this.props.cluster.get('networkConfiguration').get('networking_parameters'); var idRangePrefix = networkParameters.get('segmentation_type') == 'vlan' ? 'vlan' : 'gre_id'; return (

{i18n(parametersNS + 'l2_configuration')}

-
{i18n(networkTabNS + 'networking_parameters.l2_' + networkParameters.get('segmentation_type') + '_description')}
+
+ { + i18n(networkTabNS + 'networking_parameters.l2_' + + networkParameters.get('segmentation_type') + '_description') + } +

- {i18n(networkTabNS + 'baremetal_net')} + + {i18n(networkTabNS + 'baremetal_net')} +

-
{i18n(networkTabNS + 'networking_parameters.baremetal_parameters_description')}
+
+ {i18n(networkTabNS + 'networking_parameters.baremetal_parameters_description')} +

- {i18n(networkTabNS + 'dns_nameservers')} + + {i18n(networkTabNS + 'dns_nameservers')} +

-
{i18n(networkTabNS + 'networking_parameters.dns_servers_description')}
+
+ {i18n(networkTabNS + 'networking_parameters.dns_servers_description')} +
@@ -1465,14 +1549,17 @@ var NetworkSettings = React.createClass({ settings.isValid({models: this.props.configModels}); }, checkRestrictions(action, setting) { - return this.props.cluster.get('settings').checkRestrictions(this.props.configModels, action, setting); + return this.props.cluster.get('settings') + .checkRestrictions(this.props.configModels, action, setting); }, render() { var cluster = this.props.cluster; var settings = cluster.get('settings'); - var locked = this.props.locked || !!cluster.task({group: ['deployment', 'network'], active: true}); + var locked = this.props.locked || + !!cluster.task({group: ['deployment', 'network'], active: true}); var lockedCluster = !cluster.isAvailableForSettingsChanges(); - var allocatedRoles = _.uniq(_.flatten(_.union(cluster.get('nodes').pluck('roles'), cluster.get('nodes').pluck('pending_roles')))); + var allocatedRoles = _.uniq(_.flatten(_.union(cluster.get('nodes').pluck('roles'), + cluster.get('nodes').pluck('pending_roles')))); return (
{ @@ -1481,7 +1568,8 @@ var NetworkSettings = React.createClass({ .filter( (sectionName) => { var section = settings.get(sectionName); - return (section.metadata.group == 'network' || _.any(section, {group: 'network'})) && + return (section.metadata.group == 'network' || + _.any(section, {group: 'network'})) && !this.checkRestrictions('hide', section.metadata).result; } ) @@ -1501,7 +1589,10 @@ var NetworkSettings = React.createClass({ })); if (_.isEmpty(settingsToDisplay) && !settings.isPlugin(section)) return null; return {_.times(3, (index) => { ++index; - return
; + return
+
; })}
@@ -1620,7 +1715,12 @@ var NetworkVerificationResult = React.createClass({ var absentVlans = _.map(node.absent_vlans, (vlan) => { return vlan || i18n(networkTabNS + 'untagged'); }); - return [node.name || 'N/A', node.mac || 'N/A', node.interface, absentVlans.join(', ')]; + return [ + node.name || 'N/A', + node.mac || 'N/A', + node.interface, + absentVlans.join(', ') + ]; }) } /> diff --git a/static/views/cluster_page_tabs/nodes_tab.js b/static/views/cluster_page_tabs/nodes_tab.js index 50a8596f3..bd5ec4115 100644 --- a/static/views/cluster_page_tabs/nodes_tab.js +++ b/static/views/cluster_page_tabs/nodes_tab.js @@ -23,7 +23,8 @@ import ClusterNodesScreen from 'views/cluster_page_tabs/nodes_tab_screens/cluste import AddNodesScreen from 'views/cluster_page_tabs/nodes_tab_screens/add_nodes_screen'; import EditNodesScreen from 'views/cluster_page_tabs/nodes_tab_screens/edit_nodes_screen'; import EditNodeDisksScreen from 'views/cluster_page_tabs/nodes_tab_screens/edit_node_disks_screen'; -import EditNodeInterfacesScreen from 'views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen'; +import EditNodeInterfacesScreen from + 'views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen'; import ReactTransitionGroup from 'react-addons-transition-group'; var NodesTab = React.createClass({ @@ -65,7 +66,10 @@ var NodesTab = React.createClass({ }); }) .fail(() => { - app.navigate('#cluster/' + this.props.cluster.id + '/nodes', {trigger: true, replace: true}); + app.navigate( + '#cluster/' + this.props.cluster.id + '/nodes', + {trigger: true, replace: true} + ); }); }, getScreen(props) { @@ -111,7 +115,10 @@ var NodesTab = React.createClass({ > diff --git a/static/views/cluster_page_tabs/nodes_tab_screens/add_nodes_screen.js b/static/views/cluster_page_tabs/nodes_tab_screens/add_nodes_screen.js index e7c2a7094..40d364c78 100644 --- a/static/views/cluster_page_tabs/nodes_tab_screens/add_nodes_screen.js +++ b/static/views/cluster_page_tabs/nodes_tab_screens/add_nodes_screen.js @@ -24,7 +24,8 @@ var AddNodesScreen = React.createClass({ fetchData(options) { var nodes = new models.Nodes(); nodes.fetch = function(options) { - return this.constructor.__super__.fetch.call(this, _.extend({data: {cluster_id: ''}}, options)); + return this.constructor.__super__.fetch.call(this, _.extend({data: {cluster_id: ''}}, + options)); }; return $.when(nodes.fetch(), options.cluster.get('roles').fetch(), options.cluster.get('settings').fetch({cache: true})).then(() => ({nodes: nodes})); diff --git a/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_disks_screen.js b/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_disks_screen.js index 7b8517856..97f7f44cc 100644 --- a/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_disks_screen.js +++ b/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_disks_screen.js @@ -69,7 +69,10 @@ var EditNodeDisksScreen = React.createClass({ this.setState({initialDisks: _.cloneDeep(this.props.nodes.at(0).disks.toJSON())}); }, hasChanges() { - return !this.isLocked() && !_.isEqual(_.pluck(this.props.disks.toJSON(), 'volumes'), _.pluck(this.state.initialDisks, 'volumes')); + return !this.isLocked() && !_.isEqual( + _.pluck(this.props.disks.toJSON(), 'volumes'), + _.pluck(this.state.initialDisks, 'volumes') + ); }, loadDefaults() { this.setState({actionInProgress: true}); @@ -168,7 +171,13 @@ var EditNodeDisksScreen = React.createClass({
- {i18n('cluster_page.nodes_tab.configure_disks.' + (locked ? 'read_only_' : '') + 'title', {count: this.props.nodes.length, name: this.props.nodes.length && this.props.nodes.at(0).get('name')})} + {i18n( + 'cluster_page.nodes_tab.configure_disks.' + (locked ? 'read_only_' : '') + 'title', + { + count: this.props.nodes.length, + name: this.props.nodes.length && this.props.nodes.at(0).get('name') + } + )}
{this.props.disks.length ? @@ -184,22 +193,44 @@ var EditNodeDisksScreen = React.createClass({ }) :
- {i18n('cluster_page.nodes_tab.configure_disks.no_disks', {count: this.props.nodes.length})} + {i18n('cluster_page.nodes_tab.configure_disks.no_disks', + {count: this.props.nodes.length})}
}
@@ -225,7 +256,8 @@ var NodeDisk = React.createClass({ if (size > volumeInfo.max) { size = volumeInfo.max; } - this.props.disk.get('volumes').findWhere({name: name}).set({size: size}).isValid({minimum: volumeInfo.min}); + this.props.disk.get('volumes').findWhere({name: name}).set({size: size}) + .isValid({minimum: volumeInfo.min}); this.props.disk.trigger('change', this.props.disk); }, toggleDisk(name) { @@ -236,7 +268,8 @@ var NodeDisk = React.createClass({ var volumesInfo = this.props.volumesInfo; var diskMetaData = this.props.diskMetaData; var requiredDiskSize = _.sum(disk.get('volumes').map((volume) => { - return volume.getMinimalSize(this.props.volumes.findWhere({name: volume.get('name')}).get('min_size')); + return volume + .getMinimalSize(this.props.volumes.findWhere({name: volume.get('name')}).get('min_size')); })); var diskError = disk.get('size') < requiredDiskSize; var sortOrder = ['name', 'model', 'size']; @@ -263,26 +296,44 @@ var NodeDisk = React.createClass({ data-volume={volumeName} style={{width: volumesInfo[volumeName].width + '%'}} > -
+
{volume.get('label')}
{utils.showDiskSize(volumesInfo[volumeName].size, 2)}
{!this.props.disabled && volumesInfo[volumeName].min <= 0 && this.state.collapsed && -
×
+
+ × +
}
); })} -
-
+
+
{i18n(ns + 'unallocated')}
-
{utils.showDiskSize(volumesInfo.unallocated.size, 2)}
+
+ {utils.showDiskSize(volumesInfo.unallocated.size, 2)} +
-
+
{diskMetaData &&
@@ -294,7 +345,10 @@ var NodeDisk = React.createClass({

- {propertyName == 'size' ? utils.showDiskSize(diskMetaData[propertyName]) : diskMetaData[propertyName]} + {propertyName == 'size' ? + utils.showDiskSize(diskMetaData[propertyName]) : + diskMetaData[propertyName] + }

@@ -325,7 +379,12 @@ var NodeDisk = React.createClass({
@@ -343,10 +402,14 @@ var NodeDisk = React.createClass({ error={validationError && ''} value={value} /> -
{i18n('common.size.mb')}
+
+ {i18n('common.size.mb')} +
{!!value && value == currentMinSize && -
{i18n(ns + 'minimum_reached')}
+
+ {i18n(ns + 'minimum_reached')} +
} {validationError &&
{validationError}
@@ -355,7 +418,9 @@ var NodeDisk = React.createClass({ ); })} {diskError && -
{i18n(ns + 'not_enough_space')}
+
+ {i18n(ns + 'not_enough_space')} +
}
diff --git a/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen.js b/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen.js index 1637d5eef..8d73bf0c6 100644 --- a/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen.js +++ b/static/views/cluster_page_tabs/nodes_tab_screens/edit_node_interfaces_screen.js @@ -92,7 +92,10 @@ var EditNodeInterfacesScreen = React.createClass({ }, interfacesPickFromJSON(json) { // Pick certain interface fields that have influence on hasChanges. - return _.pick(json, ['assigned_networks', 'mode', 'type', 'slaves', 'bond_properties', 'interface_properties', 'offloading_modes']); + return _.pick(json, [ + 'assigned_networks', 'mode', 'type', 'slaves', 'bond_properties', + 'interface_properties', 'offloading_modes' + ]); }, interfacesToJSON(interfaces, remainingNodesMode) { // Sometimes 'state' is sent from the API and sometimes not @@ -179,7 +182,9 @@ var EditNodeInterfacesScreen = React.createClass({ node.interfaces.each((ifc, index) => { var updatedIfc = ifc.isBond() ? bondsByName[ifc.get('name')] : interfaces.at(index); ifc.set({ - assigned_networks: new models.InterfaceNetworks(updatedIfc.get('assigned_networks').toJSON()), + assigned_networks: new models.InterfaceNetworks( + updatedIfc.get('assigned_networks').toJSON() + ), interface_properties: updatedIfc.get('interface_properties') }); if (ifc.isBond()) { @@ -197,7 +202,8 @@ var EditNodeInterfacesScreen = React.createClass({ return Backbone.sync('update', node.interfaces, {url: _.result(node, 'url') + '/interfaces'}); })) .done(() => { - this.setState({initialInterfaces: _.cloneDeep(this.interfacesToJSON(this.props.interfaces))}); + this.setState({initialInterfaces: + _.cloneDeep(this.interfacesToJSON(this.props.interfaces))}); dispatcher.trigger('networkConfigurationUpdated'); }) .fail((response) => { @@ -213,19 +219,21 @@ var EditNodeInterfacesScreen = React.createClass({ }); }, configurationTemplateExists() { - return !_.isEmpty(this.props.cluster.get('networkConfiguration').get('networking_parameters').get('configuration_template')); + return !_.isEmpty(this.props.cluster.get('networkConfiguration') + .get('networking_parameters').get('configuration_template')); }, bondingAvailable() { var availableBondTypes = this.getBondType(); return !!availableBondTypes && !this.configurationTemplateExists(); }, getBondType() { - return _.compact(_.flatten(_.map(this.props.bondingConfig.availability, (modeAvailabilityData) => { - return _.map(modeAvailabilityData, (condition, name) => { - var result = utils.evaluateExpression(condition, this.props.configModels).value; - return result && name; - }); - })))[0]; + return _.compact(_.flatten(_.map(this.props.bondingConfig.availability, + (modeAvailabilityData) => { + return _.map(modeAvailabilityData, (condition, name) => { + var result = utils.evaluateExpression(condition, this.props.configModels).value; + return result && name; + }); + })))[0]; }, findOffloadingModesIntersection(set1, set2) { return _.map( @@ -248,7 +256,9 @@ var EditNodeInterfacesScreen = React.createClass({ var offloadingModes = interfaces.map((ifc) => ifc.get('offloading_modes') || []); if (!offloadingModes.length) return []; - return offloadingModes.reduce((result, modes) => this.findOffloadingModesIntersection(result, modes)); + return offloadingModes.reduce((result, modes) => { + return this.findOffloadingModesIntersection(result, modes); + }); }, bondInterfaces() { this.setState({actionInProgress: true}); @@ -261,7 +271,8 @@ var EditNodeInterfacesScreen = React.createClass({ var bondMode = _.flatten(_.pluck(bondingProperties[this.getBondType()].mode, 'values'))[0]; bonds = new models.Interface({ type: 'bond', - name: this.props.interfaces.generateBondName(this.getBondType() == 'linux' ? 'bond' : 'ovs-bond'), + name: this.props.interfaces.generateBondName(this.getBondType() == + 'linux' ? 'bond' : 'ovs-bond'), mode: bondMode, assigned_networks: new models.InterfaceNetworks(), slaves: _.invoke(interfaces, 'pick', 'name'), @@ -293,7 +304,9 @@ var EditNodeInterfacesScreen = React.createClass({ }, unbondInterfaces() { this.setState({actionInProgress: true}); - _.each(this.props.interfaces.where({checked: true}), (bond) => this.removeInterfaceFromBond(bond.get('name'))); + _.each(this.props.interfaces.where({checked: true}), (bond) => { + return this.removeInterfaceFromBond(bond.get('name')); + }); this.setState({actionInProgress: false}); }, removeInterfaceFromBond(bondName, slaveInterfaceName) { @@ -320,7 +333,9 @@ var EditNodeInterfacesScreen = React.createClass({ if (slaveInterfaceName) { var slavesUpdated = _.reject(slaves, {name: slaveInterfaceName}); var names = _.pluck(slavesUpdated, 'name'); - var bondSlaveInterfaces = this.props.interfaces.filter((ifc) => _.contains(names, ifc.get('name'))); + var bondSlaveInterfaces = this.props.interfaces.filter((ifc) => { + return _.contains(names, ifc.get('name')); + }); bond.set({ slaves: slavesUpdated, @@ -377,7 +392,8 @@ var EditNodeInterfacesScreen = React.createClass({ return _.uniq(speeds).length > 1 || !_.compact(speeds).length; }, isSavingPossible() { - return !_.chain(this.state.interfaceErrors).values().some().value() && !this.state.actionInProgress && this.hasChanges(); + return !_.chain(this.state.interfaceErrors).values().some().value() && + !this.state.actionInProgress && this.hasChanges(); }, getIfcProperty(property) { var {interfaces, nodes} = this.props; @@ -416,20 +432,25 @@ var EditNodeInterfacesScreen = React.createClass({ var slaveInterfaceNames = _.pluck(_.flatten(_.filter(interfaces.pluck('slaves'))), 'name'); var loadDefaultsEnabled = !this.state.actionInProgress; var revertChangesEnabled = !this.state.actionInProgress && hasChanges; - var invalidSpeedsForBonding = bondingPossible && this.validateSpeedsForBonding(checkedBonds.concat(checkedInterfaces)) || interfaces.any((ifc) => { - return ifc.isBond() && this.validateSpeedsForBonding([ifc]); - }); + var invalidSpeedsForBonding = bondingPossible && + this.validateSpeedsForBonding(checkedBonds.concat(checkedInterfaces)) || + interfaces.any((ifc) => { + return ifc.isBond() && this.validateSpeedsForBonding([ifc]); + }); var interfaceSpeeds = this.getIfcProperty('current_speed'); var interfaceNames = this.getIfcProperty('name'); return (
- {i18n(ns + (locked ? 'read_only_' : '') + 'title', {count: nodes.length, name: nodeNames.join(', ')})} + {i18n(ns + (locked ? 'read_only_' : '') + 'title', + {count: nodes.length, name: nodeNames.join(', ')})}
{configurationTemplateExists &&
-
{i18n(ns + 'configuration_template_warning')}
+
+ {i18n(ns + 'configuration_template_warning')} +
} {bondingAvailable && !locked && @@ -437,10 +458,18 @@ var EditNodeInterfacesScreen = React.createClass({
- -
@@ -478,19 +507,35 @@ var EditNodeInterfacesScreen = React.createClass({
{!locked &&
- - -
@@ -508,7 +553,8 @@ var NodeInterface = React.createClass({ drop(props, monitor) { var targetInterface = props.interface; var sourceInterface = props.interfaces.findWhere({name: monitor.getItem().interfaceName}); - var network = sourceInterface.get('assigned_networks').findWhere({name: monitor.getItem().networkName}); + var network = sourceInterface.get('assigned_networks') + .findWhere({name: monitor.getItem().networkName}); sourceInterface.get('assigned_networks').remove(network); targetInterface.get('assigned_networks').add(network); // trigger 'change' event to update screen buttons state @@ -542,7 +588,8 @@ var NodeInterface = React.createClass({ return _.contains(this.getBondPropertyValues('lacp_rate', 'for_modes'), this.getBondMode()); }, isHashPolicyNeeded() { - return _.contains(this.getBondPropertyValues('xmit_hash_policy', 'for_modes'), this.getBondMode()); + return _.contains(this.getBondPropertyValues('xmit_hash_policy', 'for_modes'), + this.getBondMode()); }, getBondMode() { var ifc = this.props.interface; @@ -552,11 +599,13 @@ var NodeInterface = React.createClass({ var modes = this.props.bondingProperties[this.props.bondType].mode; var configModels = _.clone(this.props.configModels); var availableModes = []; - var interfaces = this.props.interface.isBond() ? this.props.interface.getSlaveInterfaces() : [this.props.interface]; + var interfaces = this.props.interface.isBond() ? this.props.interface.getSlaveInterfaces() : + [this.props.interface]; _.each(interfaces, (ifc) => { configModels.interface = ifc; availableModes.push(_.reduce(modes, (result, modeSet) => { - if (modeSet.condition && !utils.evaluateExpression(modeSet.condition, configModels).value) return result; + if (modeSet.condition && + !utils.evaluateExpression(modeSet.condition, configModels).value) return result; return result.concat(modeSet.values); }, [])); }); @@ -583,7 +632,8 @@ var NodeInterface = React.createClass({ this.props.interface.set({mode: value}); this.updateBondProperties({mode: value}); if (this.isHashPolicyNeeded()) { - this.updateBondProperties({xmit_hash_policy: this.getBondPropertyValues('xmit_hash_policy', 'values')[0]}); + this.updateBondProperties({xmit_hash_policy: this.getBondPropertyValues('xmit_hash_policy', + 'values')[0]}); } if (this.isLacpRateAvailable()) { this.updateBondProperties({lacp_rate: this.getBondPropertyValues('lacp_rate', 'values')[0]}); @@ -684,7 +734,10 @@ var NodeInterface = React.createClass({ disabled={!bondingPossible} onChange={this.onPolicyChange} label={i18n(ns + 'bonding_policy')} - children={this.getBondingOptions(this.getBondPropertyValues('xmit_hash_policy', 'values'), 'hash_policy')} + children={this.getBondingOptions( + this.getBondPropertyValues('xmit_hash_policy', 'values'), + 'hash_policy' + )} wrapperClassName='pull-right' /> } @@ -695,7 +748,10 @@ var NodeInterface = React.createClass({ disabled={!bondingPossible} onChange={this.onLacpChange} label={i18n(ns + 'lacp_rate')} - children={this.getBondingOptions(this.getBondPropertyValues('lacp_rate', 'values'), 'lacp_rates')} + children={this.getBondingOptions( + this.getBondPropertyValues('lacp_rate', 'values'), + 'lacp_rates' + )} wrapperClassName='pull-right' /> } @@ -718,14 +774,21 @@ var NodeInterface = React.createClass({
{_.map(slaveInterfaces, (slaveInterface, index) => { return ( -
+
-
+
{this.props.interfaceNames[index].length == 1 &&
- {i18n(ns + 'name')}: {this.props.interfaceNames[index]} + {i18n(ns + 'name')}: + {' '} + {this.props.interfaceNames[index]}
} {this.props.nodes.length == 1 && @@ -735,7 +798,13 @@ var NodeInterface = React.createClass({ {i18n(ns + 'speed')}: {this.props.interfaceSpeeds[index].join(', ')}
{(bondingPossible && slaveInterfaces.length >= 3) && - } @@ -789,7 +858,8 @@ var NodeInterface = React.createClass({ onClick={this.toggleOffloading} disabled={locked} className='btn btn-default toggle-offloading'> - {i18n(ns + (interfaceProperties.disable_offloading ? 'disable_offloading' : 'default_offloading'))} + {i18n(ns + (interfaceProperties.disable_offloading ? 'disable_offloading' : + 'default_offloading'))} }
@@ -802,7 +872,11 @@ var NodeInterface = React.createClass({ } }); -var NodeInterfaceDropTarget = DropTarget('network', NodeInterface.target, NodeInterface.collect)(NodeInterface); +var NodeInterfaceDropTarget = DropTarget( + 'network', + NodeInterface.target, + NodeInterface.collect +)(NodeInterface); var Network = React.createClass({ statics: { @@ -838,7 +912,10 @@ var Network = React.createClass({ return this.props.connectDragSource(
- {i18n('network.' + interfaceNetwork.get('name'), {defaultValue: interfaceNetwork.get('name')})} + {i18n( + 'network.' + interfaceNetwork.get('name'), + {defaultValue: interfaceNetwork.get('name')} + )}
{vlanRange &&
diff --git a/static/views/cluster_page_tabs/nodes_tab_screens/edit_nodes_screen.js b/static/views/cluster_page_tabs/nodes_tab_screens/edit_nodes_screen.js index d4eea3d37..d73750ff8 100644 --- a/static/views/cluster_page_tabs/nodes_tab_screens/edit_nodes_screen.js +++ b/static/views/cluster_page_tabs/nodes_tab_screens/edit_nodes_screen.js @@ -30,7 +30,8 @@ var EditNodesScreen = React.createClass({ } nodes.fetch = function(options) { - return this.constructor.__super__.fetch.call(this, _.extend({data: {cluster_id: cluster.id}}, options)); + return this.constructor.__super__.fetch.call(this, + _.extend({data: {cluster_id: cluster.id}}, options)); }; nodes.parse = function() { return this.getByIds(nodes.pluck('id')); diff --git a/static/views/cluster_page_tabs/nodes_tab_screens/node.js b/static/views/cluster_page_tabs/nodes_tab_screens/node.js index 23cc70f70..cebf10073 100644 --- a/static/views/cluster_page_tabs/nodes_tab_screens/node.js +++ b/static/views/cluster_page_tabs/nodes_tab_screens/node.js @@ -44,12 +44,21 @@ var Node = React.createClass({ var options = {type: 'remote', node: this.props.node.id}; if (status == 'discover') { options.source = 'bootstrap/messages'; - } else if (status == 'provisioning' || status == 'provisioned' || (status == 'error' && error == 'provision')) { + } else if ( + status == 'provisioning' || + status == 'provisioned' || + (status == 'error' && error == 'provision') + ) { options.source = 'install/fuel-agent'; - } else if (status == 'deploying' || status == 'ready' || (status == 'error' && error == 'deploy')) { + } else if ( + status == 'deploying' || + status == 'ready' || + (status == 'error' && error == 'deploy') + ) { options.source = 'install/puppet'; } - return '#cluster/' + this.props.node.get('cluster') + '/logs/' + utils.serializeTabOptions(options); + return '#cluster/' + this.props.node.get('cluster') + '/logs/' + + utils.serializeTabOptions(options); }, applyNewNodeName(newName) { if (newName && newName != this.props.node.get('name')) { @@ -100,7 +109,8 @@ var Node = React.createClass({ .sync('delete', this.props.node) .then( (task) => { - dispatcher.trigger('networkConfigurationUpdated updateNodeStats updateNotifications labelsConfigurationUpdated'); + dispatcher.trigger('networkConfigurationUpdated updateNodeStats ' + + 'updateNotifications labelsConfigurationUpdated'); if (task.status == 'ready') { // Do not send the 'DELETE' request again, just get rid // of this node. @@ -129,7 +139,8 @@ var Node = React.createClass({ }); }, toggleExtendedNodePanel() { - var states = this.state.extendedView ? {extendedView: false, isRenaming: false} : {extendedView: true}; + var states = this.state.extendedView ? + {extendedView: false, isRenaming: false} : {extendedView: true}; this.setState(states); }, renderNameControl() { @@ -159,7 +170,8 @@ var Node = React.createClass({ return ( {i18n('cluster_page.nodes_tab.node.status.' + status, { - os: this.props.cluster && this.props.cluster.get('release').get('operating_system') || 'OS' + os: this.props.cluster && this.props.cluster.get('release').get('operating_system') + || 'OS' })} ); @@ -174,7 +186,12 @@ var Node = React.createClass({ {': ' + nodeProgress + '%'}
} -
+
+
); }, @@ -184,16 +201,34 @@ var Node = React.createClass({ var ram = this.props.node.resource('ram'); return (
- {i18n('node_details.cpu')}: {this.props.node.resource('cores') || '0'} ({_.isUndefined(htCores) ? '?' : htCores}) - {i18n('node_details.hdd')}: {_.isUndefined(hdd) ? '?' + i18n('common.size.gb') : utils.showDiskSize(hdd)} - {i18n('node_details.ram')}: {_.isUndefined(ram) ? '?' + i18n('common.size.gb') : utils.showMemorySize(ram)} + + {i18n('node_details.cpu')} + {': '} + {this.props.node.resource('cores') || '0'} ({_.isUndefined(htCores) ? '?' : htCores}) + + + {i18n('node_details.hdd')} + {': '} + {_.isUndefined(hdd) ? '?' + i18n('common.size.gb') : utils.showDiskSize(hdd)} + + + {i18n('node_details.ram')} + {': '} + {_.isUndefined(ram) ? '?' + i18n('common.size.gb') : utils.showMemorySize(ram)} +
); }, renderLogsLink(iconRepresentation) { return ( - -
+ + {!iconRepresentation && i18n('cluster_page.nodes_tab.node.view_logs')} @@ -269,7 +304,9 @@ var Node = React.createClass({