Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge "Add Recover deployment status button and actions"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Jul 25, 2018
2 parents 46d9e44 + 36df8e5 commit 07422a2
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 30 deletions.
89 changes: 77 additions & 12 deletions src/js/actions/DeploymentActions.js
Expand Up @@ -30,11 +30,16 @@ import {
START_UNDEPLOY_PENDING,
START_UNDEPLOY_SUCCESS,
UNDEPLOY_FAILED,
UNDEPLOY_SUCCESS
UNDEPLOY_SUCCESS,
RECOVER_DEPLOYMENT_STATUS_FAILED,
RECOVER_DEPLOYMENT_STATUS_SUCCESS,
RECOVER_DEPLOYMENT_STATUS_PENDING
} from '../constants/DeploymentConstants';
import { handleErrors } from './ErrorActions';
import MistralConstants from '../constants/MistralConstants';
import { sanitizeMessage } from '../utils';
import { startWorkflow } from './WorkflowActions';
import NotificationActions from './NotificationActions';
import SwiftApiService from '../services/SwiftApiService';

export const getDeploymentStatusPending = planName => ({
Expand Down Expand Up @@ -67,17 +72,13 @@ export const getDeploymentStatus = planName => dispatch => {
dispatch(getDeploymentStatusSuccess(planName, { status, message, type }));
})
.catch(error => {
if (error.name === 'SwiftApiError' && error.response.status === 404) {
dispatch(getDeploymentStatusSuccess(planName));
} else {
dispatch(
handleErrors(
error,
`Plan ${planName} deployment status could not be loaded`
)
);
dispatch(getDeploymentStatusFailed(planName, error.message));
}
dispatch(
handleErrors(
error,
`Plan ${planName} deployment status could not be loaded`
)
);
dispatch(getDeploymentStatusFailed(planName, error.message));
});
};

Expand Down Expand Up @@ -212,3 +213,67 @@ export const undeployFinished = execution => (
dispatch(undeploySuccess(planName, message));
}
};

export const recoverDeploymentStatusFailed = planName => ({
type: RECOVER_DEPLOYMENT_STATUS_FAILED,
payload: planName
});

export const recoverDeploymentStatusSuccess = planName => ({
type: RECOVER_DEPLOYMENT_STATUS_SUCCESS,
payload: planName
});

export const recoverDeploymentStatusPending = planName => ({
type: RECOVER_DEPLOYMENT_STATUS_PENDING,
payload: planName
});

export const recoverDeploymentStatus = planName => dispatch => {
dispatch(recoverDeploymentStatusPending(planName));
dispatch(
startWorkflow(
MistralConstants.RECOVER_DEPLOYMENT_STATUS,
{ container: planName },
execution => dispatch(recoverDeploymentStatusFinished(execution))
)
).catch(error => {
dispatch(
handleErrors(
error,
`Plan ${planName} deployment status could not be recovered`
)
);
dispatch(recoverDeploymentStatusFailed(planName));
});
};

export const recoverDeploymentStatusFinished = execution => (
dispatch,
getState,
{ getIntl }
) => {
const {
input: { container: planName },
output: { message, deployment_status: status },
state
} = execution;
if (state === 'ERROR') {
dispatch(
NotificationActions.notify({
title: `Plan ${planName} deployment status could not be recovered`,
message: sanitizeMessage(message)
})
);
dispatch(recoverDeploymentStatusFailed(planName));
} else {
dispatch(recoverDeploymentStatusSuccess(planName));
dispatch(
getDeploymentStatusSuccess(planName, {
status,
message,
type: execution.workflow_name
})
);
}
};
11 changes: 10 additions & 1 deletion src/js/actions/ZaqarActions.js
Expand Up @@ -33,7 +33,8 @@ import {
getDeploymentStatusSuccess,
deploymentFinished,
undeployFinished,
configDownloadMessage
configDownloadMessage,
recoverDeploymentStatusFinished
} from './DeploymentActions';
import NetworksActions from './NetworksActions';

Expand Down Expand Up @@ -201,6 +202,14 @@ export default {
break;
}

case MistralConstants.RECOVER_DEPLOYMENT_STATUS:
dispatch(
handleWorkflowMessage(payload.execution.id, execution =>
dispatch(recoverDeploymentStatusFinished(execution))
)
);
break;

