Cleanup Nodes selectors

* unify and simplify selectors which work with node capabilities
* replace non selector getAssingedNodes with getAvailableNodesByRole
  selector
* fix available nodes selector, to filter on registeredNodes as
  deployed and maintenance nodes are not considered available for
  deployment

Closes-Bug: #1637131
Change-Id: Ib057129dd5f813801ee58a0f64218c7ed9ecf5c6
This commit is contained in:
Jiri Tomasek 2017-02-09 13:40:01 +01:00
parent 0237a8ae83
commit da08626267
6 changed files with 50 additions and 56 deletions

View File

@ -0,0 +1,5 @@
fixes:
- |
Fixes `bug 1637131 <https://bugs.launchpad.net/tripleo/+bug/1637131>`__
Available Nodes are now based on registeredNodes as Deployed
and Maintenance Nodes are not considered available for deployment

View File

@ -7,7 +7,7 @@ import { getAllPlansButCurrent } from '../../selectors/plans';
import { getCurrentStack,
getCurrentStackDeploymentProgress,
getCurrentStackDeploymentInProgress } from '../../selectors/stacks';
import { getAvailableNodes, getUnassignedAvailableNodes } from '../../selectors/nodes';
import { getAvailableNodesByRole, getUnassignedAvailableNodes } from '../../selectors/nodes';
import { getEnvironmentConfigurationSummary } from '../../selectors/environmentConfiguration';
import { getCurrentPlan } from '../../selectors/plans';
import { getRoles } from '../../selectors/roles';
@ -126,7 +126,7 @@ class DeploymentPlan extends React.Component {
</DeploymentPlanStep>
<DeploymentPlanStep title={formatMessage(messages.configureRolesStepHeader)}
disabled={this.props.currentStackDeploymentInProgress}>
<RolesStep availableNodes={this.props.availableNodes}
<RolesStep availableNodesByRole={this.props.availableNodesByRole}
fetchNodes={this.props.fetchNodes}
fetchRoles={this.props.fetchRoles.bind(this, currentPlanName)}
isFetchingNodes={this.props.isFetchingNodes}
@ -163,7 +163,7 @@ class DeploymentPlan extends React.Component {
}
DeploymentPlan.propTypes = {
availableNodes: ImmutablePropTypes.map,
availableNodesByRole: ImmutablePropTypes.map,
children: React.PropTypes.node,
choosePlan: React.PropTypes.func,
currentPlan: ImmutablePropTypes.record,
@ -215,7 +215,7 @@ export function mapStateToProps(state) {
isRequestingStackDelete: state.stacks.get('isRequestingStackDelete'),
hasPlans: !state.plans.get('all').isEmpty(),
inactivePlans: getAllPlansButCurrent(state),
availableNodes: getAvailableNodes(state),
availableNodesByRole: getAvailableNodesByRole(state),
roles: getRoles(state),
rolesLoaded: state.roles.get('loaded'),
stacksLoaded: state.stacks.get('isLoaded'),

View File

@ -7,10 +7,9 @@ import { Link } from 'react-router';
import React from 'react';
import { List, Map } from 'immutable';
import { getAvailableNodes,
import { getAvailableNodesByRole,
getUnassignedAvailableNodes,
getNodesOperationInProgress,
getAssignedNodes } from '../../selectors/nodes';
getNodesOperationInProgress } from '../../selectors/nodes';
import { getRoles } from '../../selectors/roles';
import { getCurrentPlan } from '../../selectors/plans';
import FormErrorList from '../ui/forms/FormErrorList';
@ -84,7 +83,7 @@ class NodesAssignment extends React.Component {
const role = this.props.roles.get(roleIdentifier);
const roleName = role ? role.title : roleIdentifier;
const nodesToAssign = this.props.unassignedAvailableNodes
.merge(getAssignedNodes(this.props.availableNodes, roleIdentifier))
.merge(this.props.availableNodesByRole.get(roleIdentifier))
.sortBy(node => node.get('uuid'));
return (
@ -126,7 +125,7 @@ class NodesAssignment extends React.Component {
}
NodesAssignment.propTypes = {
assignNodes: React.PropTypes.func.isRequired,
availableNodes: ImmutablePropTypes.map,
availableNodesByRole: ImmutablePropTypes.map,
currentPlan: ImmutablePropTypes.record,
fetchNodes: React.PropTypes.func.isRequired,
formErrors: ImmutablePropTypes.list.isRequired,
@ -145,7 +144,7 @@ NodesAssignment.defaultProps = {
function mapStateToProps(state) {
return {
availableNodes: getAvailableNodes(state),
availableNodesByRole: getAvailableNodesByRole(state),
currentPlan: getCurrentPlan(state),
isFetchingNodes: state.nodes.get('isFetching'),
nodesInProgress: state.nodes.get('nodesInProgress'),

View File

@ -2,7 +2,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import React from 'react';
import { getAssignedNodes } from '../../selectors/nodes';
import Loader from '../ui/Loader';
import RoleCard from './RoleCard';
@ -26,12 +25,6 @@ class Roles extends React.Component {
}
}
getAssignedNodes(availableNodes, roleName) {
return availableNodes.filter(
node => node.getIn(['properties', 'capabilities']).includes(`profile:${roleName}`)
);
}
renderRoleCards() {
return this.props.roles.map(role => {
return (
@ -40,8 +33,7 @@ class Roles extends React.Component {
title={role.title}
identifier={role.identifier}
fetchNodes={this.props.fetchNodes}
assignedNodesCount={getAssignedNodes(this.props.availableNodes,
role.identifier).size}
assignedNodesCount={this.props.availableNodesByRole.get(role.identifier).size}
availableNodesCount={this.props.unassignedAvailableNodes.size}/>
</div>
);
@ -65,7 +57,7 @@ class Roles extends React.Component {
}
}
Roles.propTypes = {
availableNodes: ImmutablePropTypes.map,
availableNodesByRole: ImmutablePropTypes.map,
fetchNodes: React.PropTypes.func.isRequired,
fetchRoles: React.PropTypes.func.isRequired,
intl: React.PropTypes.object,

View File

@ -17,14 +17,14 @@ const messages = defineMessages({
});
const RolesStep = ({ isFetchingNodes,
availableNodes,
unassignedAvailableNodes,
roles,
fetchRoles,
fetchNodes,
intl,
isFetchingRoles,
rolesLoaded }) => {
availableNodesByRole,
unassignedAvailableNodes,
roles,
fetchRoles,
fetchNodes,
intl,
isFetchingRoles,
rolesLoaded }) => {
return (
<div>
<p>
@ -38,7 +38,7 @@ const RolesStep = ({ isFetchingNodes,
</Loader>
</p>
<Roles roles={roles.toList().toJS()}
availableNodes={availableNodes}
availableNodesByRole={availableNodesByRole}
unassignedAvailableNodes={unassignedAvailableNodes}
fetchRoles={fetchRoles}
fetchNodes={fetchNodes}
@ -49,7 +49,7 @@ const RolesStep = ({ isFetchingNodes,
);
};
RolesStep.propTypes = {
availableNodes: ImmutablePropTypes.map.isRequired,
availableNodesByRole: ImmutablePropTypes.map.isRequired,
fetchNodes: React.PropTypes.func.isRequired,
fetchRoles: React.PropTypes.func.isRequired,
intl: React.PropTypes.object,

View File

@ -24,10 +24,8 @@ export const getNodesWithMacs = createSelector(
);
export const getRegisteredNodes = createSelector(
getNodesWithMacs, (nodes) => {
return nodes.filterNot( node => node.get('provision_state') === 'active' ||
node.get('maintenance') );
}
getNodesWithMacs, (nodes) =>
nodes.filterNot(node => node.get('provision_state') === 'active' || node.get('maintenance'))
);
/**
@ -35,7 +33,7 @@ export const getRegisteredNodes = createSelector(
*/
export const getProfilesList = createSelector(
getNodes, nodes => nodes.reduce((profiles, v, k) => {
const profile = parseNodeCapabilities(v.getIn(['properties', 'capabilities'])).profile;
const profile = _getNodeCapabilities(v).profile;
return profile ? profiles.push(profile) : profiles;
}, List()).sort()
);
@ -49,44 +47,36 @@ export const getAvailableNodeProfiles = createSelector(
);
export const getAvailableNodes = createSelector(
getNodesWithMacs, (nodes) => nodes.filter(node => node.get('provision_state') === 'available')
getRegisteredNodes, (nodes) => nodes.filter(node => node.get('provision_state') === 'available')
);
export const getAvailableNodesByRole = createSelector(
[getAvailableNodes, getRoles], (nodes, roles) =>
roles.map(role => nodes.filter(node => _getNodeCapabilities(node).profile === role.identifier))
);
export const getDeployedNodes = createSelector(
getNodesWithMacs, (nodes) => {
return nodes.filter( node => node.get('provision_state') === 'active' );
}
getNodesWithMacs, (nodes) =>
nodes.filter( node => node.get('provision_state') === 'active' )
);
export const getMaintenanceNodes = createSelector(
getNodesWithMacs, (nodes) => {
return nodes.filter( node => node.get('maintenance') );
}
getNodesWithMacs, (nodes) =>
nodes.filter(node => node.get('maintenance'))
);
export const getUnassignedAvailableNodes = createSelector(
getAvailableNodes, (availableNodes) => {
return availableNodes.filterNot(
node => node.getIn(['properties', 'capabilities'], '').match(/.*profile:([\w\-]+)/)
);
}
getAvailableNodes, (availableNodes) =>
availableNodes.filterNot(node => _getNodeCapabilities(node).profile)
);
/*
* booleam, returns true if there are any nodes with operation in progress
*/
export const getNodesOperationInProgress = createSelector(
nodesInProgress, (nodesInProgress) => {
return !nodesInProgress.isEmpty();
}
nodesInProgress, (nodesInProgress) => !nodesInProgress.isEmpty()
);
export const getAssignedNodes = (availableNodes, roleIdentifier) => {
return availableNodes.filter(
node => node.getIn(['properties', 'capabilities'], '').includes(`profile:${roleIdentifier}`)
);
};
/**
* Helper function to convert list of port uuids into map of actual ports
* @param ports - Map of ports to filter on
@ -94,3 +84,11 @@ export const getAssignedNodes = (availableNodes, roleIdentifier) => {
*/
const filterPorts = (ports) =>
portUUIDs => ports.filter((p, k) => portUUIDs.includes(k));
/**
* Helper function to get node capabilities object
* @param node
* @returns capabilities object
*/
const _getNodeCapabilities = (node) =>
parseNodeCapabilities(node.getIn(['properties', 'capabilities'], ''));