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

validate template sources with missing DataVolume #526

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/components/TemplateSource/TemplateSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ import { PROVISION_SOURCE_URL } from '../../constants';
import { getId } from '../../selectors';
import { prefixedId } from '../../utils/utils';

const Type = ({ type, source, id, isInline }) => (
<div id={id} title={source} className={isInline ? 'kubevirt-template-source__overlay' : ''}>
const Type = ({ type, source, error, id, isInline }) => (
<div id={id} title={source || error} className={isInline ? 'kubevirt-template-source__overlay' : ''}>
{type}
</div>
);

Type.propTypes = {
type: PropTypes.string.isRequired,
error: PropTypes.string,
source: PropTypes.string,
id: PropTypes.string,
isInline: PropTypes.bool,
};

Type.defaultProps = {
error: undefined,
source: undefined,
id: undefined,
isInline: false,
Expand Down Expand Up @@ -54,22 +56,22 @@ Source.defaultProps = {
export const TemplateSource = ({ template, dataVolumes, detailed }) => {
const provisionSource = getTemplateProvisionSource(template, dataVolumes);

if (!provisionSource) {
if (!provisionSource || !provisionSource.type) {
return '---';
}

const { type, source } = provisionSource;
const { type, source, error } = provisionSource;
const id = getId(template);
const typeId = prefixedId(id, 'type');
const sourceId = prefixedId(id, 'source');

if (!detailed) {
return <Type id={typeId} type={type} source={source} isInline />;
return <Type id={typeId} type={type} source={source} error={error} isInline />;
}

return (
<React.Fragment>
<Type id={typeId} type={type} source={source} />
<Type id={typeId} type={type} source={source} error={error} />
<Source id={sourceId} type={type} source={source} />
</React.Fragment>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/Wizard/CreateVmWizard/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ export const DATA_VOLUME_SOURCE_PVC = 'datavolume-pvc';
export const VIRTUAL_MACHINES_KEY = 'virtualMachines';
export const CREATE_TEMPLATE_KEY = 'createTemplate';
export const TEMPLATES_KEY = 'templates';
export const DATAVOLUMES_KEY = 'dataVolumes';
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,10 @@ export const selectedUserTemplateUpdateCreator = (prevProps, prevState, props, s

// update provision source
const provisionSource = getTemplateProvisionSource(userTemplate, dataVolumes);
if (provisionSource) {
update[PROVISION_SOURCE_TYPE_KEY] = asValueObject(provisionSource.type);
update[PROVISION_SOURCE_TYPE_KEY] = asValueObject(
provisionSource && !provisionSource.error ? provisionSource.type : null
);
if (provisionSource && !provisionSource.error) {
const dataFieldName = provisionSourceDataFieldResolver[provisionSource.type];
if (dataFieldName) {
update[dataFieldName] = asValueObject(provisionSource.source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ Object {
"isHidden": Object {
"provisionSourceType": false,
},
"validation": null,
"value": undefined,
},
"workloadProfile": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
validateVmLikeEntityName,
validateURL,
validateMemory,
validateUserTemplate,
} from '../../../../utils/validations';
import { objectMerge } from '../../../../utils/utils';
import { settingsValue } from '../../../../k8s/selectors';
Expand All @@ -20,6 +21,7 @@ import {
PROVIDERS_DATA_KEY,
PROVISION_SOURCE_TYPE_KEY,
MEMORY_KEY,
USER_TEMPLATE_KEY,
} from '../constants';
import { NAMESPACE_MUST_BE_SELECTED } from '../../../../utils/strings';
import { isProviderValid, validateProvider } from '../providers';
Expand All @@ -44,6 +46,7 @@ const asVmSettingsValidator = validator => asGenericFieldValidator(asUpdateValid

const validateResolver = {
[NAME_KEY]: asVmSettingsValidator(validateVmLikeEntityName),
[USER_TEMPLATE_KEY]: validateUserTemplate,
[CONTAINER_IMAGE_KEY]: asVmSettingsValidator(validateContainer),
[IMAGE_URL_KEY]: asVmSettingsValidator(validateURL),
[PROVIDER_KEY]: validateProviderDropdown,
Expand Down
2 changes: 2 additions & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const PROVISION_SOURCE_CONTAINER = 'Container';
export const PROVISION_SOURCE_URL = 'URL';
export const PROVISION_SOURCE_IMPORT = 'Import';
export const PROVISION_SOURCE_CLONED_DISK = 'Cloned Disk'; // PVC or upload image to PVC
export const PROVISION_SOURCE_UNKNOWN_DATAVOLUME = 'Unknown DataVolume';
export const PROVISION_SOURCE_UNKNOWN_DATAVOLUME_SOURCE = 'Unknown DataVolume Source';

export const PVC_ACCESSMODE_RWO = 'ReadWriteOnce';
export const PVC_ACCESSMODE_RWM = 'ReadWriteMany';
Expand Down
16 changes: 14 additions & 2 deletions src/utils/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
PROVISION_SOURCE_CONTAINER,
PROVISION_SOURCE_URL,
PROVISION_SOURCE_CLONED_DISK,
PROVISION_SOURCE_UNKNOWN_DATAVOLUME,
PROVISION_SOURCE_UNKNOWN_DATAVOLUME_SOURCE,
} from '../constants';
import { TemplateModel } from '../models';
import { DATA_VOLUME_SOURCE_URL, DATA_VOLUME_SOURCE_PVC } from '../components/Wizard/CreateVmWizard/constants';
Expand Down Expand Up @@ -146,12 +148,22 @@ export const getTemplateProvisionSource = (template, dataVolumes) => {
source: `${source.namespace}/${source.name}`,
};
default:
return null;
return {
type: PROVISION_SOURCE_UNKNOWN_DATAVOLUME_SOURCE,
error: `Datavolume ${bootVolume.dataVolume.name} does not have a supported source.`,
};
}
} else {
return {
type: PROVISION_SOURCE_UNKNOWN_DATAVOLUME,
error: `Datavolume ${bootVolume.dataVolume.name} does not exist.`,
};
}
}
}
return null;
return {
error: `No bootable device found.`,
};
};

export const retrieveVmTemplate = (k8sGet, vm) =>
Expand Down
20 changes: 19 additions & 1 deletion src/utils/validations.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ import {

import { parseUrl } from './utils';

import { VALIDATION_ERROR_TYPE, METALKUBE_CONTROLLER_PROTOCOLS } from '../constants';
import { VALIDATION_ERROR_TYPE, METALKUBE_CONTROLLER_PROTOCOLS, TEMPLATE_TYPE_VM } from '../constants';
import { getName, getNamespace } from '../selectors';
import {
CREATE_TEMPLATE_KEY,
DATAVOLUMES_KEY,
NAMESPACE_KEY,
TEMPLATES_KEY,
VIRTUAL_MACHINES_KEY,
} from '../components/Wizard/CreateVmWizard/constants';
import { getTemplate, getTemplateProvisionSource } from './templates';

export const isPositiveNumber = value => value && value.toString().match(/^[1-9]\d*$/);

Expand Down Expand Up @@ -84,6 +86,22 @@ export const validateVmLikeEntityName = (value, vmSettings, props) => {
);
};

export const validateUserTemplate = (userTemplateKey, vmSettings, props) => {
const userTemplateName = get(vmSettings, [userTemplateKey, 'value']);
const userTemplate =
userTemplateName &&
getTemplate(props[TEMPLATES_KEY], TEMPLATE_TYPE_VM).find(template => getName(template) === userTemplateName);

const provisionSource = userTemplate && getTemplateProvisionSource(userTemplate, props[DATAVOLUMES_KEY]);

return {
validation:
provisionSource && provisionSource.error
? getValidationObject(`Could not select Provision Source. ${provisionSource.error}`)
: null,
};
};

export const validateMemory = value => {
if (!value) {
return getValidationObject(EMPTY_ERROR);
Expand Down