mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
compute: vApps frontend support (#550)
Support for vApp VM deployment for VMware Backend PR - https://github.com/apache/cloudstack/pull/4250 Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> Co-authored-by: nvazquez <nicovazquez90@gmail.com> Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
8801446de1
commit
c97153515d
@ -43,7 +43,7 @@ export default {
|
||||
}
|
||||
return fields
|
||||
},
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'isready', 'passwordenabled', 'sshkeyenabled', 'directdownload', 'isextractable', 'isdynamicallyscalable', 'ispublic', 'isfeatured', 'crosszones', 'type', 'account', 'domain', 'created', 'url'],
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'isready', 'passwordenabled', 'sshkeyenabled', 'directdownload', 'deployasis', 'isextractable', 'isdynamicallyscalable', 'ispublic', 'isfeatured', 'crosszones', 'type', 'account', 'domain', 'created', 'url'],
|
||||
searchFilters: ['name', 'zoneid', 'tags'],
|
||||
related: [{
|
||||
name: 'vm',
|
||||
|
||||
@ -702,6 +702,7 @@
|
||||
"label.demote.project.owner.user": "Demote user to Regular role",
|
||||
"label.deleting.template": "Deleting template",
|
||||
"label.deny": "Deny",
|
||||
"label.deployasis":"Deploy As-Is",
|
||||
"label.deploymentplanner": "Deployment planner",
|
||||
"label.description": "Description",
|
||||
"label.destcidr": "Destination CIDR",
|
||||
@ -1142,6 +1143,7 @@
|
||||
"label.isvolatile": "Volatile",
|
||||
"label.item.listing": "Item listing",
|
||||
"label.items": "items",
|
||||
"label.i.accept.all.license.agreements": "I accept all license agreement",
|
||||
"label.japanese.keyboard": "Japanese keyboard",
|
||||
"label.keep": "Keep",
|
||||
"label.keep.colon": "Keep:",
|
||||
@ -1213,6 +1215,7 @@
|
||||
"label.ldap.group.name": "LDAP Group",
|
||||
"label.ldap.port": "LDAP port",
|
||||
"label.level": "Level",
|
||||
"label.license.agreements": "License agreements",
|
||||
"label.limit": "Limit",
|
||||
"label.limitcpuuse": "CPU Cap",
|
||||
"label.limits": "Configure Limits",
|
||||
@ -2869,6 +2872,7 @@
|
||||
"message.launch.zone.description": "Zone is ready to launch; please proceed to the next step.",
|
||||
"message.launch.zone.hint": "Configure network components and traffic including IP addresses.",
|
||||
"message.ldap.group.import": "All The users from the given group name will be imported",
|
||||
"message.license.agreements.not.accepted": "License agreements not accepted",
|
||||
"message.link.domain.to.ldap": "Enable autosync for this domain in LDAP",
|
||||
"message.listnsp.not.return.providerid": "error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID",
|
||||
"message.listview.subselect.multi": "(Ctrl/Cmd-click)",
|
||||
@ -2920,6 +2924,7 @@
|
||||
"message.number.zones": "<h2><span> # of </span> Zones</h2>",
|
||||
"message.outofbandmanagement.action.maintenance": "Warning host is in maintenance mode",
|
||||
"message.ovf.properties.available": "There are OVF properties available for customizing the selected appliance. Please edit the values accordingly.",
|
||||
"message.ovf.configurations": "OVF configurations available for the selected appliance. Please select the desired value. Incompatible compute offerings will get disbaled.",
|
||||
"message.password.has.been.reset.to": "Password has been reset to",
|
||||
"message.password.of.the.vm.has.been.reset.to": "Password of the VM has been reset to",
|
||||
"message.pending.projects.1": "You have pending project invitations:",
|
||||
@ -2945,6 +2950,7 @@
|
||||
"message.publicip.state.free": "The IP address is ready to be allocated.",
|
||||
"message.publicip.state.releasing": "The IP address is being released for other network elements and is not ready for allocation.",
|
||||
"message.question.are.you.sure.you.want.to.add": "Are you sure you want to add",
|
||||
"message.read.accept.license.agreements": "Please read and accept the terms for the license agreements.",
|
||||
"message.read.admin.guide.scaling.up": "Please read the dynamic scaling section in the admin guide before scaling up.",
|
||||
"message.recover.vm": "Please confirm that you would like to recover this VM.",
|
||||
"message.redirecting.region": "Redirecting to region...",
|
||||
@ -3021,6 +3027,7 @@
|
||||
"message.step.3.continue": "Please select a disk offering to continue",
|
||||
"message.step.4.continue": "Please select at least one network to continue",
|
||||
"message.step.4.desc": "Please select the primary network that your virtual instance will be connected to.",
|
||||
"message.step.license.agreements.continue": "Please aceept all license agreements to continue",
|
||||
"message.storage.traffic": "Traffic between CloudStack's internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs. Please configure storage traffic here.",
|
||||
"message.success.enable.saml.auth": "Successfully enabled SAML Authorization",
|
||||
"message.success.create.user": "Successfully created user",
|
||||
|
||||
@ -143,6 +143,32 @@
|
||||
:status="zoneSelected ? 'process' : 'wait'">
|
||||
<template slot="description">
|
||||
<div v-if="zoneSelected">
|
||||
<a-form-item v-if="zoneSelected && templateConfigurationExists">
|
||||
<span slot="label">
|
||||
{{ $t('label.configuration') }}
|
||||
<a-tooltip :title="$t('message.ovf.configurations')">
|
||||
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
v-decorator="[
|
||||
'templateConfiguration'
|
||||
]"
|
||||
defaultActiveFirstOption
|
||||
:placeholder="'Something'"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
@change="onSelectTemplateConfigurationId"
|
||||
>
|
||||
<a-select-option v-for="opt in templateConfigurations" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<span v-if="selectedTemplateConfiguration && selectedTemplateConfiguration.description">{{ selectedTemplateConfiguration.description }}</span>
|
||||
</a-form-item>
|
||||
<compute-offering-selection
|
||||
:compute-items="options.serviceOfferings"
|
||||
:row-count="rowCount.serviceOfferings"
|
||||
@ -150,11 +176,15 @@
|
||||
:value="serviceOffering ? serviceOffering.id : ''"
|
||||
:loading="loading.serviceOfferings"
|
||||
:preFillContent="dataPreFill"
|
||||
:minimum-cpunumber="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.cpunumber ? selectedTemplateConfiguration.cpunumber : 0"
|
||||
:minimum-cpuspeed="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.cpuspeed ? selectedTemplateConfiguration.cpuspeed : 0"
|
||||
:minimum-memory="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.memory ? selectedTemplateConfiguration.memory : 0"
|
||||
@select-compute-item="($event) => updateComputeOffering($event)"
|
||||
@handle-search-filter="($event) => handleSearchFilter('serviceOfferings', $event)"
|
||||
></compute-offering-selection>
|
||||
<compute-selection
|
||||
v-if="serviceOffering && serviceOffering.iscustomized"
|
||||
v-show="!templateConfigurationExists"
|
||||
cpunumber-input-decorator="cpunumber"
|
||||
cpuspeed-input-decorator="cpuspeed"
|
||||
memory-input-decorator="memory"
|
||||
@ -169,12 +199,12 @@
|
||||
@update-compute-cpuspeed="updateFieldValue"
|
||||
@update-compute-memory="updateFieldValue" />
|
||||
<span v-if="serviceOffering && serviceOffering.iscustomized">
|
||||
<a-form-item class="form-item-hidden" >
|
||||
<a-form-item class="form-item-hidden">
|
||||
<a-input v-decorator="['cpunumber']"/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="form-item-hidden"
|
||||
v-if="serviceOffering && !(serviceOffering.cpuspeed > 0)">
|
||||
v-if="(serviceOffering && !(serviceOffering.cpuspeed > 0))">
|
||||
<a-input v-decorator="['cpuspeed']"/>
|
||||
</a-form-item>
|
||||
<a-form-item class="form-item-hidden">
|
||||
@ -216,24 +246,55 @@
|
||||
:status="zoneSelected ? 'process' : 'wait'">
|
||||
<template slot="description">
|
||||
<div v-if="zoneSelected">
|
||||
<network-selection
|
||||
v-if="!networkId"
|
||||
:items="options.networks"
|
||||
:row-count="rowCount.networks"
|
||||
:value="networkOfferingIds"
|
||||
:loading="loading.networks"
|
||||
:zoneId="zoneId"
|
||||
:preFillContent="dataPreFill"
|
||||
@select-network-item="($event) => updateNetworks($event)"
|
||||
@handle-search-filter="($event) => handleSearchFilter('networks', $event)"
|
||||
></network-selection>
|
||||
<network-configuration
|
||||
v-if="networks.length > 0"
|
||||
:items="networks"
|
||||
:preFillContent="dataPreFill"
|
||||
@update-network-config="($event) => updateNetworkConfig($event)"
|
||||
@select-default-network-item="($event) => updateDefaultNetworks($event)"
|
||||
></network-configuration>
|
||||
<div v-if="vm.templateid && templateNics && templateNics.length > 0">
|
||||
<a-form-item
|
||||
v-for="(nic, nicIndex) in templateNics"
|
||||
:key="nicIndex"
|
||||
:v-bind="nic.name" >
|
||||
<span slot="label">
|
||||
{{ nic.elementName + ' - ' + nic.name }}
|
||||
<a-tooltip :title="nic.networkDescription">
|
||||
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
v-decorator="[
|
||||
'networkMap.nic-' + nic.InstanceID.toString(),
|
||||
{ initialValue: options.networks && options.networks.length > 0 ? options.networks[Math.min(nicIndex, options.networks.length - 1)].id : null }
|
||||
]"
|
||||
:placeholder="nic.networkDescription"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
>
|
||||
<a-select-option v-for="opt in options.networks" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<network-selection
|
||||
v-if="!networkId"
|
||||
:items="options.networks"
|
||||
:row-count="rowCount.networks"
|
||||
:value="networkOfferingIds"
|
||||
:loading="loading.networks"
|
||||
:zoneId="zoneId"
|
||||
:preFillContent="dataPreFill"
|
||||
@select-network-item="($event) => updateNetworks($event)"
|
||||
@handle-search-filter="($event) => handleSearchFilter('networks', $event)"
|
||||
></network-selection>
|
||||
<network-configuration
|
||||
v-if="networks.length > 0"
|
||||
:items="networks"
|
||||
:preFillContent="dataPreFill"
|
||||
@update-network-config="($event) => updateNetworkConfig($event)"
|
||||
@select-default-network-item="($event) => updateDefaultNetworks($event)"
|
||||
></network-configuration>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
@ -271,11 +332,11 @@
|
||||
<a-step
|
||||
:title="$t('label.ovf.properties')"
|
||||
:status="zoneSelected ? 'process' : 'wait'"
|
||||
v-if="vm.templateid && template.properties && template.properties.length > 0">
|
||||
v-if="vm.templateid && templateProperties && templateProperties.length > 0">
|
||||
<template slot="description">
|
||||
<div>
|
||||
<a-form-item
|
||||
v-for="(property, propertyIndex) in template.properties"
|
||||
v-for="(property, propertyIndex) in templateProperties"
|
||||
:key="propertyIndex"
|
||||
:v-bind="property.key" >
|
||||
<span slot="label">
|
||||
@ -287,43 +348,42 @@
|
||||
|
||||
<span v-if="property.type && property.type==='boolean'">
|
||||
<a-switch
|
||||
v-decorator="['properties.' + property.key, { initialValue: property.value==='TRUE'?true:false}]"
|
||||
v-decorator="['properties.' + escapePropertyKey(property.key), { initialValue: property.value==='TRUE'?true:false}]"
|
||||
:defaultChecked="property.value==='TRUE'?true:false"
|
||||
:placeholder="property.description"
|
||||
/>
|
||||
</span>
|
||||
<span v-else-if="property.type && (property.type==='int' || property.type==='real')">
|
||||
<a-input-number
|
||||
v-decorator="['properties.'+property.key]"
|
||||
v-decorator="['properties.'+ escapePropertyKey(property.key) ]"
|
||||
:defaultValue="property.value"
|
||||
:placeholder="property.description"
|
||||
:min="property.qualifiers && property.qualifiers.includes('MinValue') && property.qualifiers.includes('MaxValue')?property.qualifiers.split(',')[0].replace('MinValue(','').slice(0, -1):0"
|
||||
:max="property.qualifiers && property.qualifiers.includes('MinValue') && property.qualifiers.includes('MaxValue')?property.qualifiers.split(',')[1].replace('MaxValue(','').slice(0, -1):property.type==='real'?1:Number.MAX_SAFE_INTEGER" />
|
||||
:min="getPropertyQualifiers(property.qualifiers, 'number-select').min"
|
||||
:max="getPropertyQualifiers(property.qualifiers, 'number-select').max" />
|
||||
</span>
|
||||
<span v-else-if="property.type && property.type==='string' && property.qualifiers && property.qualifiers.startsWith('ValueMap')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
v-decorator="['properties.' + property.key, { initialValue: property.value }]"
|
||||
v-decorator="['properties.' + escapePropertyKey(property.key), { initialValue: property.value.length>0 ? property.value: getPropertyQualifiers(property.qualifiers, 'select')[0] }]"
|
||||
:placeholder="property.description"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
>
|
||||
<a-select-option :v-if="property.value===''" key="">{{ }}</a-select-option>
|
||||
<a-select-option v-for="opt in property.qualifiers.replace('ValueMap','').substr(1).slice(0, -1).split(',')" :key="removeQuotes(opt)">
|
||||
{{ removeQuotes(opt) }}
|
||||
<a-select-option v-for="opt in getPropertyQualifiers(property.qualifiers, 'select')" :key="opt">
|
||||
{{ opt }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</span>
|
||||
<span v-else-if="property.type && property.type==='string' && property.password">
|
||||
<a-input-password
|
||||
v-decorator="['properties.' + property.key, { initialValue: property.value }]"
|
||||
v-decorator="['properties.' + escapePropertyKey(property.key), { initialValue: property.value }]"
|
||||
:placeholder="property.description" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<a-input
|
||||
v-decorator="['properties.' + property.key, { initialValue: property.value }]"
|
||||
v-decorator="['properties.' + escapePropertyKey(property.key), { initialValue: property.value }]"
|
||||
:placeholder="property.description" />
|
||||
</span>
|
||||
</a-form-item>
|
||||
@ -409,6 +469,36 @@
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step
|
||||
:title="$t('label.license.agreements')"
|
||||
:status="zoneSelected ? 'process' : 'wait'"
|
||||
v-if="vm.templateid && templateLicenses && templateLicenses.length > 0">
|
||||
<template slot="description">
|
||||
<div style="margin-top: 10px">
|
||||
{{ $t('message.read.accept.license.agreements') }}
|
||||
<a-form-item>
|
||||
<div
|
||||
style="margin-top: 10px"
|
||||
v-for="(license, licenseIndex) in templateLicenses"
|
||||
:key="licenseIndex"
|
||||
:v-bind="license.id">
|
||||
<span slot="label">
|
||||
{{ 'Agreement ' + (licenseIndex+1) + ': ' + license.name }}
|
||||
</span>
|
||||
<a-textarea
|
||||
:value="license.text"
|
||||
:auto-size="{ minRows: 3, maxRows: 8 }"
|
||||
readOnly />
|
||||
</div>
|
||||
<a-checkbox
|
||||
style="margin-top: 10px"
|
||||
v-decorator="['licensesaccepted']">
|
||||
{{ $t('label.i.accept.all.license.agreements') }}
|
||||
</a-checkbox>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</a-steps>
|
||||
<div class="card-footer">
|
||||
<!-- ToDo extract as component -->
|
||||
@ -550,6 +640,11 @@ export default {
|
||||
},
|
||||
instanceConfig: {},
|
||||
template: {},
|
||||
templateConfigurations: [],
|
||||
templateNics: [],
|
||||
templateLicenses: [],
|
||||
templateProperties: [],
|
||||
selectedTemplateConfiguration: {},
|
||||
iso: {},
|
||||
hypervisor: '',
|
||||
serviceOffering: {},
|
||||
@ -775,6 +870,9 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
templateConfigurationExists () {
|
||||
return this.vm.templateid && this.templateConfigurations && this.templateConfigurations.length > 0
|
||||
},
|
||||
networkId () {
|
||||
return this.$route.query.networkid || null
|
||||
},
|
||||
@ -902,8 +1000,33 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
removeQuotes (value) {
|
||||
return value.replace(/"/g, '')
|
||||
getPropertyQualifiers (qualifiers, type) {
|
||||
var result = ''
|
||||
switch (type) {
|
||||
case 'select':
|
||||
result = []
|
||||
if (qualifiers && qualifiers.includes('ValueMap')) {
|
||||
result = qualifiers.replace('ValueMap', '').substr(1).slice(0, -1).split(',')
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
result[i] = result[i].replace(/"/g, '')
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'number-select':
|
||||
var min = 0
|
||||
var max = Number.MAX_SAFE_INTEGER
|
||||
if (qualifiers && qualifiers.includes('MinValue') && qualifiers.includes('MaxValue')) {
|
||||
var arr = qualifiers.split(',')
|
||||
if (arr.length > 1) {
|
||||
min = arr[0].replace('MinValue(', '').slice(0, -1)
|
||||
max = arr[1].replace('MaxValue(', '').slice(0, -1)
|
||||
}
|
||||
}
|
||||
result = { min: min, max: max }
|
||||
break
|
||||
default:
|
||||
}
|
||||
return result
|
||||
},
|
||||
fillValue (field) {
|
||||
this.form.getFieldDecorator([field], { initialValue: this.dataPreFill[field] })
|
||||
@ -1006,6 +1129,16 @@ export default {
|
||||
for (const key in this.options.templates) {
|
||||
var t = _.find(_.get(this.options.templates[key], 'template', []), (option) => option.id === value)
|
||||
if (t) {
|
||||
this.templateConfigurations = []
|
||||
this.selectedTemplateConfiguration = {}
|
||||
this.templateNics = []
|
||||
this.templateLicenses = []
|
||||
this.templateProperties = []
|
||||
this.updateTemplateParameters()
|
||||
if (t.deployasis === true && !t.details && (!this.template || t.id !== this.template.id)) {
|
||||
// Deploy as-is template without details detected, need to retrieve the template details
|
||||
this.fetchTemplateDetails(t)
|
||||
}
|
||||
template = t
|
||||
break
|
||||
}
|
||||
@ -1015,6 +1148,11 @@ export default {
|
||||
this.dataPreFill.minrootdisksize = Math.ceil(size)
|
||||
}
|
||||
} else if (name === 'isoid') {
|
||||
this.templateConfigurations = []
|
||||
this.selectedTemplateConfiguration = {}
|
||||
this.templateNics = []
|
||||
this.templateLicenses = []
|
||||
this.templateProperties = []
|
||||
this.tabKey = 'isoid'
|
||||
this.form.setFieldsValue({
|
||||
isoid: value,
|
||||
@ -1030,6 +1168,9 @@ export default {
|
||||
this.form.setFieldsValue({
|
||||
computeofferingid: id
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.updateTemplateConfigurationOfferingDetails(id)
|
||||
}, 500)
|
||||
},
|
||||
updateDiskOffering (id) {
|
||||
if (id === '0') {
|
||||
@ -1069,6 +1210,9 @@ export default {
|
||||
keypair: name
|
||||
})
|
||||
},
|
||||
escapePropertyKey (key) {
|
||||
return key.split('.').join('\\002E')
|
||||
},
|
||||
updateSecurityGroups (securitygroupids) {
|
||||
this.securitygroupids = securitygroupids
|
||||
},
|
||||
@ -1096,6 +1240,20 @@ export default {
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!values.computeofferingid) {
|
||||
this.$notification.error({
|
||||
message: this.$t('message.request.failed'),
|
||||
description: this.$t('message.step.2.continue')
|
||||
})
|
||||
return
|
||||
}
|
||||
if ('licensesaccepted' in values && values.licensesaccepted !== true) {
|
||||
this.$notification.error({
|
||||
message: this.$t('message.license.agreements.not.accepted'),
|
||||
description: this.$t('message.step.license.agreements.continue')
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.loading.deploy = true
|
||||
|
||||
@ -1147,30 +1305,40 @@ export default {
|
||||
// step 5: select an affinity group
|
||||
deployVmData.affinitygroupids = (values.affinitygroupids || []).join(',')
|
||||
// step 6: select network
|
||||
const arrNetwork = []
|
||||
networkIds = values.networkids
|
||||
if (networkIds.length > 0) {
|
||||
for (let i = 0; i < networkIds.length; i++) {
|
||||
if (networkIds[i] === this.defaultNetwork) {
|
||||
const ipToNetwork = {
|
||||
networkid: this.defaultNetwork
|
||||
}
|
||||
arrNetwork.unshift(ipToNetwork)
|
||||
} else {
|
||||
const ipToNetwork = {
|
||||
networkid: networkIds[i]
|
||||
}
|
||||
arrNetwork.push(ipToNetwork)
|
||||
if ('networkMap' in values) {
|
||||
const keys = Object.keys(values.networkMap)
|
||||
for (var j = 0; j < keys.length; ++j) {
|
||||
if (values.networkMap[keys[j]] && values.networkMap[keys[j]].length > 0) {
|
||||
deployVmData['nicnetworklist[' + j + '].nic'] = keys[j].replace('nic-', '')
|
||||
deployVmData['nicnetworklist[' + j + '].network'] = values.networkMap[keys[j]]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < arrNetwork.length; j++) {
|
||||
deployVmData['iptonetworklist[' + j + '].networkid'] = arrNetwork[j].networkid
|
||||
if (this.networkConfig.length > 0) {
|
||||
const networkConfig = this.networkConfig.filter((item) => item.key === arrNetwork[j].networkid)
|
||||
if (networkConfig && networkConfig.length > 0) {
|
||||
deployVmData['iptonetworklist[' + j + '].ip'] = networkConfig[0].ipAddress ? networkConfig[0].ipAddress : undefined
|
||||
deployVmData['iptonetworklist[' + j + '].mac'] = networkConfig[0].macAddress ? networkConfig[0].macAddress : undefined
|
||||
} else {
|
||||
const arrNetwork = []
|
||||
networkIds = values.networkids
|
||||
if (networkIds.length > 0) {
|
||||
for (let i = 0; i < networkIds.length; i++) {
|
||||
if (networkIds[i] === this.defaultNetwork) {
|
||||
const ipToNetwork = {
|
||||
networkid: this.defaultNetwork
|
||||
}
|
||||
arrNetwork.unshift(ipToNetwork)
|
||||
} else {
|
||||
const ipToNetwork = {
|
||||
networkid: networkIds[i]
|
||||
}
|
||||
arrNetwork.push(ipToNetwork)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < arrNetwork.length; j++) {
|
||||
deployVmData['iptonetworklist[' + j + '].networkid'] = arrNetwork[j].networkid
|
||||
if (this.networkConfig.length > 0) {
|
||||
const networkConfig = this.networkConfig.filter((item) => item.key === arrNetwork[j].networkid)
|
||||
if (networkConfig && networkConfig.length > 0) {
|
||||
deployVmData['iptonetworklist[' + j + '].ip'] = networkConfig[0].ipAddress ? networkConfig[0].ipAddress : undefined
|
||||
deployVmData['iptonetworklist[' + j + '].mac'] = networkConfig[0].macAddress ? networkConfig[0].macAddress : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1185,13 +1353,15 @@ export default {
|
||||
if ('properties' in values) {
|
||||
const keys = Object.keys(values.properties)
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
deployVmData['properties[' + i + '].key'] = keys[i]
|
||||
const propKey = keys[i].split('\\002E').join('.')
|
||||
deployVmData['properties[' + i + '].key'] = propKey
|
||||
deployVmData['properties[' + i + '].value'] = values.properties[keys[i]]
|
||||
}
|
||||
}
|
||||
if ('bootintosetup' in values) {
|
||||
deployVmData.bootintosetup = values.bootintosetup
|
||||
}
|
||||
|
||||
const title = this.$t('label.launch.vm')
|
||||
const description = values.name || ''
|
||||
const password = this.$t('label.password')
|
||||
@ -1293,6 +1463,23 @@ export default {
|
||||
this.loading[name] = false
|
||||
})
|
||||
},
|
||||
fetchTemplateDetails (template) {
|
||||
api('listTemplates', {
|
||||
templateFilter: 'all',
|
||||
id: template.id,
|
||||
details: 'all'
|
||||
}).then(response => {
|
||||
if (response && response.listtemplatesresponse) {
|
||||
const items = response.listtemplatesresponse.template
|
||||
if (items && items.length > 0) {
|
||||
this.template.details = items[0].details
|
||||
this.updateTemplateParameters()
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
})
|
||||
},
|
||||
fetchTemplates (templateFilter, params) {
|
||||
params = params || {}
|
||||
if (params.keyword || params.category !== templateFilter) {
|
||||
@ -1301,6 +1488,7 @@ export default {
|
||||
}
|
||||
params.zoneid = _.get(this.zone, 'id')
|
||||
params.templatefilter = templateFilter
|
||||
params.details = 'min'
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
api('listTemplates', params).then((response) => {
|
||||
@ -1425,6 +1613,120 @@ export default {
|
||||
.replace(/>/g, '>')
|
||||
|
||||
return reversedValue
|
||||
},
|
||||
fetchTemplateNics (template) {
|
||||
var nics = []
|
||||
if (template && template.details && Object.keys(template.details).length > 0) {
|
||||
var keys = Object.keys(template.details)
|
||||
keys = keys.filter(key => key.startsWith('ACS-network-'))
|
||||
for (var key of keys) {
|
||||
var propertyMap = JSON.parse(template.details[key])
|
||||
nics.push(propertyMap)
|
||||
}
|
||||
nics.sort(function (a, b) {
|
||||
return a.InstanceID - b.InstanceID
|
||||
})
|
||||
}
|
||||
return nics
|
||||
},
|
||||
fetchTemplateProperties (template) {
|
||||
var properties = []
|
||||
if (template && template.details && Object.keys(template.details).length > 0) {
|
||||
var keys = Object.keys(template.details)
|
||||
keys = keys.filter(key => key.startsWith('ACS-property-'))
|
||||
for (var key of keys) {
|
||||
var propertyMap = JSON.parse(template.details[key])
|
||||
properties.push(propertyMap)
|
||||
}
|
||||
properties.sort(function (a, b) {
|
||||
return a.label.localeCompare(b.label)
|
||||
})
|
||||
}
|
||||
return properties
|
||||
},
|
||||
fetchTemplateConfigurations (template) {
|
||||
var configurations = []
|
||||
if (template && template.details && Object.keys(template.details).length > 0) {
|
||||
var keys = Object.keys(template.details)
|
||||
keys = keys.filter(key => key.startsWith('ACS-configuration-'))
|
||||
for (var key of keys) {
|
||||
var configuration = JSON.parse(template.details[key])
|
||||
configuration.name = configuration.label
|
||||
configuration.displaytext = configuration.label
|
||||
configuration.iscustomized = true
|
||||
configuration.cpunumber = 0
|
||||
configuration.cpuspeed = 0
|
||||
configuration.memory = 0
|
||||
for (var harwareItem of configuration.hardwareItems) {
|
||||
if (harwareItem.resourceType === 'Processor') {
|
||||
configuration.cpunumber = harwareItem.virtualQuantity
|
||||
configuration.cpuspeed = harwareItem.reservation
|
||||
} else if (harwareItem.resourceType === 'Memory') {
|
||||
configuration.memory = harwareItem.virtualQuantity
|
||||
}
|
||||
}
|
||||
configurations.push(configuration)
|
||||
}
|
||||
configurations.sort(function (a, b) {
|
||||
return a.cpunumber - b.cpunumber
|
||||
})
|
||||
}
|
||||
return configurations
|
||||
},
|
||||
fetchTemplateLicenses (template) {
|
||||
var licenses = []
|
||||
if (template && template.details && Object.keys(template.details).length > 0) {
|
||||
var keys = Object.keys(template.details)
|
||||
keys = keys.filter(key => key.startsWith('ACS-eula-'))
|
||||
for (var key of keys) {
|
||||
var license = {
|
||||
id: this.escapePropertyKey(key.replace(' ', '-')),
|
||||
name: key.replace('ACS-eula-', ''),
|
||||
text: template.details[key]
|
||||
}
|
||||
licenses.push(license)
|
||||
}
|
||||
}
|
||||
return licenses
|
||||
},
|
||||
updateTemplateParameters () {
|
||||
if (this.template) {
|
||||
this.templateNics = this.fetchTemplateNics(this.template)
|
||||
this.templateConfigurations = this.fetchTemplateConfigurations(this.template)
|
||||
this.templateLicenses = this.fetchTemplateLicenses(this.template)
|
||||
this.templateProperties = this.fetchTemplateProperties(this.template)
|
||||
this.selectedTemplateConfiguration = {}
|
||||
if (this.templateConfigurationExists) {
|
||||
setTimeout(() => {
|
||||
this.selectedTemplateConfiguration = this.templateConfigurations[0]
|
||||
if ('templateConfiguration' in this.form.fieldsStore.fieldsMeta) {
|
||||
this.updateFieldValue('templateConfiguration', this.selectedTemplateConfiguration.id)
|
||||
}
|
||||
this.updateComputeOffering(null) // reset as existing selection may be incompatible
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
},
|
||||
onSelectTemplateConfigurationId (value) {
|
||||
this.selectedTemplateConfiguration = _.find(this.templateConfigurations, (option) => option.id === value)
|
||||
this.updateComputeOffering(null)
|
||||
},
|
||||
updateTemplateConfigurationOfferingDetails (offeringId) {
|
||||
var offering = this.serviceOffering
|
||||
if (!offering || offering.id !== offeringId) {
|
||||
offering = _.find(this.options.serviceOfferings, (option) => option.id === offeringId)
|
||||
}
|
||||
if (offering && offering.iscustomized && this.templateConfigurationExists && this.selectedTemplateConfiguration) {
|
||||
if ('cpunumber' in this.form.fieldsStore.fieldsMeta) {
|
||||
this.updateFieldValue('cpunumber', this.selectedTemplateConfiguration.cpunumber)
|
||||
}
|
||||
if ((offering.cpuspeed == null || offering.cpuspeed === undefined) && 'cpuspeed' in this.form.fieldsStore.fieldsMeta) {
|
||||
this.updateFieldValue('cpuspeed', this.selectedTemplateConfiguration.cpuspeed)
|
||||
}
|
||||
if ('memory' in this.form.fieldsStore.fieldsMeta) {
|
||||
this.updateFieldValue('memory', this.selectedTemplateConfiguration.memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +81,18 @@ export default {
|
||||
zoneId: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
minimumCpunumber: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
minimumCpuspeed: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
minimumMemory: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -115,36 +127,58 @@ export default {
|
||||
computed: {
|
||||
tableSource () {
|
||||
return this.computeItems.map((item) => {
|
||||
var cpuNumberValue = item.cpunumber + ''
|
||||
var maxCpuNumber = item.cpunumber
|
||||
var maxCpuSpeed = item.cpuspeed
|
||||
var maxMemory = item.memory
|
||||
var cpuNumberValue = (item.cpunumber !== null && item.cpunumber !== undefined && item.cpunumber > 0) ? item.cpunumber + '' : ''
|
||||
var cpuSpeedValue = (item.cpuspeed !== null && item.cpuspeed !== undefined && item.cpuspeed > 0) ? parseFloat(item.cpuspeed / 1000.0).toFixed(2) + '' : ''
|
||||
var ramValue = item.memory + ''
|
||||
var ramValue = (item.memory !== null && item.memory !== undefined && item.memory > 0) ? item.memory + '' : ''
|
||||
if (item.iscustomized === true) {
|
||||
cpuNumberValue = ''
|
||||
ramValue = ''
|
||||
if ('serviceofferingdetails' in item &&
|
||||
'mincpunumber' in item.serviceofferingdetails &&
|
||||
'maxcpunumber' in item.serviceofferingdetails) {
|
||||
maxCpuNumber = item.serviceofferingdetails.maxcpunumber
|
||||
cpuNumberValue = item.serviceofferingdetails.mincpunumber + '-' + item.serviceofferingdetails.maxcpunumber
|
||||
}
|
||||
if ('serviceofferingdetails' in item &&
|
||||
'minmemory' in item.serviceofferingdetails &&
|
||||
'maxmemory' in item.serviceofferingdetails) {
|
||||
maxMemory = item.serviceofferingdetails.maxmemory
|
||||
ramValue = item.serviceofferingdetails.minmemory + '-' + item.serviceofferingdetails.maxmemory
|
||||
}
|
||||
}
|
||||
var disabled = false
|
||||
if (this.minimumCpunumber > 0 && ((item.iscustomized === false && maxCpuNumber !== this.minimumCpunumber) ||
|
||||
(item.iscustomized === true && maxCpuNumber < this.minimumCpunumber))) {
|
||||
disabled = true
|
||||
}
|
||||
if (disabled === false && this.minimumCpuspeed > 0 && maxCpuSpeed && maxCpuSpeed !== this.minimumCpuspeed) {
|
||||
disabled = true
|
||||
}
|
||||
if (disabled === false && maxMemory && this.minimumMemory > 0 &&
|
||||
((item.iscustomized === false && maxMemory !== this.minimumMemory) ||
|
||||
(item.iscustomized === true && maxMemory < this.minimumMemory))) {
|
||||
disabled = true
|
||||
}
|
||||
return {
|
||||
key: item.id,
|
||||
name: item.name,
|
||||
cpu: cpuNumberValue.length > 0 ? `${cpuNumberValue} CPU x ${cpuSpeedValue} Ghz` : '',
|
||||
ram: ramValue.length > 0 ? `${ramValue} MB` : ''
|
||||
ram: ramValue.length > 0 ? `${ramValue} MB` : '',
|
||||
disabled: disabled
|
||||
}
|
||||
})
|
||||
},
|
||||
rowSelection () {
|
||||
return {
|
||||
type: 'radio',
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectRow
|
||||
selectedRowKeys: this.selectedRowKeys || [],
|
||||
onChange: this.onSelectRow,
|
||||
getCheckboxProps: (record) => ({
|
||||
props: {
|
||||
disabled: record.disabled
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -152,6 +186,8 @@ export default {
|
||||
value (newValue, oldValue) {
|
||||
if (newValue && newValue !== oldValue) {
|
||||
this.selectedRowKeys = [newValue]
|
||||
} else {
|
||||
this.selectedRowKeys = []
|
||||
}
|
||||
},
|
||||
loading () {
|
||||
|
||||
@ -190,6 +190,13 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12" v-if="allowed && hyperVMWShow && currentForm !== 'Upload' && deployAsIsSupported">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item :label="$t('label.deployasis')">
|
||||
<a-switch v-decorator="['deployasis']" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12" v-if="allowed && hyperXenServerShow">
|
||||
<a-form-item v-if="hyperXenServerShow" :label="$t('label.xenservertoolsversion61plus')">
|
||||
<a-switch
|
||||
@ -440,6 +447,11 @@ export default {
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
computed: {
|
||||
deployAsIsSupported () {
|
||||
return this.apiConfig.params.filter(x => x.name === 'deployasis').length > 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.fetchZone()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user