Forbid interfaces configuration for nodes with different networks
If selected nodes have different networks then UI should provide links to configuration of nodes with the same set of networks. Closes-Bug: #1588865 Change-Id: I0233ec8aaf9221ac84137ecb254010e7863e4122
This commit is contained in:
parent
f5954e6d40
commit
90de7ef447
|
@ -3661,6 +3661,15 @@ input[type=range] {
|
|||
|
||||
// Interfaces styles
|
||||
|
||||
.ifc-management-panel {
|
||||
@ifc-panel-indent: 5px;
|
||||
|
||||
.different-networks-alert a {
|
||||
display: block;
|
||||
margin-top: @ifc-panel-indent;
|
||||
}
|
||||
}
|
||||
|
||||
.ifc-list {
|
||||
.ifc-container {
|
||||
@base-ifc-indent: 5px;
|
||||
|
|
|
@ -458,7 +458,10 @@
|
|||
"dpdk_description": "The Data Plane Development Kit (DPDK) provides high-performance packet processing libraries and user space drivers.",
|
||||
"locked_dpdk_bond": "DPDK cannot be enabled because not all slave interfaces support it",
|
||||
"different_availability": "<Different Availability>",
|
||||
"availability_tooltip": "Some network interfaces do not support this feature, therefore, these properties will not change after saving."
|
||||
"availability_tooltip": "Some network interfaces do not support this feature, therefore, these properties will not change after saving.",
|
||||
"nodes_have_different_networks": "Interfaces of the selected nodes can not be configured in bulk. Configure them separately. The following nodes have different sets of networks:",
|
||||
"node_networks": "__count__ node has __networks__ networks",
|
||||
"node_networks_plural": "__count__ nodes have __networks__ networks"
|
||||
},
|
||||
"configure_disks": {
|
||||
"no_disks": "No unassigned disks available.",
|
||||
|
|
|
@ -109,13 +109,12 @@ var NodesTab = React.createClass({
|
|||
},
|
||||
componentWillReceiveProps(newProps) {
|
||||
var screen = this.getScreen(newProps);
|
||||
if (this.state.screen !== screen && this.checkScreenExists(screen)) {
|
||||
var screenOptions = this.getScreenOptions(newProps);
|
||||
var newState = {
|
||||
screen: screen,
|
||||
screenOptions: screenOptions,
|
||||
screenData: {}
|
||||
};
|
||||
var screenOptions = this.getScreenOptions(newProps);
|
||||
if (
|
||||
this.state.screen !== screen && this.checkScreenExists(screen) ||
|
||||
!_.isEqual(this.state.screenOptions, screenOptions)
|
||||
) {
|
||||
var newState = {screen, screenOptions, screenData: {}};
|
||||
if (this.shouldScreenDataBeLoaded(screen)) {
|
||||
this.setState(_.extend(newState, {loading: true}));
|
||||
this.loadScreenData(screen, screenOptions);
|
||||
|
|
|
@ -599,6 +599,23 @@ var EditNodeInterfacesScreen = React.createClass({
|
|||
return _.intersection(... _.map(interfaces, this.getAvailableBondingTypes));
|
||||
},
|
||||
render() {
|
||||
var nodesByNetworksMap = {};
|
||||
this.props.nodes.each((node) => {
|
||||
var networkNames = _.flatten(
|
||||
node.interfaces.map((ifc) => ifc.get('assigned_networks').pluck('name'))
|
||||
).sort();
|
||||
nodesByNetworksMap[networkNames] =
|
||||
_.union((nodesByNetworksMap[networkNames] || []), [node.id]);
|
||||
});
|
||||
if (_.size(nodesByNetworksMap) > 1) {
|
||||
return (
|
||||
<ErrorScreen
|
||||
{... _.pick(this.props, 'nodes', 'cluster')}
|
||||
nodesByNetworksMap={nodesByNetworksMap}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
var {nodes, interfaces} = this.props;
|
||||
var {interfacesByIndex, indexByInterface} = this.state;
|
||||
var nodeNames = nodes.pluck('name');
|
||||
|
@ -780,6 +797,59 @@ var EditNodeInterfacesScreen = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var ErrorScreen = React.createClass({
|
||||
render() {
|
||||
var {nodes, cluster, nodesByNetworksMap} = this.props;
|
||||
return (
|
||||
<div className='ifc-management-panel row'>
|
||||
<div className='title'>
|
||||
{i18n(
|
||||
ns + 'read_only_title',
|
||||
{count: nodes.length, name: nodes.pluck('name').join(', ')}
|
||||
)}
|
||||
</div>
|
||||
{_.size(nodesByNetworksMap) > 1 &&
|
||||
<div className='col-xs-12'>
|
||||
<div className='alert alert-danger different-networks-alert'>
|
||||
{i18n(ns + 'nodes_have_different_networks')}
|
||||
{_.map(nodesByNetworksMap, (nodeIds, networkNames) => {
|
||||
return (
|
||||
<a
|
||||
key={networkNames}
|
||||
className='no-leave-check'
|
||||
href={
|
||||
'#cluster/' + cluster.id + '/nodes/interfaces/' +
|
||||
utils.serializeTabOptions({nodes: nodeIds})
|
||||
}
|
||||
>
|
||||
{i18n(ns + 'node_networks', {
|
||||
count: nodeIds.length,
|
||||
networks: _.map(networkNames.split(','), (name) => i18n('network.' + name))
|
||||
.join(', ')
|
||||
})}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className='col-xs-12 page-buttons content-elements'>
|
||||
<div className='well clearfix'>
|
||||
<div className='btn-group'>
|
||||
<a
|
||||
className='btn btn-default'
|
||||
href={'#cluster/' + cluster.id + '/nodes'}
|
||||
>
|
||||
{i18n('cluster_page.nodes_tab.back_to_nodes_button')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var NodeInterface = React.createClass({
|
||||
statics: {
|
||||
target: {
|
||||
|
|
Loading…
Reference in New Issue