Add Prepare Container Images step

Introduces Prepare Container Images as Step 5 in deployment plan
page and includes container images configuration summary based
on ContainerImagePrepare parameter

Story: 2004509
Task: 28233
Change-Id: I0f9eb020da5c60a90bebc8999dc888be362292d8
This commit is contained in:
Jiri Tomasek 2018-11-20 10:00:09 +01:00
parent 97afdda125
commit 31c7b4ed26
4 changed files with 257 additions and 5 deletions

View File

@ -0,0 +1,67 @@
/**
* 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, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { Loader } from '../ui/Loader';
import ContainerImagesConfigurationSummary from './ContainerImagesConfigurationSummary';
const messages = defineMessages({
editConfigurationLink: {
id: 'ConfigureContainerImagesStep.editConfigurationLink',
defaultMessage: 'Edit Configuration'
},
loadingImagesConfiguration: {
id: 'ConfigureContainerImagesStep.loadingImagesConfiguration',
defaultMessage: 'Loading images configuration...'
}
});
const ConfigureContainerImagesStep = ({
planName,
intl: { formatMessage },
isFetchingParameters,
containerImagePrepareParameterSeed
}) => (
<Fragment>
<Loader
loaded={!isFetchingParameters}
content={formatMessage(messages.loadingImagesConfiguration)}
>
<ContainerImagesConfigurationSummary
containerImagePrepareParameterSeed={containerImagePrepareParameterSeed}
/>
</Loader>
<Link
className="btn btn-default"
id="ConfigureContainerImagesStep__EditConfigurationLink"
to={`/plans/${planName}/container-images`}
>
<FormattedMessage {...messages.editConfigurationLink} />
</Link>
</Fragment>
);
ConfigureContainerImagesStep.propTypes = {
containerImagePrepareParameterSeed: PropTypes.object.isRequired,
intl: PropTypes.object.isRequired,
isFetchingParameters: PropTypes.bool.isRequired,
planName: PropTypes.string.isRequired
};
export default injectIntl(ConfigureContainerImagesStep);

View File

@ -0,0 +1,117 @@
/**
* 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, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
const messages = defineMessages({
editConfigurationLink: {
id: 'ConfigureContainerImagesStep.editConfigurationLink',
defaultMessage: 'Edit Configuration'
},
loadingImagesConfiguration: {
id: 'ConfigureContainerImagesStep.loadingImagesConfiguration',
defaultMessage: 'Loading images configuration...'
},
namespaceLabel: {
id: 'ContainerImagesConfigurationSummary.namespaceLabel',
defaultMessage: 'Image Template'
},
tagFromLabelLabel: {
id: 'ContainerImagesConfigurationSummary.tagFromLabelLabel',
defaultMessage: 'Tag from Label'
},
pushDestinationLabel: {
id: 'ContainerImagesConfigurationSummary.pushDestinationLabel',
defaultMessage: 'Push Destination'
},
pushDestinationUndercloud: {
id: 'ContainerImagesConfigurationSummary.pushDestinationUndercloud',
defaultMessage: 'Undercloud image registry'
},
containerImagesNotConfiguredYet: {
id: 'ContainerImagesConfigurationSummary.containerImagesNotConfiguredYet',
defaultMessage: 'Container images are not configured yet'
}
});
const ContainerImagesConfigurationSummary = ({
containerImagePrepareParameterSeed,
intl: { formatMessage }
}) => {
if (Object.keys(containerImagePrepareParameterSeed).length > 0) {
const {
push_destination,
tag_from_label,
namespace,
name_prefix,
name_suffix,
tag
} = containerImagePrepareParameterSeed;
return (
<dl className="dl-horizontal">
{namespace && (
<Fragment>
<strong>
<FormattedMessage {...messages.namespaceLabel} />
{': '}
</strong>
<span>{`${namespace}/${name_prefix &&
name_prefix}<IMAGE-NAME>${name_suffix && name_suffix}${tag &&
':' + tag}`}</span>
<br />
</Fragment>
)}
{push_destination && (
<Fragment>
<strong>
<FormattedMessage {...messages.pushDestinationLabel} />
{': '}
</strong>
<span>
{push_destination === true
? formatMessage(messages.pushDestinationUndercloud)
: push_destination}
</span>
<br />
</Fragment>
)}
{tag_from_label && (
<Fragment>
<strong>
<FormattedMessage {...messages.tagFromLabelLabel} />
{': '}
</strong>
<span>{tag_from_label}</span>
</Fragment>
)}
</dl>
);
} else {
return (
<p>
<FormattedMessage {...messages.containerImagesNotConfiguredYet} />
</p>
);
}
};
ContainerImagesConfigurationSummary.propTypes = {
containerImagePrepareParameterSeed: PropTypes.object.isRequired,
intl: PropTypes.object.isRequired
};
export default injectIntl(ContainerImagesConfigurationSummary);

View File

@ -31,10 +31,12 @@ import {
getCurrentPlanDeploymentIsInProgress
} from '../../selectors/deployment';
import { getEnvironmentConfigurationSummary } from '../../selectors/environmentConfiguration';
import { getContainerImagePrepareParameterSeed } from '../../selectors/parameters';
import { getCurrentPlan } from '../../selectors/plans';
import { getDeploymentStatus } from '../../actions/DeploymentActions';
import ConfigurePlanStep from './ConfigurePlanStep';
import ConfigureNetworkStep from './ConfigureNetworkStep';
import ConfigureContainerImagesStep from './ConfigureContainerImagesStep';
import { DeploymentPlanStep } from './DeploymentPlanStep';
import DeployStep from './DeployStep';
import { fetchEnvironmentConfiguration } from '../../actions/EnvironmentConfigurationActions';
@ -66,6 +68,20 @@ const messages = defineMessages({
id: 'CurrentPlan.configureNetworkStepHeader',
defaultMessage: 'Configure Network'
},
configureContainerImagesStepHeader: {
id: 'CurrentPlan.configureContainerImagesStepHeader',
defaultMessage: 'Prepare Container Images'
},
configureContainerImagesStepTooltip: {
id: 'CurrentPlan.configureContainerImagesStepTooltip',
defaultMessage:
'Container images need to be pulled from an image registry which is reliably \
available to overcloud nodes. The three common options to serve images are \
to use the default registry, the registry available on the undercloud, or an \
independently managed registry. Use this step to configure where to pull images \
from, which local repository to push images to and how to discover the last \
versioned tag for each image.'
},
deployStepHeader: {
id: 'CurrentPlan.deployStepHeader',
defaultMessage: 'Deploy'
@ -96,7 +112,7 @@ const messages = defineMessages({
id: 'CurrentPlan.configureNetworkStepTooltip',
defaultMessage:
'This step lets user manage deployment networks, assign them to deployment roles, ' +
'and configure network interfaces'
'and configure network interfaces.'
},
deployStepTooltip: {
id: 'CurrentPlan.deploymentStepTooltip',
@ -124,6 +140,7 @@ class CurrentPlan extends React.Component {
render() {
const {
intl: { formatMessage },
containerImagePrepareParameterSeed,
currentPlan,
deploymentInProgress,
deploymentStatus,
@ -131,6 +148,7 @@ class CurrentPlan extends React.Component {
environmentConfigurationSummary,
environmentConfigurationLoaded,
isFetchingEnvironmentConfiguration,
isFetchingParameters,
fetchEnvironmentConfiguration
} = this.props;
@ -185,6 +203,21 @@ class CurrentPlan extends React.Component {
>
<ConfigureNetworkStep planName={currentPlanName} />
</DeploymentPlanStep>
<DeploymentPlanStep
title={formatMessage(messages.configureContainerImagesStepHeader)}
disabled={disableDeploymentSteps}
tooltip={formatMessage(
messages.configureContainerImagesStepTooltip
)}
>
<ConfigureContainerImagesStep
planName={currentPlanName}
isFetchingParameters={isFetchingParameters}
containerImagePrepareParameterSeed={
containerImagePrepareParameterSeed
}
/>
</DeploymentPlanStep>
<DeploymentPlanStep
title={formatMessage(messages.deployStepHeader)}
tooltip={formatMessage(messages.deployStepTooltip)}
@ -238,6 +271,7 @@ class CurrentPlan extends React.Component {
}
CurrentPlan.propTypes = {
containerImagePrepareParameterSeed: PropTypes.object.isRequired,
currentPlan: ImmutablePropTypes.record,
deploymentInProgress: PropTypes.bool.isRequired,
deploymentStatus: PropTypes.object.isRequired,
@ -248,8 +282,8 @@ CurrentPlan.propTypes = {
fetchParameters: PropTypes.func,
getDeploymentStatus: PropTypes.func.isRequired,
intl: PropTypes.object,
isFetchingEnvironmentConfiguration: PropTypes.bool,
isFetchingParameters: PropTypes.bool
isFetchingEnvironmentConfiguration: PropTypes.bool.isRequired,
isFetchingParameters: PropTypes.bool.isRequired
};
export function mapStateToProps(state, props) {
@ -262,7 +296,10 @@ export function mapStateToProps(state, props) {
environmentConfigurationSummary: getEnvironmentConfigurationSummary(state),
isFetchingEnvironmentConfiguration:
state.environmentConfiguration.isFetching,
isFetchingParameters: state.parameters.isFetching
isFetchingParameters: state.parameters.isFetching,
containerImagePrepareParameterSeed: getContainerImagePrepareParameterSeed(
state
)
};
}

View File

@ -20,7 +20,7 @@ import { List, Set } from 'immutable';
import { internalParameters } from '../constants/ParametersConstants';
import { getRole } from './roles';
import { getEnvironment } from './environmentConfiguration';
import { Resource } from '../immutableRecords/parameters';
import { Resource, Parameter } from '../immutableRecords/parameters';
const parameters = state => state.parameters.get('parameters');
const resources = state => state.parameters.get('resources');
@ -189,6 +189,37 @@ export const getResourceParametersDeep = createSelector(
).update(filterParameters(parameters))
);
/** Get ContainerImagePrepare parameter value. Used for container images configuration */
export const getContainerImagePrepareParameter = createSelector(
getParameters,
parameters =>
parameters.get('ContainerImagePrepare', new Parameter({ default: [] }))
);
/** Get seed values from ContainerImagePrepare parameter */
export const getContainerImagePrepareParameterSeed = createSelector(
getContainerImagePrepareParameter,
parameter => {
if (parameter.default[0]) {
const {
push_destination,
tag_from_label,
set: { namespace, name_prefix, name_suffix, tag }
} = parameter.default[0];
return {
push_destination,
tag_from_label,
namespace,
name_prefix,
name_suffix,
tag
};
} else {
return {};
}
}
);
/**
* Recursively extracts Parameter names from a Resource and it's nested Resources
*/