1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

B OpenNebula/one#6744: Fix placement expression formatting (#3258)

Signed-off-by: Victor Hansson <vhansson@opennebula.io>
(cherry picked from commit 60bfce4146bb6a701a47d99d12143d904ebd670e)
This commit is contained in:
vichansson 2024-10-14 18:15:40 +03:00 committed by Tino Vázquez
parent d486ee1ae4
commit 1f003cbcd5
No known key found for this signature in database
GPG Key ID: 14201E424D02047E
4 changed files with 94 additions and 28 deletions

View File

@ -51,6 +51,7 @@ const ToggleController = memo(
notNull = false,
readOnly = false,
onConditionChange,
defaultValue,
}) => {
const {
field: { ref, value: optionSelected, onChange, onBlur },
@ -76,6 +77,16 @@ const ToggleController = memo(
[onChange, onConditionChange, readOnly, notNull]
)
// Safe loading of default value
useEffect(() => {
if (
defaultValue &&
values?.some(({ text, value }) => [text, value]?.includes(defaultValue))
) {
onChange(defaultValue)
}
}, [])
return (
<FormControl fullWidth margin="dense">
{label && (
@ -127,6 +138,7 @@ ToggleController.propTypes = {
notNull: PropTypes.bool,
readOnly: PropTypes.bool,
onConditionChange: PropTypes.func,
defaultValue: PropTypes.any,
}
ToggleController.displayName = 'ToggleController'

View File

@ -34,15 +34,12 @@ import { transformXmlString } from 'client/models/Helper'
const addHypervisorRequirement = (schedRequirements, hypervisor) => {
// Regular expression pattern to match (HYPERVISOR=VALUE)
const regexPattern = /\(HYPERVISOR=(kvm|dummy|lxc|qemu)\)/
const regexPattern = /HYPERVISOR=(kvm|dummy|lxc|qemu)/
// If exists a condition with hypervisor, replace the type. If not, add the hypervisor type.
if (regexPattern.test(schedRequirements)) {
// Replace the matched pattern with the new hypervisor
return schedRequirements.replace(
regexPattern,
'(HYPERVISOR=' + hypervisor + ')'
)
return schedRequirements.replace(regexPattern, 'HYPERVISOR=' + hypervisor)
} else {
// Add the condition only
if (!hypervisor) {
@ -50,8 +47,8 @@ const addHypervisorRequirement = (schedRequirements, hypervisor) => {
}
return schedRequirements
? `(${schedRequirements}) & (HYPERVISOR=${hypervisor})`
: `(HYPERVISOR=${hypervisor})`
? `${schedRequirements} | HYPERVISOR=${hypervisor}`
: `HYPERVISOR=${hypervisor}`
}
}
@ -63,21 +60,26 @@ const HOST_REQ_FIELD = (isUpdate, modifiedFields, instantiate) => ({
type: INPUT_TYPES.TEXT,
dependOf: [
'$general.HYPERVISOR',
'$extra.CLUSTER_HOST_TABLE',
'$extra.PLACEMENT_CLUSTER_TABLE',
'$extra.PLACEMENT_HOST_TABLE',
'$extra.CLUSTER_HOST_TYPE',
],
watcher: (dependencies, { formContext }) => {
const [hypervisor, clusterHostTable, clusterHostType] = dependencies
const [hypervisor, clusterTable, hostTable, clusterHostType] = dependencies
const clusterHostTable = clusterHostType?.includes(T.Cluster)
? clusterTable
: hostTable
if (!hypervisor) {
return
}
const tableType = clusterHostType?.includes(T.Cluster) ? 'CLUSTER' : 'HOST'
const regexPattern = new RegExp(`\\b${tableType}_ID\\s*=\\s*(\\d+)`)
const tableType = clusterHostType?.includes(T.Cluster) ? 'CLUSTER_' : ''
const regexPattern = new RegExp(`\\b${tableType}ID\\s*=\\s*\\d+`)
const actualValue = formContext.getValues('extra.SCHED_REQUIREMENTS')
const parts = actualValue?.split('&')?.map((part) => part?.trim())
const parts = actualValue?.split('|')?.map((part) => part?.trim())
const matchedParts = parts?.filter((part) => regexPattern.test(part))
const nonMatchedParts = parts?.filter((part) => !regexPattern.test(part))
@ -98,7 +100,7 @@ const HOST_REQ_FIELD = (isUpdate, modifiedFields, instantiate) => ({
const newExpressions = clusterHostTable
?.filter((id) => !remainingIDs.includes(id))
.map((id) => `(${tableType}_ID = ${id})`)
.map((id) => `${tableType}ID = ${id}`)
const updatedParts = [
...(nonMatchedParts ?? []),
@ -106,11 +108,11 @@ const HOST_REQ_FIELD = (isUpdate, modifiedFields, instantiate) => ({
...(newExpressions ?? []),
]
const updatedValue = updatedParts?.join(' & ') ?? ''
const updatedValue = updatedParts?.join(' | ') ?? ''
// Check if the hypervisor condition already exists in the actualValue
const hasHypervisorCondition = actualValue?.includes(
`(HYPERVISOR=${hypervisor})`
`HYPERVISOR=${hypervisor}`
)
// Add the hypervisor condition only if it doesn't exist
@ -223,26 +225,47 @@ const DS_RANK_FIELD = {
const TABLE_TYPE = {
name: 'CLUSTER_HOST_TYPE',
type: INPUT_TYPES.TOGGLE,
values: () =>
arrayToOptions([T.SelectCluster, T.SelectHost], {
addEmpty: false,
}),
values: arrayToOptions([T.SelectCluster, T.SelectHost], {
addEmpty: false,
}),
validation: string()
.trim()
.required()
.default(() => T.Host),
.default(() => T.SelectCluster),
notNull: true,
defaultValue: T.SelectCluster,
grid: { xs: 12, md: 12 },
}
/** @type {Field} Cluster selection field */
const CLUSTER_HOST_TABLE = {
name: 'CLUSTER_HOST_TABLE',
const CLUSTER_TABLE = {
name: 'PLACEMENT_CLUSTER_TABLE',
dependOf: 'CLUSTER_HOST_TYPE',
type: INPUT_TYPES.TABLE,
Table: (tableType) =>
tableType?.includes(T.Cluster) ? ClustersTable : HostsTable,
Table: ClustersTable,
htmlType: (tableType) =>
!tableType?.includes(T.Cluster) && INPUT_TYPES.HIDDEN,
singleSelect: false,
fieldProps: {
preserveState: true,
},
validation: array(string().trim())
.required()
.default(() => undefined),
grid: { xs: 12, md: 12 },
}
/** @type {Field} Cluster selection field */
const HOST_TABLE = {
name: 'PLACEMENT_HOST_TABLE',
dependOf: 'CLUSTER_HOST_TYPE',
type: INPUT_TYPES.TABLE,
Table: HostsTable,
htmlType: (tableType) => !tableType?.includes(T.Host) && INPUT_TYPES.HIDDEN,
singleSelect: false,
fieldProps: {
preserveState: true,
},
validation: array(string().trim())
.required()
.default(() => undefined),
@ -269,7 +292,8 @@ const SECTIONS = (oneConfig, adminGroup, isUpdate, modifiedFields) => [
fields: disableFields(
[
TABLE_TYPE,
CLUSTER_HOST_TABLE,
CLUSTER_TABLE,
HOST_TABLE,
HOST_REQ_FIELD(isUpdate, modifiedFields),
HOST_POLICY_TYPE_FIELD,
HOST_RANK_FIELD,

View File

@ -25,6 +25,7 @@ import General, {
STEP_ID as GENERAL_ID,
} from 'client/components/Forms/VmTemplate/CreateForm/Steps/General'
import { T } from 'client/constants'
import { userInputsToArray } from 'client/models/Helper'
import { createSteps, getUnknownAttributes, decodeBase64 } from 'client/utils'
@ -95,8 +96,37 @@ const Steps = createSteps([General, ExtraConfiguration, CustomVariables], {
}
}
// Init placement
const schedRequirements = vmTemplate?.TEMPLATE?.SCHED_REQUIREMENTS
if (schedRequirements) {
objectSchema[EXTRA_ID].SCHED_REQUIREMENTS = schedRequirements
const parts = schedRequirements?.split(' | ')
const tableIds = parts?.reduce((ids, part) => {
if (part?.includes('ID')) {
const isCluster = part.toUpperCase().includes(T.Cluster.toUpperCase())
const tableId = isCluster ? T.Cluster : T.Host
const partId = part?.split(' = ')?.at(-1)?.trim()
if (!partId) return ids
;(ids[tableId] ??= []).push(partId)
}
return ids
}, {})
if (tableIds?.[T.Cluster]) {
objectSchema[EXTRA_ID].PLACEMENT_CLUSTER_TABLE = tableIds[T.Cluster]
}
if (tableIds?.[T.Host]) {
objectSchema[EXTRA_ID].PLACEMENT_HOST_TABLE = tableIds[T.Host]
}
}
const defaultType = T.SelectCluster
objectSchema[EXTRA_ID].CLUSTER_HOST_TYPE = defaultType
const knownTemplate = schema.cast(objectSchema, {
stripUnknown: true,
stripUnknown: false,
context: { ...vmTemplate, [EXTRA_ID]: vmTemplate.TEMPLATE },
})

View File

@ -197,8 +197,8 @@ module.exports = {
SelectDisk: 'Select disk',
SelectDockerHubTag: 'Select DockerHub image tag (default latest)',
SelectGroup: 'Select a group',
SelectHost: 'Select host',
SelectHosts: 'Select hosts',
SelectHost: 'Select Host',
SelectHosts: 'Select Hosts',
SelectMarketplace: 'Select Marketplace',
SelectNetwork: 'Select a network',
SelectVirtualNetworks: 'Select virtual networks',