1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-20 14:03:36 +03:00

B OpenNebula/one#6725: Fix problems in vrouters in Sunstone (#3230)

Signed-off-by: dcarracedo <dcarracedo@opennebula.io>
Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
This commit is contained in:
David 2024-09-18 13:49:05 +02:00 committed by GitHub
parent a95a94b5a6
commit b2fe5a3010
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 52 deletions

View File

@ -34,7 +34,7 @@ const NAME = {
const DESCRIPTION = {
name: 'description',
label: 'Description',
label: T.Description,
type: INPUT_TYPES.TEXT,
multiline: true,
validation: string().trim().default(''),
@ -64,7 +64,7 @@ const KEEPALIVEPASS = {
const VMNAME = {
name: 'vmname',
label: T.VmName,
tooltip: T.VmTemplateNameHelper,
tooltip: T.VmVrTemplateNameHelper,
type: INPUT_TYPES.TEXT,
validation: string()
.trim()
@ -107,15 +107,6 @@ const HOLD = {
grid: { md: 12 },
}
const PERSISTENT = {
name: 'persistent',
label: T.InstantiateAsPersistent,
type: INPUT_TYPES.SWITCH,
tooltip: T.InstantiateAsPersistentConcept,
validation: boolean().default(() => false),
grid: { md: 12 },
}
export const FIELDS = [
NAME,
DESCRIPTION,
@ -124,7 +115,6 @@ export const FIELDS = [
VMNAME,
INSTANCES,
HOLD,
PERSISTENT,
]
export const SCHEMA = getObjectSchemaFromFields(FIELDS)

View File

@ -47,8 +47,8 @@ const NicCard = ({ info = {}, removeNic, selectNic, active } = {}) => {
nicId,
VROUTER_MANAGEMENT: management,
autonetworkselect,
sshconnection,
rdpconnection,
SSH: sshconnection,
RDP: rdpconnection,
} = info
return (

View File

@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { mixed, number, boolean } from 'yup'
import { mixed, boolean, array, string } from 'yup'
import { VNetworksTable, SecurityGroupsTable } from 'client/components/Tables'
import { getObjectSchemaFromFields } from 'client/utils'
import { getObjectSchemaFromFields, REG_V4, REG_V6 } from 'client/utils'
import { T, INPUT_TYPES } from 'client/constants'
const NETWORK = {
name: 'network_id',
name: 'NETWORK_ID',
label: T.Network,
type: INPUT_TYPES.TABLE,
cy: 'network',
@ -36,17 +35,21 @@ const NETWORK = {
}
const RDP = {
name: 'rdpconnection',
name: 'RDP',
label: T.RdpConnection,
type: INPUT_TYPES.SWITCH,
validation: boolean().default(() => false),
validation: boolean()
.yesOrNo()
.default(() => false),
grid: { md: 6 },
}
const SSH = {
name: 'sshconnection',
name: 'SSH',
label: T.SshConnection,
type: INPUT_TYPES.SWITCH,
validation: boolean().default(() => false),
validation: boolean()
.yesOrNo()
.default(() => false),
grid: { md: 6 },
}
@ -54,15 +57,15 @@ const FORCEIPV4 = {
name: 'IP',
label: T.VirtualRouterNICForceIpv4,
type: INPUT_TYPES.TEXT,
validation: number()
.min(7) // Shortest possible IPv4
.max(16) // Longest possible
validation: string()
.trim()
.matches(REG_V4, { message: T.InvalidIPv4 })
.default(() => undefined),
grid: { md: 6 },
}
const FLOATINGIP = {
name: 'floating_ip',
name: 'FLOATING_IP',
label: T.VirtualRouterNICFloatingIP,
type: INPUT_TYPES.CHECKBOX,
validation: boolean().yesOrNo(),
@ -73,9 +76,9 @@ const FORCEIPV6 = {
name: 'IP6',
label: T.VirtualRouterNICForceIpv6,
type: INPUT_TYPES.TEXT,
validation: number()
.min(7)
.max(39)
validation: string()
.trim()
.matches(REG_V6, { message: T.InvalidIPv6 })
.default(() => undefined),
grid: { md: 6 },
}
@ -89,7 +92,7 @@ const MANAGEMENINTERFACE = {
}
const SECURITY_GROUPS = {
name: 'secgroup',
name: 'SECURITY_GROUPS',
label: T.SecurityGroups,
type: INPUT_TYPES.TABLE,
cy: 'secgroup',
@ -115,4 +118,4 @@ export const FIELDS = [
SECURITY_GROUPS,
]
export const SCHEMA = getObjectSchemaFromFields(FIELDS)
export const SCHEMA = array().of(getObjectSchemaFromFields(FIELDS))

View File

@ -42,12 +42,12 @@ const Content = () => {
append,
remove,
} = useFieldArray({
name: `${STEP_ID}.NIC`,
name: `${STEP_ID}`,
})
const watchedNicsArray = useWatch({
control,
name: `${STEP_ID}.NIC`,
name: `${STEP_ID}`,
})
const handleAddnewNic = () => {
@ -92,11 +92,11 @@ const Content = () => {
) : (
<FormWithSchema
legend={Tr(T.VirtualRouterNICNetworkConfiguration)}
key={`${STEP_ID}-NIC-${activeNic}`}
key={`${STEP_ID}-${activeNic}`}
cy={STEP_ID}
fields={FIELDS}
saveState={true}
id={`${STEP_ID}.NIC.${activeNic}`}
id={`${STEP_ID}.${activeNic}`}
/>
),
[nics, activeNic]

View File

@ -77,23 +77,33 @@ const Steps = createSteps(
)
},
transformBeforeSubmit: (formData, vmTemplate) => {
const { [BASIC_ID]: { name, instances, hold, persistent, vmname } = {} } =
const { [BASIC_ID]: { name, instances, hold, vmname } = {} } =
formData ?? {}
const selectedTemplateID = formData?.template_selection?.vmTemplate
delete formData?.template_selection
const templates = [...new Array(instances)].map((__, idx) => ({
id: vmTemplate?.ID ?? selectedTemplateID,
vrname: name,
name: vmname?.replace(/%idx/gi, idx), // VM NAME
number: instances,
pending: hold, // start on hold
persistent: persistent,
...(selectedTemplateID && { initiateFromSelection: true }),
...formData,
}))
// Delete nic id
formData.networking.forEach((nic) => {
delete nic.nicId
})
const templates = [
{
id: vmTemplate?.ID ?? selectedTemplateID,
vrname: name,
name: vmname
? vmname.includes('%i')
? vmname
: vmname + '-%i'
: undefined,
number: instances,
pending: hold, // start on hold
...(selectedTemplateID && { initiateFromSelection: true }),
...formData,
},
]
return templates
},

View File

@ -1107,6 +1107,10 @@ module.exports = {
Defaults to 'template name-<vmid>' when empty.
When creating several VMs, the wildcard %%idx will be
replaced with a number starting from 0`,
VmVrTemplateNameHelper: `
Defaults to 'template name-<vmid>' when empty.
When creating several VMs, the wildcard %%i will be
replaced with a number starting from 0`,
NumberOfInstances: 'Number of instances',
NumberOfVms: 'Number of VMs',
MakeTemplateAvailableForVROnly:

View File

@ -20,7 +20,6 @@ import { useGeneralApi } from 'client/features/General'
import { useGetGroupsQuery } from 'client/features/OneApi/group'
import { useGetUsersQuery } from 'client/features/OneApi/user'
import { useGetTemplateQuery } from 'client/features/OneApi/vmTemplate'
import { convertKeysToCase } from 'client/utils'
import {
useInstantiateVRouterTemplateMutation,
@ -76,20 +75,40 @@ function InstantiateVrTemplate() {
const promises = templates.map(async (t) => {
t.template = jsonToXml(t)
/**
* In allocate request template send only the following info:
* - Name - Name of the vrouter
* - Description - Description of the vrouter
* - Keep alive ID
* - Keep alive password
* - NICS
*/
const allocationResult = await allocate({
template: jsonToXml({
NAME: t.vrname,
...(t?.networking?.NIC
? { NIC: convertKeysToCase(t.networking.NIC, false) }
: {}),
DESCRIPTION: t.general?.description,
KEEPALIVED_ID: t.general?.keepaliveid,
KEEPALIVED_PASSWORD: t.general?.keepalivepass,
NIC: t.networking,
}),
}).unwrap()
/**
* In instantiate request send only the following info:
* - id - If of the vrouter (created in the previous allocate request)
* - templateId - Id of the vrouter template
* - number - Number of virtual machines that are gonna be instantiated
* - pending - Start virtual machines on hold state
* - template - XML template only with the user inputs
*/
return instantiate({
...t,
fromPostbody: t?.initiateFromSelection,
id: allocationResult,
templateId: templateId ?? parseInt(t?.id, 10),
...(t?.initiateFromSelection && { fromPostbody: true }),
number: t?.number,
name: t?.name,
pending: t?.pending,
template: jsonToXml(t?.user_inputs),
}).unwrap()
})