/* * Copyright 2015 Mirantis, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ import $ from 'jquery'; import _ from 'underscore'; import Backbone from 'backbone'; import i18n from 'i18n'; import React from 'react'; import ReactDOM from 'react-dom'; import utils from 'utils'; import models from 'models'; import {backboneMixin, unsavedChangesMixin} from 'component_mixins'; import {Input} from 'views/controls'; var EditNodeDisksScreen = React.createClass({ mixins: [ backboneMixin('cluster', 'change:status change:nodes sync'), backboneMixin('nodes', 'change sync'), backboneMixin('disks', 'reset change'), unsavedChangesMixin ], statics: { fetchData(options) { var nodes = utils.getNodeListFromTabOptions(options); if (!nodes || !nodes.areDisksConfigurable()) { return $.Deferred().reject(); } var volumes = new models.Volumes(); volumes.url = _.result(nodes.at(0), 'url') + '/volumes'; return $.when(...nodes.map((node) => { node.disks = new models.Disks(); return node.disks.fetch({url: _.result(node, 'url') + '/disks'}); }, this).concat(volumes.fetch())) .then(() => { var disks = new models.Disks(_.cloneDeep(nodes.at(0).disks.toJSON()), {parse: true}); return { disks: disks, nodes: nodes, volumes: volumes }; }); } }, getInitialState() { return {actionInProgress: false}; }, componentWillMount() { this.updateInitialData(); }, isLocked() { return !!this.props.cluster.task({group: 'deployment', active: true}) || !_.all(this.props.nodes.invoke('areDisksConfigurable')); }, updateInitialData() { 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') ); }, loadDefaults() { this.setState({actionInProgress: true}); this.props.disks.fetch({url: _.result(this.props.nodes.at(0), 'url') + '/disks/defaults/'}) .fail((response) => { var ns = 'cluster_page.nodes_tab.configure_disks.configuration_error.'; utils.showErrorDialog({ title: i18n(ns + 'title'), message: utils.getResponseText(response) || i18n(ns + 'load_defaults_warning') }); }) .always(() => { this.setState({actionInProgress: false}); }); }, revertChanges() { this.props.disks.reset(_.cloneDeep(this.state.initialDisks), {parse: true}); }, applyChanges() { if (!this.isSavingPossible()) return $.Deferred().reject(); this.setState({actionInProgress: true}); return $.when(...this.props.nodes.map((node) => { node.disks.each((disk, index) => { disk.set({volumes: new models.Volumes(this.props.disks.at(index).get('volumes').toJSON())}); }); return Backbone.sync('update', node.disks, {url: _.result(node, 'url') + '/disks'}); })) .done(this.updateInitialData) .fail((response) => { var ns = 'cluster_page.nodes_tab.configure_disks.configuration_error.'; utils.showErrorDialog({ title: i18n(ns + 'title'), message: utils.getResponseText(response) || i18n(ns + 'saving_warning') }); }) .always(() => { this.setState({actionInProgress: false}); }); }, getDiskMetaData(disk) { var result; var disksMetaData = this.props.nodes.at(0).get('meta').disks; // try to find disk metadata by matching "extra" field // if at least one entry presents both in disk and metadata entry, // this metadata entry is for our disk var extra = disk.get('extra') || []; result = _.find(disksMetaData, (diskMetaData) => _.isArray(diskMetaData.extra) && _.intersection(diskMetaData.extra, extra).length ); // if matching "extra" fields doesn't work, try to search by disk id if (!result) { result = _.find(disksMetaData, {disk: disk.id}); } return result; }, getVolumesInfo(disk) { var volumes = {}; var unallocatedWidth = 100; disk.get('volumes').each((volume) => { var size = volume.get('size') || 0; var width = this.getVolumeWidth(disk, size); var name = volume.get('name'); unallocatedWidth -= width; volumes[name] = { size: size, width: width, max: volume.getMaxSize(), min: volume.getMinimalSize(this.props.volumes.findWhere({name: name}).get('min_size')), error: volume.validationError }; }); volumes.unallocated = { size: disk.getUnallocatedSpace(), width: unallocatedWidth }; return volumes; }, getVolumeWidth(disk, size) { return disk.get('size') ? utils.floor(size / disk.get('size') * 100, 2) : 0; }, hasErrors() { return this.props.disks.any((disk) => disk.get('volumes').any('validationError') ); }, isSavingPossible() { return !this.state.actionInProgress && this.hasChanges() && !this.hasErrors(); }, render() { var hasChanges = this.hasChanges(); var locked = this.isLocked(); var loadDefaultsDisabled = !!this.state.actionInProgress; var revertChangesDisabled = !!this.state.actionInProgress || !hasChanges; return (
{propertyName == 'size' ? utils.showDiskSize(diskMetaData[propertyName]) : diskMetaData[propertyName] }