289 lines
13 KiB
JavaScript
289 lines
13 KiB
JavaScript
import { connect } from 'react-redux';
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import React from 'react';
|
|
|
|
import { getAllPlansButCurrent } from '../../selectors/plans';
|
|
import { getCurrentStack,
|
|
getCurrentStackDeploymentProgress,
|
|
getCurrentStackDeploymentInProgress } from '../../selectors/stacks';
|
|
import { getAvailableNodesByRole, getUnassignedAvailableNodes } from '../../selectors/nodes';
|
|
import { getEnvironmentConfigurationSummary } from '../../selectors/environmentConfiguration';
|
|
import { getCurrentPlan } from '../../selectors/plans';
|
|
import { getRoles } from '../../selectors/roles';
|
|
import ConfigurePlanStep from './ConfigurePlanStep';
|
|
import CurrentPlanActions from '../../actions/CurrentPlanActions';
|
|
import { DeploymentPlanStep } from './DeploymentPlanStep';
|
|
import DeployStep from './DeployStep';
|
|
import EnvironmentConfigurationActions from '../../actions/EnvironmentConfigurationActions';
|
|
import HardwareStep from './HardwareStep';
|
|
import PlansDropdown from './PlansDropdown';
|
|
import NodesActions from '../../actions/NodesActions';
|
|
import NoPlans from './NoPlans';
|
|
import NotificationActions from '../../actions/NotificationActions';
|
|
import PlanActions from '../../actions/PlansActions';
|
|
import StacksActions from '../../actions/StacksActions';
|
|
import stackStates from '../../constants/StacksConstants';
|
|
import RolesStep from './RolesStep';
|
|
import RolesActions from '../../actions/RolesActions';
|
|
import ValidationsActions from '../../actions/ValidationsActions';
|
|
|
|
const messages = defineMessages({
|
|
hardwareStepHeader: {
|
|
id: 'DeploymentPlan.hardwareStepHeader',
|
|
defaultMessage: 'Prepare Hardware'
|
|
},
|
|
configureRolesStepHeader: {
|
|
id: 'DeploymentPlan.configureRolesStepHeader',
|
|
defaultMessage: 'Configure Roles and Assign Nodes'
|
|
},
|
|
deploymentConfigurationStepHeader: {
|
|
id: 'DeploymentPlan.deploymentConfigurationStepHeader',
|
|
defaultMessage: 'Specify Deployment Configuration'
|
|
},
|
|
deployStepHeader: {
|
|
id: 'DeploymentPlan.deployStepHeader',
|
|
defaultMessage: 'Deploy'
|
|
},
|
|
hardwareStepTooltip: {
|
|
id: 'DeploymentPlan.hardwareStepTooltip',
|
|
defaultMessage: 'This step registers and introspects your nodes. Registration involves ' +
|
|
'defining the power management details of each node so that you so that the director can ' +
|
|
'control them during the introspection and provisioning stages. After registration, you ' +
|
|
'introspect the nodes, which identifies the hardware each node uses and builds a profile of ' +
|
|
'each node. After registration and introspection, you can assign these nodes into specific ' +
|
|
'roles in your overcloud.'
|
|
},
|
|
configurePlanStepTooltip: {
|
|
id: 'DeploymentPlan.configurePlanStepTooltip',
|
|
defaultMessage: 'This step allows you edit specific settings for the overcloud\'s network, ' +
|
|
'storage, and other certified plugins. Use this step to define your network isolation ' +
|
|
'configuration and your backend storage settings.'
|
|
},
|
|
configureRolesStepTooltip: {
|
|
id: 'DeploymentPlan.configureRolesStepTooltip',
|
|
defaultMessage: 'This step assigns and removes nodes from roles in your overcloud. On each ' +
|
|
'role\'s selection dialog, you can tag available nodes into the role or untag nodes already ' +
|
|
'assigned to the role. Click "Assign Nodes" for a particular role to open the selection ' +
|
|
'dialog and start assigning nodes. ' +
|
|
'You can also customize role-specific settings in this step. For example, you can compose ' +
|
|
'services on each role and customize specific parameters related to each role. Click the ' +
|
|
'pencil icon in the top-right corner of each role to see these role-specific settings'
|
|
},
|
|
deployStepTooltip: {
|
|
id: 'DeploymentPlan.deploymentStepTooltip',
|
|
defaultMessage: 'This step performs the deployment of the overcloud. Once the deployment ' +
|
|
'begins, the director tracks the progress and provides a report of each completed, running, ' +
|
|
'or failed step. When the deployment completes, the director displays the current overcloud ' +
|
|
'status and login details, which you use to interact with your overcloud. Click "Deploy" to ' +
|
|
'start the deployment.'
|
|
}
|
|
});
|
|
|
|
class DeploymentPlan extends React.Component {
|
|
componentDidMount() {
|
|
this.props.fetchStacks();
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
if (!nextProps.stacksLoaded) { this.props.fetchStacks(); }
|
|
this.postDeploymentValidationsCheck(nextProps.currentStack);
|
|
this.pollCurrentStack(nextProps.currentStack);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
clearTimeout(this.stackProgressTimeout);
|
|
}
|
|
|
|
pollCurrentStack(currentStack) {
|
|
if (currentStack) {
|
|
if (currentStack.stack_status.match(/PROGRESS/)) {
|
|
clearTimeout(this.stackProgressTimeout);
|
|
this.stackProgressTimeout = setTimeout(() => {
|
|
this.props.fetchStacks();
|
|
this.props.fetchStackResources(currentStack);
|
|
}, 20000);
|
|
}
|
|
}
|
|
}
|
|
|
|
postDeploymentValidationsCheck(nextStack) {
|
|
const { currentStack, currentPlan } = this.props;
|
|
const progressStates = [stackStates.UPDATE_IN_PROGRESS, stackStates.CREATE_IN_PROGRESS];
|
|
const successStates = [stackStates.UPDATE_COMPLETE, stackStates.CREATE_COMPLETE];
|
|
if (currentStack
|
|
&& nextStack
|
|
&& progressStates.includes(currentStack.stack_status)
|
|
&& successStates.includes(nextStack.stack_status)) {
|
|
this.props.runPostDeploymentValidations(currentPlan.name);
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const { formatMessage } = this.props.intl;
|
|
let children;
|
|
const currentPlanName = this.props.hasPlans ? this.props.currentPlan.name : undefined;
|
|
|
|
// Render children only when current plan is already selected
|
|
if (this.props.children && currentPlanName) {
|
|
children = React.cloneElement(this.props.children,
|
|
{currentPlanName: currentPlanName,
|
|
parentPath: '/' + this.props.route.path});
|
|
}
|
|
|
|
return (
|
|
<div className="row">
|
|
{this.props.hasPlans ? (
|
|
<div className="col-sm-12">
|
|
<div className="page-header page-header-bleed-right">
|
|
<h1>
|
|
{currentPlanName}
|
|
<PlansDropdown currentPlanName={currentPlanName}
|
|
plans={this.props.inactivePlans}
|
|
choosePlan={this.props.choosePlan}/>
|
|
</h1>
|
|
</div>
|
|
<ol className="deployment-step-list">
|
|
<DeploymentPlanStep title={formatMessage(messages.hardwareStepHeader)}
|
|
disabled={this.props.currentStackDeploymentInProgress}
|
|
tooltip={formatMessage(messages.hardwareStepTooltip)}>
|
|
<HardwareStep />
|
|
</DeploymentPlanStep>
|
|
<DeploymentPlanStep title={formatMessage(messages.deploymentConfigurationStepHeader)}
|
|
disabled={this.props.currentStackDeploymentInProgress}
|
|
tooltip={formatMessage(messages.configurePlanStepTooltip)}>
|
|
<ConfigurePlanStep
|
|
fetchEnvironmentConfiguration={this.props.fetchEnvironmentConfiguration}
|
|
summary={this.props.environmentConfigurationSummary}
|
|
planName={currentPlanName}
|
|
isFetching={this.props.isFetchingEnvironmentConfiguration}
|
|
loaded={this.props.environmentConfigurationLoaded}/>
|
|
</DeploymentPlanStep>
|
|
<DeploymentPlanStep title={formatMessage(messages.configureRolesStepHeader)}
|
|
disabled={this.props.currentStackDeploymentInProgress}
|
|
tooltip={formatMessage(messages.configureRolesStepTooltip)}>
|
|
<RolesStep availableNodesByRole={this.props.availableNodesByRole}
|
|
fetchNodes={this.props.fetchNodes}
|
|
fetchRoles={this.props.fetchRoles.bind(this, currentPlanName)}
|
|
isFetchingNodes={this.props.isFetchingNodes}
|
|
isFetchingRoles={this.props.isFetchingRoles}
|
|
roles={this.props.roles}
|
|
rolesLoaded={this.props.rolesLoaded}
|
|
unassignedAvailableNodes={this.props.unassignedAvailableNodes}/>
|
|
</DeploymentPlanStep>
|
|
<DeploymentPlanStep title={formatMessage(messages.deployStepHeader)}
|
|
tooltip={formatMessage(messages.deployStepTooltip)}>
|
|
<DeployStep
|
|
currentPlan={this.props.currentPlan}
|
|
currentStack={this.props.currentStack}
|
|
currentStackResources={this.props.currentStackResources}
|
|
currentStackResourcesLoaded={this.props.currentStackResourcesLoaded}
|
|
currentStackDeploymentProgress={this.props.currentStackDeploymentProgress}
|
|
deleteStack={this.props.deleteStack}
|
|
deployPlan={this.props.deployPlan}
|
|
fetchStackEnvironment={this.props.fetchStackEnvironment}
|
|
fetchStackResource={this.props.fetchStackResource}
|
|
isRequestingStackDelete={this.props.isRequestingStackDelete}
|
|
stacksLoaded={this.props.stacksLoaded}/>
|
|
</DeploymentPlanStep>
|
|
</ol>
|
|
</div>
|
|
) : (
|
|
<div className="col-sm-12">
|
|
<NoPlans/>
|
|
</div>
|
|
)}
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
DeploymentPlan.propTypes = {
|
|
availableNodesByRole: ImmutablePropTypes.map,
|
|
children: React.PropTypes.node,
|
|
choosePlan: React.PropTypes.func,
|
|
currentPlan: ImmutablePropTypes.record,
|
|
currentStack: ImmutablePropTypes.record,
|
|
currentStackDeploymentInProgress: React.PropTypes.bool,
|
|
currentStackDeploymentProgress: React.PropTypes.number.isRequired,
|
|
currentStackResources: ImmutablePropTypes.map,
|
|
currentStackResourcesLoaded: React.PropTypes.bool.isRequired,
|
|
deleteStack: React.PropTypes.func,
|
|
deployPlan: React.PropTypes.func,
|
|
environmentConfigurationLoaded: React.PropTypes.bool,
|
|
environmentConfigurationSummary: React.PropTypes.string,
|
|
fetchEnvironmentConfiguration: React.PropTypes.func,
|
|
fetchNodes: React.PropTypes.func,
|
|
fetchRoles: React.PropTypes.func,
|
|
fetchStackEnvironment: React.PropTypes.func,
|
|
fetchStackResource: React.PropTypes.func,
|
|
fetchStackResources: React.PropTypes.func.isRequired,
|
|
fetchStacks: React.PropTypes.func,
|
|
hasPlans: React.PropTypes.bool,
|
|
inactivePlans: ImmutablePropTypes.map,
|
|
intl: React.PropTypes.object,
|
|
isFetchingEnvironmentConfiguration: React.PropTypes.bool,
|
|
isFetchingNodes: React.PropTypes.bool,
|
|
isFetchingRoles: React.PropTypes.bool,
|
|
isRequestingStackDelete: React.PropTypes.bool,
|
|
notify: React.PropTypes.func,
|
|
roles: ImmutablePropTypes.map,
|
|
rolesLoaded: React.PropTypes.bool,
|
|
route: React.PropTypes.object,
|
|
runPostDeploymentValidations: React.PropTypes.func.isRequired,
|
|
stacksLoaded: React.PropTypes.bool.isRequired,
|
|
unassignedAvailableNodes: ImmutablePropTypes.map
|
|
};
|
|
|
|
export function mapStateToProps(state) {
|
|
return {
|
|
currentPlan: getCurrentPlan(state),
|
|
currentStack: getCurrentStack(state),
|
|
currentStackResources: state.stacks.resources,
|
|
currentStackResourcesLoaded: state.stacks.resourcesLoaded,
|
|
currentStackDeploymentInProgress: getCurrentStackDeploymentInProgress(state),
|
|
currentStackDeploymentProgress: getCurrentStackDeploymentProgress(state),
|
|
environmentConfigurationLoaded: state.environmentConfiguration.loaded,
|
|
environmentConfigurationSummary: getEnvironmentConfigurationSummary(state),
|
|
isFetchingEnvironmentConfiguration: state.environmentConfiguration.isFetching,
|
|
isFetchingNodes: state.nodes.get('isFetching'),
|
|
isFetchingRoles: state.roles.get('isFetching'),
|
|
isRequestingStackDelete: state.stacks.get('isRequestingStackDelete'),
|
|
hasPlans: !state.plans.get('all').isEmpty(),
|
|
inactivePlans: getAllPlansButCurrent(state),
|
|
availableNodesByRole: getAvailableNodesByRole(state),
|
|
roles: getRoles(state),
|
|
rolesLoaded: state.roles.get('loaded'),
|
|
stacksLoaded: state.stacks.get('isLoaded'),
|
|
unassignedAvailableNodes: getUnassignedAvailableNodes(state)
|
|
};
|
|
}
|
|
|
|
function mapDispatchToProps(dispatch) {
|
|
return {
|
|
choosePlan: planName => dispatch(CurrentPlanActions.choosePlan(planName)),
|
|
deleteStack: (stackName, stackId) => {
|
|
dispatch(StacksActions.deleteStack(stackName, stackId));
|
|
},
|
|
deployPlan: planName => dispatch(PlanActions.deployPlan(planName)),
|
|
fetchStackEnvironment: (stack) => dispatch(StacksActions.fetchEnvironment(stack)),
|
|
fetchEnvironmentConfiguration: (planName, parentPath) => {
|
|
dispatch(EnvironmentConfigurationActions.fetchEnvironmentConfiguration(planName, parentPath));
|
|
},
|
|
fetchNodes: () => dispatch(NodesActions.fetchNodes()),
|
|
fetchRoles: planName => dispatch(RolesActions.fetchRoles(planName)),
|
|
fetchStackResources: (stack) =>
|
|
dispatch(StacksActions.fetchResources(stack.stack_name, stack.id)),
|
|
fetchStackResource: (stack, resourceName) =>
|
|
dispatch(StacksActions.fetchResource(stack, resourceName)),
|
|
fetchStacks: () => dispatch(StacksActions.fetchStacks()),
|
|
notify: notification => dispatch(NotificationActions.notify(notification)),
|
|
runPostDeploymentValidations: planName => {
|
|
dispatch(ValidationsActions.runValidationGroups(['post-deployment'], planName));
|
|
}
|
|
};
|
|
}
|
|
|
|
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(DeploymentPlan));
|