Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
Add schedule cutover functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
mzazrivec committed Nov 27, 2019
1 parent 288ed33 commit 8cba3f9
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 107 deletions.
33 changes: 33 additions & 0 deletions app/javascript/react/screens/App/Overview/OverviewActions.js
Expand Up @@ -20,6 +20,7 @@ import {
HIDE_EDIT_PLAN_TITLE_MODAL,
V2V_RETRY_MIGRATION,
V2V_SCHEDULE_MIGRATION,
V2V_SCHEDULE_CUTOVER,
V2V_SET_MIGRATIONS_FILTER,
V2V_TOGGLE_SCHEDULE_MIGRATION_MODAL,
SHOW_PLAN_WIZARD_EDIT_MODE,
Expand Down Expand Up @@ -197,6 +198,38 @@ export const toggleScheduleMigrationModal = plan => ({
payload: plan
});

export const scheduleCutover = payload => dispatch =>
dispatch({
type: V2V_SCHEDULE_CUTOVER,
payload: new Promise((resolve, reject) => {
const {
scheduleTime,
plan: { id: planId }
} = payload;
let url = `/api/service_templates/${planId}`;
let body = {
action: 'edit',
resource: {
config_info: {
// FIXME: we need to suply full config info hash here from the plan object
warm_migration_cutover_datetime: null // FIXME: cutover date in iso-format
}
}
};
return API.post(url, body)
.then(response => {
resolve(response);
dispatch({
type: V2V_NOTIFICATION_ADD,
message: __('Migration cutover successfully scheduled'),
notificationType: 'success',
actionEnabled: false
});
})
.catch(e => reject(e));
})
});

export const scheduleMigration = payload => dispatch =>
dispatch({
type: V2V_SCHEDULE_MIGRATION,
Expand Down
Expand Up @@ -13,6 +13,7 @@ export const V2V_AUTO_SET_MIGRATIONS_FILTER = 'V2V_AUTO_SET_MIGRATIONS_FILTER';
export const V2V_RETRY_MIGRATION = 'V2V_RETRY_MIGRATION';
export const V2V_TOGGLE_SCHEDULE_MIGRATION_MODAL = 'V2V_TOGGLE_SCHEDULE_MIGRATION_MODAL';
export const V2V_SCHEDULE_MIGRATION = 'V2V_SCHEDULE_MIGRATION';
export const V2V_SCHEDULE_CUTOVER = 'V2V_SCHEDULE_CUTOVER';
export const V2V_EDIT_PLAN_REQUEST = 'V2V_EDIT_PLAN_REQUEST';
export const V2V_CANCEL_PLAN_REQUEST = 'V2V_CANCEL_PLAN_REQUEST';
export const SHOW_CONFIRM_MODAL = 'SHOW_CONFIRM_MODAL';
Expand Down
Expand Up @@ -18,6 +18,7 @@ import {
} from './helpers/inProgressHelpers';
import InProgressRow from './InProgressRow';
import ProgressBarTooltip from './ProgressBarTooltip';
import ScheduleMigrationButton from './ScheduleMigrationButton';

const MigrationInProgressListItem = ({
plan,
Expand All @@ -34,7 +35,9 @@ const MigrationInProgressListItem = ({
setMigrationsFilterAction,
cancelPlanRequestAction,
isCancellingPlanRequest,
requestsProcessingCancellation
requestsProcessingCancellation,
loading,
toggleScheduleMigrationModal
}) => {
const { requestsOfAssociatedPlan, mostRecentRequest } = getRequestsOfPlan({ plan, allRequestsWithTasks });
const waitingForConversionHost = isWaitingForConversionHost(mostRecentRequest);
Expand All @@ -52,6 +55,17 @@ const MigrationInProgressListItem = ({
{__('Initiating migration. This might take a few minutes.')}
</ListViewTable.InfoItem>
]}
/* FIXME: the schedule button is not here to stay, just temporary. We want to display schedule button for nicely running warm migrations only */
actions={
<div>
<ScheduleMigrationButton
loading={loading}
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
plan={plan}
isMissingMapping={!plan.infraMappingName}
/>
</div>
}
/>
);
}
Expand Down Expand Up @@ -84,9 +98,19 @@ const MigrationInProgressListItem = ({
</ListViewTable.InfoItem>
]}
actions={
<Button disabled={cancelButtonDisabled} onClick={onCancelClick}>
{__('Cancel Migration')}
</Button>
<div>
/* FIXME: the schedule button here is not to stay. We want to display the button for nicely running warm
migrations only. */
<ScheduleMigrationButton
loading={loading}
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
plan={plan}
isMissingMapping={!plan.infraMappingName}
/>
<Button disabled={cancelButtonDisabled} onClick={onCancelClick}>
{__('Cancel Migration')}
</Button>
</div>
}
/>
);
Expand Down Expand Up @@ -216,7 +240,9 @@ MigrationInProgressListItem.propTypes = {
setMigrationsFilterAction: PropTypes.func,
cancelPlanRequestAction: PropTypes.func,
isCancellingPlanRequest: PropTypes.bool,
requestsProcessingCancellation: PropTypes.array
requestsProcessingCancellation: PropTypes.array,
loading: PropTypes.bool,
toggleScheduleMigrationModal: PropTypes.func
};

export default MigrationInProgressListItem;
Expand Up @@ -118,7 +118,7 @@ class Migrations extends React.Component {
{activeFilter === MIGRATIONS_FILTERS.notStarted && (
<MigrationsNotStartedList
notStartedPlans={Immutable.asMutable(notStartedPlans, { deep: true })}
migrateClick={createTransformationPlanRequestClick}
scheduleMigrationNow={createTransformationPlanRequestClick}
loading={isCreatingTransformationPlanRequest}
redirectTo={redirectTo}
showConfirmModalAction={showConfirmModalAction}
Expand Down Expand Up @@ -155,11 +155,16 @@ class Migrations extends React.Component {
cancelPlanRequestAction={cancelPlanRequestAction}
isCancellingPlanRequest={isCancellingPlanRequest}
requestsProcessingCancellation={requestsProcessingCancellation}
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
scheduleMigrationModal={scheduleMigrationModal}
scheduleMigrationPlan={scheduleMigrationPlan}
scheduleMigration={scheduleMigration}
scheduleMigrationNow={createTransformationPlanRequestClick}
/>
)}
{activeFilter === MIGRATIONS_FILTERS.completed && (
<MigrationsCompletedList
migrateClick={createTransformationPlanRequestClick}
scheduleMigrationNow={createTransformationPlanRequestClick}
finishedTransformationPlans={Immutable.asMutable(finishedTransformationPlans, { deep: true })}
allRequestsWithTasks={allRequestsWithTasks}
retryClick={createTransformationPlanRequestClick}
Expand Down
Expand Up @@ -47,7 +47,7 @@ const MigrationsCompletedList = ({
fetchTransformationMappingsAction,
fetchTransformationMappingsUrl,
showEditPlanNameModalAction,
migrateClick
scheduleMigrationNow
}) => (
<React.Fragment>
<Grid.Col xs={12}>
Expand Down Expand Up @@ -340,15 +340,15 @@ const MigrationsCompletedList = ({
scheduleMigrationModal={scheduleMigrationModal}
scheduleMigrationPlan={scheduleMigrationPlan}
scheduleMigration={scheduleMigration}
migrateClick={migrateClick}
scheduleMigrationNow={scheduleMigrationNow}
fetchTransformationPlansAction={fetchTransformationPlansAction}
fetchTransformationPlansUrl={fetchTransformationPlansUrl}
/>
</React.Fragment>
);

MigrationsCompletedList.propTypes = {
migrateClick: PropTypes.func,
scheduleMigrationNow: PropTypes.func,
finishedTransformationPlans: PropTypes.array,
allRequestsWithTasks: PropTypes.array,
retryClick: PropTypes.func,
Expand All @@ -374,7 +374,7 @@ MigrationsCompletedList.propTypes = {
showEditPlanNameModalAction: PropTypes.func
};
MigrationsCompletedList.defaultProps = {
migrateClick: noop,
scheduleMigrationNow: noop,
finishedTransformationPlans: [],
retryClick: noop,
loading: false
Expand Down
@@ -1,10 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, Spinner, Toolbar } from 'patternfly-react';
import { noop, Grid, Spinner, Toolbar } from 'patternfly-react';
import ShowWizardEmptyState from '../../../common/ShowWizardEmptyState/ShowWizardEmptyState';
import MigrationInProgressListItem from './MigrationInProgressListItem';
import ListViewTable from '../../../common/ListViewTable/ListViewTable';
import ListViewToolbar from '../../../common/ListViewToolbar/ListViewToolbar';
import ScheduleMigrationModal from '../ScheduleMigrationModal/ScheduleMigrationModal';
import { MIGRATIONS_FILTER_TYPES, MIGRATIONS_IN_PROGRESS_SORT_FIELDS } from './MigrationsConstants';

const MigrationsInProgressList = ({
Expand All @@ -23,68 +24,85 @@ const MigrationsInProgressList = ({
setMigrationsFilterAction,
cancelPlanRequestAction,
isCancellingPlanRequest,
requestsProcessingCancellation
requestsProcessingCancellation,
toggleScheduleMigrationModal,
scheduleMigrationModal,
scheduleMigrationPlan,
scheduleMigration,
scheduleMigrationNow
}) => (
<Grid.Col xs={12} id="progress-bar-items">
<Spinner loading={!!loading}>
{activeTransformationPlans.length > 0 && allRequestsWithTasks.length > 0 ? (
<ListViewToolbar
filterTypes={MIGRATIONS_FILTER_TYPES}
sortFields={MIGRATIONS_IN_PROGRESS_SORT_FIELDS}
listItems={activeTransformationPlans}
>
{({
filteredSortedPaginatedListItems,
renderFilterControls,
renderSortControls,
renderActiveFilters,
renderPaginationRow
}) => (
<React.Fragment>
<Grid.Row>
<Toolbar>
{renderFilterControls()}
{renderSortControls()}
{renderActiveFilters(filteredSortedPaginatedListItems)}
</Toolbar>
</Grid.Row>
<ListViewTable className="plans-in-progress-list" style={{ marginTop: 10 }}>
{filteredSortedPaginatedListItems.items.map(plan => (
<MigrationInProgressListItem
plan={plan}
serviceTemplatePlaybooks={serviceTemplatePlaybooks}
allRequestsWithTasks={allRequestsWithTasks}
reloadCard={reloadCard}
key={plan.id}
redirectTo={redirectTo}
fetchTransformationPlansAction={fetchTransformationPlansAction}
fetchTransformationPlansUrl={fetchTransformationPlansUrl}
isFetchingTransformationPlans={isFetchingTransformationPlans}
isFetchingAllRequestsWithTasks={isFetchingAllRequestsWithTasks}
acknowledgeDeniedPlanRequestAction={acknowledgeDeniedPlanRequestAction}
isEditingPlanRequest={isEditingPlanRequest}
setMigrationsFilterAction={setMigrationsFilterAction}
cancelPlanRequestAction={cancelPlanRequestAction}
isCancellingPlanRequest={isCancellingPlanRequest}
requestsProcessingCancellation={requestsProcessingCancellation}
/>
))}
</ListViewTable>
{renderPaginationRow(filteredSortedPaginatedListItems)}
</React.Fragment>
)}
</ListViewToolbar>
) : (
<ShowWizardEmptyState
title={__('No Migration Plans In Progress')}
iconType="pf"
iconName="info"
description={<span>{__('There are no existing migration plans in an In Progress state.')}</span>}
/>
)}
</Spinner>
{/* TODO: scheduling modal here? maybe lift that out of CompletedList? */}
</Grid.Col>
<React.Fragment>
<Grid.Col xs={12} id="progress-bar-items">
<Spinner loading={!!loading}>
{activeTransformationPlans.length > 0 && allRequestsWithTasks.length > 0 ? (
<ListViewToolbar
filterTypes={MIGRATIONS_FILTER_TYPES}
sortFields={MIGRATIONS_IN_PROGRESS_SORT_FIELDS}
listItems={activeTransformationPlans}
>
{({
filteredSortedPaginatedListItems,
renderFilterControls,
renderSortControls,
renderActiveFilters,
renderPaginationRow
}) => (
<React.Fragment>
<Grid.Row>
<Toolbar>
{renderFilterControls()}
{renderSortControls()}
{renderActiveFilters(filteredSortedPaginatedListItems)}
</Toolbar>
</Grid.Row>
<ListViewTable className="plans-in-progress-list" style={{ marginTop: 10 }}>
{filteredSortedPaginatedListItems.items.map(plan => (
<MigrationInProgressListItem
plan={plan}
serviceTemplatePlaybooks={serviceTemplatePlaybooks}
allRequestsWithTasks={allRequestsWithTasks}
reloadCard={reloadCard}
key={plan.id}
redirectTo={redirectTo}
fetchTransformationPlansAction={fetchTransformationPlansAction}
fetchTransformationPlansUrl={fetchTransformationPlansUrl}
isFetchingTransformationPlans={isFetchingTransformationPlans}
isFetchingAllRequestsWithTasks={isFetchingAllRequestsWithTasks}
acknowledgeDeniedPlanRequestAction={acknowledgeDeniedPlanRequestAction}
isEditingPlanRequest={isEditingPlanRequest}
setMigrationsFilterAction={setMigrationsFilterAction}
cancelPlanRequestAction={cancelPlanRequestAction}
isCancellingPlanRequest={isCancellingPlanRequest}
requestsProcessingCancellation={requestsProcessingCancellation}
loading={loading}
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
/>
))}
</ListViewTable>
{renderPaginationRow(filteredSortedPaginatedListItems)}
</React.Fragment>
)}
</ListViewToolbar>
) : (
<ShowWizardEmptyState
title={__('No Migration Plans In Progress')}
iconType="pf"
iconName="info"
description={<span>{__('There are no existing migration plans in an In Progress state.')}</span>}
/>
)}
</Spinner>
</Grid.Col>
<ScheduleMigrationModal
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
scheduleMigrationModal={scheduleMigrationModal}
scheduleMigrationPlan={scheduleMigrationPlan}
scheduleMigration={scheduleMigration}
scheduleMigrationNow={scheduleMigrationNow}
fetchTransformationPlansAction={fetchTransformationPlansAction}
fetchTransformationPlansUrl={fetchTransformationPlansUrl}
/>
</React.Fragment>
);

MigrationsInProgressList.propTypes = {
Expand All @@ -103,13 +121,18 @@ MigrationsInProgressList.propTypes = {
setMigrationsFilterAction: PropTypes.func,
cancelPlanRequestAction: PropTypes.func,
isCancellingPlanRequest: PropTypes.bool,
requestsProcessingCancellation: PropTypes.array
requestsProcessingCancellation: PropTypes.array,
toggleScheduleMigrationModal: PropTypes.func,
scheduleMigrationModal: PropTypes.bool,
scheduleMigrationPlan: PropTypes.object,
scheduleMigration: PropTypes.func,
scheduleMigrationNow: PropTypes.func
};

MigrationsInProgressList.defaultProps = {
activeTransformationPlans: [],
serviceTemplatePlaybooks: [],
loading: false
scheduleMigrationNow: noop
};

export default MigrationsInProgressList;

0 comments on commit 8cba3f9

Please sign in to comment.