case MistralConstants.PLAN_EXPORT: {
dispatch(
handleWorkflowMessage(payload.execution.id, execution =>
Expand Down
16 changes: 10 additions & 6 deletions src/js/components/deployment/DeploymentFailure.js
Expand Up @@ -22,6 +22,7 @@ import PropTypes from 'prop-types';
import React from 'react';

import DeleteStackButton from '../deployment_plan/DeleteStackButton';
import RecoverDeploymentStatusButton from '../deployment/RecoverDeploymentStatusButton';
import { deploymentStatusMessages } from '../../constants/DeploymentConstants';
import { getCurrentStack } from '../../selectors/stacks';
import {
Expand Down Expand Up @@ -57,12 +58,15 @@ class DeploymentFailure extends React.Component {
>
<p>{sanitizeMessage(message)}</p>
</InlineNotification>
{stack && (
<DeleteStackButton
deleteStack={undeployPlan.bind(this, planName)}
disabled={isPendingRequest}
/>
)}
<div>
{stack && (
<DeleteStackButton
deleteStack={undeployPlan.bind(this, planName)}
disabled={isPendingRequest}
/>
)}
{!stack && <RecoverDeploymentStatusButton />}
</div>
</ModalBody>
);
}
Expand Down
72 changes: 72 additions & 0 deletions src/js/components/deployment/RecoverDeploymentStatusButton.js
@@ -0,0 +1,72 @@
/**
* Copyright 2018 Red Hat 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 React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Button } from 'patternfly-react';
import { FormattedMessage, injectIntl } from 'react-intl';

import { defineMessages } from 'react-intl';
import { getCurrentPlanName } from '../../selectors/plans';
import { getCurrentPlanDeploymentStatusUI } from '../../selectors/deployment';
import { InlineLoader } from '../ui/Loader';
import { recoverDeploymentStatus } from '../../actions/DeploymentActions';

const messages = defineMessages({
recoveringDeploymentStatus: {
id: 'RecoverDeploymentStatusButton.recoveringDeploymentStatus',
defaultMessage: 'Recovering deployment status'
},
recoverDeploymentStatus: {
id: 'RecoverDeploymentStatusButton.recoverDeploymentStatus',
defaultMessage: 'Recover deployment status'
}
});
const RecoverDeploymentStatusButton = ({
currentPlanName,
intl: { formatMessage },
isPendingRequest,
recoverDeploymentStatus
}) => (
<Button
disabled={isPendingRequest}
onClick={() => recoverDeploymentStatus(currentPlanName)}
>
<InlineLoader
loaded={!isPendingRequest}
content={formatMessage(messages.recoveringDeploymentStatus)}
>
<FormattedMessage {...messages.recoverDeploymentStatus} />
</InlineLoader>
</Button>
);
RecoverDeploymentStatusButton.propTypes = {
currentPlanName: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
isPendingRequest: PropTypes.bool.isRequired,
recoverDeploymentStatus: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
currentPlanName: getCurrentPlanName(state),
isPendingRequest: getCurrentPlanDeploymentStatusUI(state).isPendingRequest
});
export default injectIntl(
connect(mapStateToProps, { recoverDeploymentStatus })(
RecoverDeploymentStatusButton
)
);
31 changes: 20 additions & 11 deletions src/js/components/deployment_plan/DeployStep.js
Expand Up @@ -19,7 +19,7 @@ import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import React from 'react';
import React, { Fragment } from 'react';

import DeploymentSuccess from './DeploymentSuccess';
import DeploymentFailure from './DeploymentFailure';
Expand All @@ -35,6 +35,8 @@ import {
} from '../../selectors/deployment';
import { InlineLoader } from '../ui/Loader';
import InlineNotification from '../ui/InlineNotification';
import { recoverDeploymentStatus } from '../../actions/DeploymentActions';
import RecoverDeploymentStatusButton from '../deployment/RecoverDeploymentStatusButton';

const messages = defineMessages({
requestingDeploy: {
Expand All @@ -52,7 +54,8 @@ export const DeployStep = ({
deploymentStatus,
deploymentStatusUIError,
intl: { formatMessage },
isPendingDeploymentRequest
isPendingDeploymentRequest,
recoverDeploymentStatus
}) => {
switch (deploymentStatus.status) {
case deploymentStates.DEPLOYING:
Expand All @@ -66,13 +69,16 @@ export const DeployStep = ({
return <DeploymentFailure planName={currentPlan.name} />;
case deploymentStates.UNKNOWN:
return (
<InlineNotification
title={formatMessage(deploymentStatusMessages.UNKNOWN, {
planName: currentPlan.name
})}
>
{deploymentStatusUIError}
</InlineNotification>
<Fragment>
<InlineNotification
title={formatMessage(deploymentStatusMessages.UNKNOWN, {
planName: currentPlan.name
})}
>
{deploymentStatusUIError}
</InlineNotification>
<RecoverDeploymentStatusButton />
</Fragment>
);
default:
return (
Expand All @@ -97,7 +103,8 @@ DeployStep.propTypes = {
deploymentStatus: PropTypes.object.isRequired,
deploymentStatusUIError: PropTypes.string,
intl: PropTypes.object,
isPendingDeploymentRequest: PropTypes.bool.isRequired
isPendingDeploymentRequest: PropTypes.bool.isRequired,
recoverDeploymentStatus: PropTypes.func.isRequired
};

const mapStateToProps = (state, props) => ({
Expand All @@ -107,4 +114,6 @@ const mapStateToProps = (state, props) => ({
.isPendingRequest
});

export default injectIntl(connect(mapStateToProps)(DeployStep));
export default injectIntl(
connect(mapStateToProps, { recoverDeploymentStatus })(DeployStep)
);
6 changes: 6 additions & 0 deletions src/js/constants/DeploymentConstants.js
Expand Up @@ -31,6 +31,12 @@ export const START_UNDEPLOY_SUCCESS = 'START_UNDEPLOY_SUCCESS';
export const START_UNDEPLOY_PENDING = 'START_UNDEPLOY_PENDING';
export const UNDEPLOY_FAILED = 'UNDEPLOY_FAILED';
export const UNDEPLOY_SUCCESS = 'UNDEPLOY_SUCCESS';
export const RECOVER_DEPLOYMENT_STATUS_FAILED =
'RECOVER_DEPLOYMENT_STATUS_FAILED';
export const RECOVER_DEPLOYMENT_STATUS_SUCCESS =
'RECOVER_DEPLOYMENT_STATUS_SUCCESS';
export const RECOVER_DEPLOYMENT_STATUS_PENDING =
'RECOVER_DEPLOYMENT_STATUS_PENDING';

export const deploymentStates = keyMirror({
UNDEPLOYED: null,
Expand Down
1 change: 1 addition & 0 deletions src/js/constants/MistralConstants.js
Expand Up @@ -29,6 +29,7 @@ export default {
CONFIG_DOWNLOAD_DEPLOY: 'tripleo.deployment.v1.config_download_deploy',
DEPLOYMENT_DEPLOY_PLAN: 'tripleo.deployment.v1.deploy_plan',
UNDEPLOY_PLAN: 'tripleo.deployment.v1.undeploy_plan',
RECOVER_DEPLOYMENT_STATUS: 'tripleo.deployment.v1.recover_deployment_status',
DOWNLOAD_LOGS: 'tripleo.plan_management.v1.download_logs',
HEAT_STACKS_LIST: 'tripleo.stack.v1._heat_stacks_list',
NETWORK_LIST: 'tripleo.plan_management.v1.list_networks',
Expand Down
6 changes: 6 additions & 0 deletions src/js/reducers/deploymentStatus.js
Expand Up @@ -32,6 +32,9 @@ import {
START_UNDEPLOY_SUCCESS,
UNDEPLOY_FAILED,
UNDEPLOY_SUCCESS,
RECOVER_DEPLOYMENT_STATUS_FAILED,
RECOVER_DEPLOYMENT_STATUS_SUCCESS,
RECOVER_DEPLOYMENT_STATUS_PENDING,
deploymentStates
} from '../constants/DeploymentConstants';
import {
Expand Down Expand Up @@ -127,11 +130,14 @@ export const deploymentStatusUI = (state = Map(), { type, payload }) => {
);
case START_DEPLOYMENT_PENDING:
case START_UNDEPLOY_PENDING:
case RECOVER_DEPLOYMENT_STATUS_PENDING:
return state.setIn([payload, 'isPendingRequest'], true);
case START_DEPLOYMENT_SUCCESS:
case START_DEPLOYMENT_FAILED:
case START_UNDEPLOY_SUCCESS:
case START_UNDEPLOY_FAILED:
case RECOVER_DEPLOYMENT_STATUS_SUCCESS:
case RECOVER_DEPLOYMENT_STATUS_FAILED:
return state.setIn([payload, 'isPendingRequest'], false);
default:
return state;
Expand Down

0 comments on commit 07422a2

Please sign in to comment.