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 (