IDC.vue 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. <template>
  2. <div>
  3. <a-form
  4. class="mt-3"
  5. :form="form.fc"
  6. v-bind="formItemLayout"
  7. @submit="submit"
  8. hideRequiredMark>
  9. <servertemplate v-if="isServertemplate" :decorators="decorators.servertemplate">
  10. <a-form-item :label="$t('compute.text_297', [$t('dictionary.project')])">
  11. <domain-project :fc="form.fc" :decorators="{ project: decorators.project, domain: decorators.domain }" />
  12. </a-form-item>
  13. </servertemplate>
  14. <!-- <a-divider orientation="left">{{$t('compute.text_300')}}</a-divider> -->
  15. <a-form-item v-if="!isServertemplate" :label="$t('compute.text_297', [$t('dictionary.project')])">
  16. <domain-project
  17. :fc="form.fc"
  18. :fd="form.fd"
  19. :decorators="{ project: decorators.project, domain: decorators.domain }"
  20. :ignoreStorage="isInitForm"
  21. @fetchDomainCallback="fetchDomainCallback"
  22. @fetchProjectCallback="fetchProjectCallback" />
  23. </a-form-item>
  24. <a-form-item :label="$t('compute.text_177')" class="mb-0">
  25. <cloudregion-zone
  26. :zone-params="zoneParams"
  27. :cloudregion-params="cloudregionParams"
  28. :decorator="decorators.cloudregionZone"
  29. filterBrandResource="compute_engine" />
  30. </a-form-item>
  31. <a-form-item :label="$t('compute.text_228')" v-if="!isServertemplate">
  32. <a-input v-decorator="decorators.name" />
  33. <template v-slot:extra>
  34. <name-repeated res="servers" :name="form.fd.name" :default-text="$t('compute.text_893')" />
  35. </template>
  36. </a-form-item>
  37. <a-form-item :label="$t('common.description')" v-if="!isServertemplate">
  38. <a-textarea :auto-size="{ minRows: 1, maxRows: 3 }" v-decorator="decorators.description" :placeholder="$t('common_367')" />
  39. </a-form-item>
  40. <a-form-item :label="$t('compute.text_1041')" v-if="isOpenWorkflow">
  41. <a-input v-decorator="decorators.reason" :placeholder="$t('compute.text_1042')" />
  42. </a-form-item>
  43. <a-form-item v-show="!isServertemplate" :label="$t('compute.text_1132')">
  44. <duration useServerDuration :decorators="decorators.duration" :form="form" />
  45. </a-form-item>
  46. <a-form-item :label="$t('compute.text_294')" v-show="!isServertemplate">
  47. <a-input-number v-decorator="decorators.count" @blur="countBlur" :min="1" :max="100" />
  48. </a-form-item>
  49. <a-form-item :label="$t('compute.text_176')" :extra="$t('compute.text_1151')">
  50. <hypervisor-radio :decorator="decorators.hypervisor" :type="form.fi.createType" :hypervisors="hypervisors" />
  51. </a-form-item>
  52. <a-form-item
  53. :label="$t('compute.text_1365')" v-if="isKvm" v-show="form.fi.capability.host_cpu_archs && form.fi.capability.host_cpu_archs.length > 1">
  54. <os-arch
  55. v-decorator="decorators.os_arch"
  56. :form="form"
  57. :options="archOptions" />
  58. </a-form-item>
  59. <a-form-item v-if="form.fd.hypervisor === 'kvm'">
  60. <span slot="label">
  61. {{ $t('compute.text_1152') }}&nbsp;
  62. <a-tooltip :title="$t('compute.vgpu_check.tooltip')">
  63. <a-icon type="question-circle-o" />
  64. </a-tooltip>
  65. </span>
  66. <pci :decorators="decorators.pci" :pciDevTypeOptions="pciDevTypeOptions" :form="form" :pci-options="pciOptions" />
  67. </a-form-item>
  68. <a-form-item :label="$t('compute.text_1058')" class="mb-0">
  69. <cpu-radio :decorator="decorators.vcpu" :options="form.fi.cpuMem.cpus || []" :showUnlimited="true" :form="form" :hypervisor="form.fd.hypervisor" :showCpuSocketsInit="form.fd.hypervisor === 'esxi' && initFormData.hypervisor === 'esxi' && initFormData.cpu_sockets" :cpuSocketsInit="initFormData.cpu_sockets" @change="cpuChange" />
  70. </a-form-item>
  71. <a-form-item :label="$t('compute.text_369')" class="mb-0">
  72. <mem-radio :decorator="decorators.vmem" :options="form.fi.cpuMem.mems_mb || []" :showUnlimited="true" />
  73. </a-form-item>
  74. <a-form-item :label="$t('compute.text_109')" v-if="showSku">
  75. <sku
  76. v-decorator="decorators.sku"
  77. :type="type"
  78. :sku-params="skuParam"
  79. :hypervisor="form.fd.hypervisor" />
  80. </a-form-item>
  81. <a-form-item :label="$t('compute.text_267')" :extra="extra">
  82. <os-select
  83. :type="type"
  84. :uefi="uefi"
  85. :vgaPci="vgaPci"
  86. :form="form"
  87. :hypervisor="form.fd.hypervisor"
  88. :decorator="decorators.imageOS"
  89. :image-params="imageParams"
  90. :cacheImageParams="cacheImageParams"
  91. :cloudproviderParamsExtra="cloudproviderParamsExtra"
  92. @updateImageMsg="updateFi" />
  93. </a-form-item>
  94. <a-form-item v-if="isKvm && form.fd.imageType === 'iso'" class="mb-0">
  95. <span slot="label">
  96. {{ $t('compute.kickstart') }}&nbsp;
  97. <a-tooltip :title="$t('compute.kickstart.tooltip')">
  98. <a-icon type="question-circle-o" />
  99. </a-tooltip>
  100. </span>
  101. <kickstart :decorator="decorators.kickstart" :form="form" />
  102. </a-form-item>
  103. <a-form-item v-if="isShowAgent" :label="$t('compute.agent.label')" :extra="$t('compute.agent.extra')">
  104. <a-checkbox v-decorator="decorators.deploy_telegraf">{{ $t('compute.agent.install.plugin') }}</a-checkbox>
  105. </a-form-item>
  106. <a-form-item :label="$t('compute.text_49')" class="mb-0">
  107. <system-disk
  108. ref="systemDiskRef"
  109. v-if="form.fd.hypervisor"
  110. :decorator="decorators.systemDisk"
  111. :isServertemplate="isServertemplate"
  112. :type="type"
  113. :form="form"
  114. :hypervisor="form.fd.hypervisor"
  115. :sku="form.fd.sku"
  116. :capability-data="form.fi.capability"
  117. :image="form.fi.imageMsg"
  118. :defaultSize="systemdiskDefaultSize"
  119. :isHostImageType="isHostImageType"
  120. :imageType="form.fi.imageType"
  121. :storageParams="storageParams"
  122. :storageHostParams="storageHostParams"
  123. :domain="project_domain"
  124. :isStorageShow="isStorageShow"
  125. :isAutoResetShow="isKvm"
  126. @storageHostChange="storageHostChange" />
  127. </a-form-item>
  128. <a-form-item :label="$t('compute.text_50')">
  129. <data-disk
  130. v-if="form.fd.hypervisor"
  131. ref="dataDiskRef"
  132. :decorator="decorators.dataDisk"
  133. :form="form"
  134. :type="type"
  135. :hypervisor="form.fd.hypervisor"
  136. :sku="form.fd.sku"
  137. :capability-data="form.fi.capability"
  138. :isSnapshotImageType="isSnapshotImageType"
  139. :isHostImageType="isHostImageType"
  140. :imageType="form.fi.imageType"
  141. :defaultType="form.fd.systemDiskType"
  142. :domain="project_domain"
  143. :isWindows="isWindows"
  144. :isStorageShow="isStorageShow"
  145. :enableMointpoint="true"
  146. :storageParams="dataDiskStorageParams"
  147. :storageHostParams="storageHostParams"
  148. :isAutoResetShow="isKvm"
  149. :isInitForm="isInitForm"
  150. @storageHostChange="storageHostChange" />
  151. <div slot="extra" class="warning-color" v-if="isStorageShow && form.fi.imageType !== 'backup' && form.fi.imageType !== 'snapshot'">{{ $t('compute.select_storage_no_schetag') }}</div>
  152. </a-form-item>
  153. <a-form-item :label="$t('compute.text_1372')" v-if="showServerAccount">
  154. <server-account :form="form" :hypervisor="form.fd.hypervisor" :instance_capabilities="form.fi.capability.instance_capabilities" :osType="osType" />
  155. </a-form-item>
  156. <a-form-item :label="$t('compute.text_308')" v-if="!isIso">
  157. <server-password :form="form" :login-types="loginTypes" :isSnapshotImageType="isSnapshotImageType" :decorator="decorators.loginConfig" />
  158. </a-form-item>
  159. <a-form-item :label="$t('compute.text_104')" class="mb-0">
  160. <server-network
  161. ref="networkRef"
  162. :form="form"
  163. :isServertemplate="isServertemplate"
  164. :decorator="decorators.network"
  165. :network-list-params="networkParam"
  166. :schedtag-params="schedtagParams"
  167. :networkVpcParams="networkVpcParams"
  168. :vpcResource="vpcResource"
  169. :hypervisor="form.fd.hypervisor"
  170. :serverCount="form.fd.count"
  171. :vpcResourceMapper="vpcResourceMapper"
  172. :networkResourceMapper="networkResourceMapper"
  173. :showMacConfig="form.fd.hypervisor === 'kvm'"
  174. :showDeviceConfig="form.fd.hypervisor === 'kvm'"
  175. :showSecgroupConfig="form.fd.hypervisor === 'kvm'"
  176. :secgroupParams="networkSecgroupParams" />
  177. </a-form-item>
  178. <a-form-item :label="$t('compute.text_1154')" class="mb-0">
  179. <tag
  180. v-decorator="decorators.tag" :default-checked="tagDefaultChecked" />
  181. </a-form-item>
  182. <!-- <a-divider orientation="left" v-if="showAdvanceConfig">{{$t('compute.text_309')}}</a-divider> -->
  183. <a-collapse :bordered="false" v-model="collapseActive">
  184. <a-collapse-panel :header="$t('compute.text_309')" key="1">
  185. <eip-config
  186. ref="eipConfigRef"
  187. v-if="showEip"
  188. :decorators="decorators.eip"
  189. :eip-params="eipParams"
  190. :hypervisor="form.fd.hypervisor"
  191. :showBind="false"
  192. :isServertemplate="isServertemplate"
  193. :cloud-env="type"
  194. :form="form"
  195. :formItemLayout="formItemLayout" />
  196. <a-form-item
  197. v-if="!isServertemplate"
  198. :validate-status="hostNameValidate.validateStatus"
  199. :help="hostNameValidate.errorMsg">
  200. <span slot="label">
  201. {{ $t('common_388') }}&nbsp;
  202. <a-tooltip :title="hostNameTips">
  203. <a-icon type="question-circle-o" />
  204. </a-tooltip>
  205. </span>
  206. <host-name v-decorator="decorators.hostName" :isWindows="isWindows" @change="handleHostNameChange" />
  207. </a-form-item>
  208. <a-form-item :label="$t('compute.text_105')" v-if="isKvm">
  209. <secgroup-config
  210. :form="form"
  211. :isSnapshotImageType="isSnapshotImageType"
  212. :decorators="decorators.secgroup"
  213. :secgroup-params="secgroupParams"
  214. :hypervisor="form.fd.hypervisor"
  215. :showSecgroupBind="showSecgroupBind" />
  216. </a-form-item>
  217. <a-form-item :label="$t('compute.text_311')" class="mb-0">
  218. <sched-policy
  219. ref="schedPolicyRef"
  220. :form="form"
  221. :server-type="form.fi.createType"
  222. :disabled-host="policyHostDisabled"
  223. :policy-host-params="policyHostParams"
  224. :decorators="decorators.schedPolicy"
  225. :policy-schedtag-params="policySchedtagParams"
  226. :showSchedCloudprovider="showSchedCloudprovider"
  227. :cloudproviderParamsExtra="cloudproviderParamsExtra" />
  228. </a-form-item>
  229. <a-form-item :label="$t('compute.text_1155')" class="mb-0" v-if="isKvm">
  230. <bios :decorator="decorators.bios" :uefi="uefi" :isArm="isArm" :showDefault="true" />
  231. </a-form-item>
  232. <a-form-item :label="$t('compute.vdi_protocol')" class="mb-0" v-if="isKvm">
  233. <vdi :decorator="decorators.vdi" :showDefault="true" />
  234. </a-form-item>
  235. <a-form-item :label="$t('compute.vga')" class="mb-0" v-if="isKvm">
  236. <vga :decorator="decorators.vga" :vdi="vdi" :form="form" :showDefault="true" />
  237. </a-form-item>
  238. <a-form-item :label="$t('compute.machine')" class="mb-0" v-if="isKvm">
  239. <machine :decorator="getMachineDecorator()" :isArm="isArm" :showDefault="true" />
  240. </a-form-item>
  241. <a-form-item v-show="!isServertemplate" v-if="isKvm && isLocalDisk" :label="$t('compute.text_1156')" :extra="$t('compute.text_1157')">
  242. <backup
  243. :decorator="decorators.backup"
  244. :disabled="form.fd.systemDiskType"
  245. :disabled-items="backupDisableds"
  246. :domain="form.fd.domain"
  247. :availableHostCount="availableHostCount"
  248. :hostParams="backupHostParams" />
  249. </a-form-item>
  250. <a-form-item v-if="isKvm" :label="$t('compute.text_494')" :extra="$t('compute.daemon.tooltip')">
  251. <a-switch
  252. v-decorator="decorators.is_daemon"
  253. :checkedChildren="$t('compute.text_115')"
  254. :unCheckedChildren="$t('compute.text_116')" />
  255. </a-form-item>
  256. <a-form-item v-show="!isServertemplate" v-if="isKvm" :label="$t('dictionary.instancegroup')" :extra="$t('compute.text_1158')">
  257. <instance-groups :decorators="decorators.groups" :params="instanceGroupsParams" />
  258. </a-form-item>
  259. <a-form-item v-show="!isServertemplate" v-if="isKvm && enableEncryption" :label="$t('compute.server.encryption')" :extra="$t('compute.server.encryption.extra')">
  260. <encrypt-keys :decorators="decorators.encrypt_keys" />
  261. </a-form-item>
  262. <custom-data v-if="showCustomData" ref="customData" :decorators="decorators" :form="form" />
  263. <!-- <a-form-item v-if="!isOpenSourceVersion" :label="$t('compute.bastionHost.bastion_host')">
  264. <bastion-host :decorator="decorators.bastion_host" :form="form" />
  265. </a-form-item> -->
  266. <bastion-host ref="bastionHostRef" v-if="!isOpenSourceVersion && hasBastionService" :decorator="decorators.bastion_host" :form="form" />
  267. </a-collapse-panel>
  268. </a-collapse>
  269. <bottom-bar
  270. :loading="submiting"
  271. :form="form"
  272. :type="type"
  273. :dataDiskSizes="dataDiskSizes"
  274. :isOpenWorkflow="isOpenWorkflow"
  275. :errors.sync="errors"
  276. :isServertemplate="isServertemplate"
  277. :hasMeterService="hasMeterService"
  278. @add-cart="addShopCart"
  279. @cancel="handleCancel" />
  280. </a-form>
  281. </div>
  282. </template>
  283. <script>
  284. import _ from 'lodash'
  285. import * as R from 'ramda'
  286. import OsArch from '@/sections/OsArch'
  287. import { IMAGES_TYPE_MAP, STORAGE_TYPES, HOST_CPU_ARCHS } from '@/constants/compute'
  288. import { resolveValueChangeField } from '@/utils/common/ant'
  289. import { HYPERVISORS_MAP } from '@/constants'
  290. import { diskSupportTypeMedium, getOriginDiskKey } from '@/utils/common/hypervisor'
  291. import SecgroupConfig from '@Compute/sections/SecgroupConfig'
  292. import EipConfig from '@Compute/sections/EipConfig'
  293. import EncryptKeys from '@Compute/sections/encryptkeys'
  294. import Vdi from '@Compute/sections/VDI'
  295. import Vga from '@Compute/sections/VGA'
  296. import Machine from '@Compute/sections/Machine'
  297. import { NETWORK_OPTIONS_MAP, GPU_DEV_TYPE_OPTIONS } from '@Compute/constants'
  298. import Kickstart from '@Compute/sections/Kickstart'
  299. import mixin from './mixin'
  300. export default {
  301. name: 'VM_IDCCreate',
  302. components: {
  303. SecgroupConfig,
  304. EipConfig,
  305. OsArch,
  306. Vdi,
  307. Vga,
  308. Machine,
  309. EncryptKeys,
  310. Kickstart,
  311. },
  312. mixins: [mixin],
  313. data () {
  314. return {
  315. isLocalDisk: true,
  316. timer: null,
  317. isFirstInit: true,
  318. storageHosts: {}, // 所有磁盘的storage-host
  319. storageHostParams: {}, // 第一个选择的块存储
  320. }
  321. },
  322. computed: {
  323. isKvm () {
  324. return this.form.fd.hypervisor === HYPERVISORS_MAP.kvm.key
  325. },
  326. isIso () {
  327. return this.form.fd.imageType === IMAGES_TYPE_MAP.iso.key
  328. },
  329. isArm () {
  330. return this.form.fd.os_arch === HOST_CPU_ARCHS.arm.key
  331. },
  332. isLoongarch64 () {
  333. return this.form.fd.os_arch === HOST_CPU_ARCHS.loongarch64.key
  334. },
  335. vdi () {
  336. return this.form.fd.vdi
  337. },
  338. hypervisors () {
  339. const { hypervisors = [] } = this.form.fi.capability
  340. return hypervisors.filter(v => v !== 'pod')
  341. },
  342. networkSecgroupParams () {
  343. const ret = {
  344. limit: 20,
  345. scope: this.$store.getters.scope,
  346. }
  347. if (this.form.fi.networkVpcObj && this.form.fi.networkVpcObj.id) {
  348. ret.vpc_id = this.form.fi.networkVpcObj.id
  349. }
  350. return ret
  351. },
  352. cloudregionParams () {
  353. return {
  354. cloud_env: 'onpremise',
  355. usable: true,
  356. show_emulated: true,
  357. ...this.scopeParams,
  358. }
  359. },
  360. zoneParams () {
  361. return {
  362. usable: true,
  363. show_emulated: true,
  364. order_by: 'created_at',
  365. order: 'asc',
  366. ...this.scopeParams,
  367. }
  368. },
  369. instanceGroupsParams () {
  370. return {
  371. ...this.scopeParams,
  372. enabled: true,
  373. }
  374. },
  375. cacheImageParams () {
  376. const params = {
  377. cloudregion_id: _.get(this.form.fd, 'cloudregion.key'),
  378. os_arch: HOST_CPU_ARCHS.x86.key,
  379. }
  380. if (!params.cloudregion_id) return {}
  381. if (this.form.fd.imageType === 'vmware') {
  382. params.image_type = 'system'
  383. }
  384. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  385. return params
  386. },
  387. showSku () {
  388. if (this.form.fd.hypervisor) {
  389. return true
  390. }
  391. return false
  392. },
  393. skuParam () {
  394. return {
  395. limit: 0,
  396. public_cloud: false,
  397. postpaid_status: 'available',
  398. cpu_core_count: this.form.fd.vcpu,
  399. memory_size_mb: this.form.fd.vmem,
  400. cloudregion: _.get(this.form, 'fd.cloudregion.key'),
  401. provider: 'OneCloud',
  402. ...this.scopeParams,
  403. }
  404. },
  405. policyHostParams () {
  406. const zone = _.get(this.form.fd, 'zone.key')
  407. if (zone) {
  408. const params = {
  409. enabled: 1,
  410. usable: true,
  411. zone,
  412. hypervisor: this.form.fd.hypervisor,
  413. os_arch: HOST_CPU_ARCHS.x86.key,
  414. ...this.scopeParams,
  415. }
  416. if ([HYPERVISORS_MAP.esxi.key, HYPERVISORS_MAP.kvm.key].includes(params.hypervisor)) {
  417. if (this.form.fd[this.decorators.systemDisk.storage[0]]) {
  418. params.storage_id = this.form.fd[this.decorators.systemDisk.storage[0]]
  419. }
  420. if (this.storageHostParams.disk &&
  421. this.storageHostParams.disk !== 'system' &&
  422. this.storageHostParams.storageHosts &&
  423. this.storageHostParams.storageHosts.length &&
  424. !params.storage_id) {
  425. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  426. params.storage_id = this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]
  427. }
  428. }
  429. params.cloudprovider = this.form.fd.prefer_manager
  430. }
  431. if (this.isArm) params.os_arch = HOST_CPU_ARCHS.arm.key
  432. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  433. return params
  434. }
  435. return {}
  436. },
  437. backupHostParams () {
  438. const zone = _.get(this.form.fd, 'zone.key')
  439. if (zone) {
  440. const params = {
  441. enabled: 1,
  442. usable: true,
  443. zone,
  444. hypervisor: this.form.fd.hypervisor,
  445. os_arch: HOST_CPU_ARCHS.x86.key,
  446. ...this.scopeParams,
  447. }
  448. if (this.isArm) params.os_arch = HOST_CPU_ARCHS.arm.key
  449. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  450. return params
  451. }
  452. return {}
  453. },
  454. networkParam () {
  455. if (!this.cloudregionZoneParams.cloudregion) return {}
  456. const params = {
  457. filter: 'server_type.notin(ipmi, pxe, eip)',
  458. usable: true,
  459. ...this.cloudregionZoneParams,
  460. ...this.scopeParams,
  461. host_type: 'hypervisor',
  462. }
  463. if ([HYPERVISORS_MAP.esxi.key].includes(this.form.fd.hypervisor)) {
  464. params.host_type = 'esxi'
  465. }
  466. if ([HYPERVISORS_MAP.esxi.key, HYPERVISORS_MAP.kvm.key].includes(this.form.fd.hypervisor)) {
  467. if (this.form.fd[this.decorators.systemDisk.storage[0]]) {
  468. params.storage_id = this.form.fd[this.decorators.systemDisk.storage[0]]
  469. }
  470. if (this.storageHostParams.disk &&
  471. this.storageHostParams.disk !== 'system' &&
  472. this.storageHostParams.storageHosts &&
  473. this.storageHostParams.storageHosts.length &&
  474. !params.storage_id) {
  475. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  476. params.storage_id = this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]
  477. }
  478. }
  479. }
  480. return params
  481. },
  482. instanceSpecParmas () {
  483. return {
  484. usable: true,
  485. enabled: true,
  486. cloudregion: _.get(this.form.fd, 'cloudregion.key'),
  487. }
  488. },
  489. showAdvanceConfig () { // 是否展示高级配置
  490. return this.isKvm || !this.isServertemplate
  491. },
  492. uefi () {
  493. const { pciEnable } = this.form.fd
  494. const pciModels = []
  495. Object.keys(this.form.fd).filter(key => key.includes('pciModel')).forEach(key => {
  496. if (R.is(Array, this.form.fd[key])) {
  497. pciModels.push(...this.form.fd[key])
  498. } else {
  499. pciModels.push(this.form.fd[key])
  500. }
  501. })
  502. if (this.isKvm && pciEnable && pciModels.length) {
  503. const pciDevTypes = []
  504. Object.keys(this.form.fd).filter(key => key.includes('pciDevType')).forEach(key => {
  505. if (R.is(Array, this.form.fd[key])) {
  506. pciDevTypes.push(...this.form.fd[key])
  507. } else {
  508. pciDevTypes.push(this.form.fd[key])
  509. }
  510. })
  511. if (this.isWindows && pciDevTypes.includes(GPU_DEV_TYPE_OPTIONS[0].value)) {
  512. return true
  513. }
  514. }
  515. return false
  516. },
  517. vgaPci () {
  518. const { pciEnable } = this.form.fd
  519. const pciModels = []
  520. Object.keys(this.form.fd).filter(key => key.includes('pciModel')).forEach(key => {
  521. if (R.is(Array, this.form.fd[key])) {
  522. pciModels.push(...this.form.fd[key])
  523. } else {
  524. pciModels.push(this.form.fd[key])
  525. }
  526. })
  527. if (this.isKvm && pciEnable && pciModels.length) {
  528. const pciDevTypes = []
  529. Object.keys(this.form.fd).filter(key => key.includes('pciDevType')).forEach(key => {
  530. if (R.is(Array, this.form.fd[key])) {
  531. pciDevTypes.push(...this.form.fd[key])
  532. } else {
  533. pciDevTypes.push(this.form.fd[key])
  534. }
  535. })
  536. if (pciDevTypes.includes(GPU_DEV_TYPE_OPTIONS[0].value)) {
  537. return true
  538. }
  539. }
  540. return false
  541. },
  542. cloudproviderParamsExtra () {
  543. const params = {
  544. ...this.scopeParams,
  545. }
  546. if (this.cloudregionZoneParams?.cloudregion) {
  547. params.cloudregion_id = this.cloudregionZoneParams.cloudregion
  548. }
  549. return params
  550. },
  551. showSchedCloudprovider () { // 创建VMware机器时,镜像类型不是 VMware 平台镜像时调度策略可以选择指定云账号
  552. let show = false
  553. if (this.form.fd.hypervisor === HYPERVISORS_MAP.esxi.key) {
  554. if (this.form.fd.imageType !== IMAGES_TYPE_MAP.vmware.key) {
  555. show = true
  556. }
  557. if (!this.form.fd[this.decorators.systemDisk.storage[0]]) {
  558. show = true
  559. }
  560. }
  561. return show
  562. },
  563. systemdiskSizeDisabled () {
  564. // if (this.form.fd.hypervisor === HYPERVISORS_MAP.esxi.key) {
  565. // const vmLocalImageType = [IMAGES_TYPE_MAP.vmware.key]
  566. // if (vmLocalImageType.includes(this.form.fd.imageType)) {
  567. // return true
  568. // }
  569. // }
  570. return false
  571. },
  572. systemdiskDefaultSize () {
  573. if (this.isIso) {
  574. return 30
  575. }
  576. return null
  577. },
  578. availableHostCount () { // 可用的宿主机数量
  579. if (R.is(Object, this.form.fi.capability)) {
  580. return this.form.fi.capability.available_host_count || 0
  581. }
  582. return 0
  583. },
  584. eipParams () {
  585. if (!this.cloudregionZoneParams.cloudregion) return {}
  586. return {
  587. project: this.project,
  588. region: this.cloudregionZoneParams.cloudregion,
  589. }
  590. },
  591. showEip () {
  592. const { vpcs, networkType } = this.form.fd
  593. if (networkType === NETWORK_OPTIONS_MAP.default.key) {
  594. return false
  595. }
  596. if (R.is(Object, vpcs)) {
  597. const vpcList = Object.values(vpcs)
  598. if (vpcList.length && !~vpcList.indexOf('default')) {
  599. return this.enableEip
  600. }
  601. }
  602. return false
  603. },
  604. storageParams () {
  605. const { systemDiskType = {}, hypervisor } = this.form.fd
  606. let key = systemDiskType.key || ''
  607. const params = {
  608. ...this.scopeParams,
  609. // usable: true, // 包含了 enable:true, status为online的数据
  610. brand: HYPERVISORS_MAP[this.form.fd.hypervisor]?.brand, // kvm,vmware支持指定存储
  611. manager: this.form.fd.prefer_manager,
  612. }
  613. // 磁盘区分介质
  614. if (diskSupportTypeMedium(hypervisor)) {
  615. const medium = getOriginDiskKey(key, true)
  616. key = getOriginDiskKey(key)
  617. params.filter = [
  618. `storage_type.contains("${key}")`,
  619. `medium_type.contains("${medium}")`,
  620. ]
  621. } else {
  622. params.filter = [
  623. `storage_type.contains("${key}")`,
  624. ]
  625. }
  626. return params
  627. },
  628. dataDiskStorageParams () {
  629. const { dataDiskSizes = {}, hypervisor } = this.form.fd
  630. let dataDiskType = ''
  631. let medium = ''
  632. for (const key in dataDiskSizes) {
  633. if (this.form.fd[`dataDiskTypes[${key}]`]) {
  634. dataDiskType = this.form.fd[`dataDiskTypes[${key}]`].key
  635. // 磁盘区分介质
  636. if (diskSupportTypeMedium(hypervisor)) {
  637. medium = getOriginDiskKey(dataDiskType, true)
  638. dataDiskType = getOriginDiskKey(dataDiskType)
  639. } else {
  640. dataDiskType = getOriginDiskKey(dataDiskType)
  641. }
  642. }
  643. }
  644. const params = {
  645. ...this.scopeParams,
  646. // usable: true, // 包含了 host status online 和 account 正常
  647. brand: HYPERVISORS_MAP[this.form.fd.hypervisor]?.brand, // kvm,vmware支持指定存储
  648. manager: this.form.fd.prefer_manager,
  649. }
  650. if (dataDiskType) {
  651. if (medium) {
  652. params.filter = [
  653. `storage_type.contains("${dataDiskType}")`,
  654. `medium_type.contains("${medium}")`,
  655. ]
  656. } else {
  657. params.filter = [`storage_type.contains("${dataDiskType}")`]
  658. }
  659. }
  660. return params
  661. },
  662. isStorageShow () { // 是否开启了指定存储
  663. if ([HYPERVISORS_MAP.esxi.key, HYPERVISORS_MAP.kvm.key].includes(this.form.fd.hypervisor)) {
  664. if (this.form.fd[this.decorators.systemDisk.storage[0]]) {
  665. return true
  666. }
  667. if (this.storageHostParams.disk &&
  668. this.storageHostParams.disk !== 'system' &&
  669. this.storageHostParams.storageHosts &&
  670. this.storageHostParams.storageHosts.length) {
  671. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  672. return true
  673. }
  674. }
  675. }
  676. return false
  677. },
  678. imageParams () {
  679. const params = {
  680. ...this.scopeParams,
  681. os_arch: HOST_CPU_ARCHS.x86.key,
  682. }
  683. if (this.isArm) params.os_arch = HOST_CPU_ARCHS.arm.key
  684. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  685. return params
  686. },
  687. archOptions () {
  688. let opts = []
  689. if (this.form.fi.capability.host_cpu_archs && this.form.fi.capability.host_cpu_archs.length) {
  690. opts = this.form.fi.capability.host_cpu_archs.map(item => {
  691. if (item === HOST_CPU_ARCHS.arm.capabilityKey) return HOST_CPU_ARCHS.arm
  692. if (item === HOST_CPU_ARCHS.x86.capabilityKey) return HOST_CPU_ARCHS.x86
  693. if (item === HOST_CPU_ARCHS.loongarch64.capabilityKey) return HOST_CPU_ARCHS.loongarch64
  694. return item
  695. })
  696. }
  697. return opts.sort((a, b) => a.order - b.order)
  698. },
  699. extra () {
  700. if (this.isIso && this.isWindows) {
  701. return this.$t('compute.iso_windows_help')
  702. }
  703. return this.$t('compute.text_302')
  704. },
  705. enableEncryption () {
  706. return this.$appConfig.isPrivate && !this.$store.getters.isSysCE
  707. },
  708. isShowAgent () {
  709. if (this.isIso || !this.osType) return false
  710. if (this.isWindows) {
  711. return !this.isArm
  712. }
  713. return true
  714. },
  715. },
  716. watch: {
  717. 'form.fi.imageMsg': {
  718. deep: true,
  719. handler (val, oldVal) {
  720. if (R.equals(val, oldVal)) return
  721. this.$nextTick(() => {
  722. // this.form.fi.dataDiskDisabled = false
  723. // this.form.fi.sysDiskDisabled = false
  724. this.form.fi.imageType = ''
  725. if (this.form.fd.imageType === IMAGES_TYPE_MAP.host.key) {
  726. const { root_image: rootImage, data_images: dataImages } = this.form.fi.imageMsg
  727. const systemDiskSize = rootImage.min_disk_mb / 1024
  728. const { hypervisor } = this.form.fd
  729. const { data_storage_types2 } = this.form.fi.capability
  730. const medium = data_storage_types2[hypervisor][0].split('/')[1]
  731. const systemDiskType = {
  732. key: data_storage_types2[hypervisor][0],
  733. label: STORAGE_TYPES[HYPERVISORS_MAP.kvm.key].local.label,
  734. }
  735. this.form.fc.setFieldsValue({
  736. systemDiskSize,
  737. systemDiskType,
  738. })
  739. // 重置数据盘数据
  740. this._resetDataDisk()
  741. if (dataImages) {
  742. dataImages.forEach(val => {
  743. this.$refs.dataDiskRef.add({ size: val.min_disk_mb / 1024, min: val.min_disk_mb / 1024, minusDisabled: true, medium })
  744. })
  745. }
  746. }
  747. if (this.form.fd.imageType === IMAGES_TYPE_MAP.snapshot.key || this.form.fd.imageType === IMAGES_TYPE_MAP.backup.key) {
  748. // 镜像类型为主机快照或主机备份的话要回填数据并禁用
  749. const snapshots = _.cloneDeep(this.form.fi.imageMsg.server_config.disks)
  750. if (!snapshots) return
  751. let sysDisk = snapshots.find(val => val.disk_type === 'sys')
  752. if (!sysDisk) {
  753. sysDisk = snapshots.shift()
  754. }
  755. const dataDisks = snapshots.filter(val => val.disk_type !== 'sys')
  756. const { matchType, matchLabel } = this.matchStorage(sysDisk.backend, sysDisk.medium, 'storage_types2')
  757. const data = {
  758. systemDiskType: {
  759. key: matchType,
  760. label: matchLabel || STORAGE_TYPES[HYPERVISORS_MAP.kvm.key][matchType].label,
  761. },
  762. systemDiskSize: sysDisk.size / 1024,
  763. }
  764. if (val && R.is(Object, val.server_config)) {
  765. if (val.server_config.vcpu_count) {
  766. const cpuValue = val.server_config.vcpu_count
  767. data[this.decorators.vcpu[0]] = cpuValue
  768. this.cpuChange(cpuValue)
  769. if (val.server_config.vmem_size) data[this.decorators.vmem[0]] = val.server_config.vmem_size
  770. }
  771. }
  772. this.form.fc.setFieldsValue(data)
  773. // 重置数据盘数据
  774. this._resetDataDisk()
  775. dataDisks.forEach(val => {
  776. const { matchType, matchMedium } = this.matchStorage(val.backend, val.medium, 'data_storage_types2')
  777. this.$refs.dataDiskRef.add({ diskType: matchType, size: val.size / 1024, sizeDisabled: true, medium: matchMedium })
  778. })
  779. this.form.fi.imageType = this.form.fd.imageType
  780. // this.form.fi.dataDiskDisabled = true
  781. // this.form.fi.sysDiskDisabled = true
  782. } else {
  783. if (oldVal && R.is(Object, oldVal.server_config)) { // 说明是从主机快照切换过去的
  784. const vcpuDecorator = this.decorators.vcpu
  785. const vcpuInit = vcpuDecorator[1].initialValue
  786. this.form.fc.setFieldsValue({
  787. [vcpuDecorator[0]]: vcpuInit,
  788. })
  789. this.cpuChange(vcpuInit)
  790. }
  791. }
  792. })
  793. },
  794. },
  795. uefi (val) {
  796. this.setBios(val)
  797. },
  798. isArm (val, oldV) {
  799. this.setBios(val)
  800. },
  801. isShowAgent (val) {
  802. this.form.fc.setFieldsValue({ deploy_telegraf: val })
  803. },
  804. 'form.fd.imageType': {
  805. handler (val) {
  806. if (val === IMAGES_TYPE_MAP.iso.key) {
  807. this.form.fc.setFieldsValue({
  808. kickstart_enabled: false,
  809. })
  810. this.form.fd.kickstart_enabled = false
  811. }
  812. },
  813. },
  814. },
  815. mounted () {
  816. // this.$nextTick(() => {
  817. // this.init()
  818. // })
  819. },
  820. destroyed () {
  821. this.timer = null
  822. },
  823. methods: {
  824. matchStorage (backend, medium, key) {
  825. const { hypervisor } = this.form.fd
  826. const types = (this.form.fi.capability[key] || {})[hypervisor] || []
  827. const typeMaths = types.filter(val => val.split('/')[0] === backend)
  828. const mediumMaths = typeMaths.filter(val => val.split('/')[1] === medium)
  829. if (mediumMaths.length) {
  830. return {
  831. matchType: mediumMaths[0],
  832. matchLabel: STORAGE_TYPES[hypervisor]?.[mediumMaths[0].split('/')[1]]?.label || mediumMaths[0],
  833. }
  834. }
  835. if (typeMaths.length) {
  836. return {
  837. matchType: typeMaths[0],
  838. matchLabel: STORAGE_TYPES[hypervisor]?.[typeMaths[0].split('/')[1]]?.label || typeMaths[0],
  839. }
  840. }
  841. return { matchType: `${backend}/${medium}`, matchLabel: '' }
  842. },
  843. vpcResourceMapper (list) {
  844. if (this.form.fd.hypervisor === HYPERVISORS_MAP.esxi.key) {
  845. return list.filter(val => val.id === 'default')
  846. }
  847. return list
  848. },
  849. onValuesChange (vm, changedFields) {
  850. this.$nextTick(() => {
  851. const formValue = this.form.fc.getFieldsValue()
  852. const newField = resolveValueChangeField(changedFields)
  853. this._setNewFieldToFd(newField, formValue)
  854. const keys = Object.keys(newField)
  855. if (keys.includes('zone') || keys.includes('cloudregion')) {
  856. this.fetchCapability()
  857. }
  858. if (keys.includes('cloudregion')) {
  859. this.$nextTick(this.fetchInstanceSpecs)
  860. }
  861. if (changedFields.schedPolicyType === 'host') {
  862. this.$set(this.form.fd, 'schedPolicyHost', undefined)
  863. }
  864. if (changedFields.backupEnable) {
  865. this.$set(this.form.fd, 'backup', undefined)
  866. }
  867. this.setIsLocalDisk()
  868. })
  869. },
  870. storageHostChange (val) {
  871. const { disk } = this.storageHostParams
  872. if (val.disk) {
  873. this.storageHosts[val.disk] = val
  874. }
  875. // 由第一块选择块存储的盘来确定块存储所在的host
  876. if (!disk || disk === val.disk) { // 第一块盘选
  877. if (val.storageHosts && val.storageHosts.length) {
  878. this.storageHostParams = val
  879. } else { // 清空操作
  880. let changeNew = false
  881. for (const key in this.storageHosts) {
  882. if (this.storageHosts[key].storageHosts && this.storageHosts[key].storageHosts.length) {
  883. this.storageHostParams = this.storageHosts[key] // 选其他已选的hosts作为新的范围
  884. changeNew = true
  885. break
  886. }
  887. }
  888. if (!changeNew) this.storageHostParams = {}
  889. }
  890. }
  891. },
  892. setIsLocalDisk () {
  893. const isLocal = (v = '') => { return v.startsWith('local') }
  894. const isSysLocal = isLocal(_.get(this.form, 'fd.systemDiskType.key'))
  895. const fd = this.form.fc.getFieldsValue()
  896. let isDiskLocal = true
  897. const { dataDiskTypes } = fd
  898. if (R.is(Object, dataDiskTypes)) {
  899. const diskTypeItem = dataDiskTypes[Object.keys(dataDiskTypes)[0]]
  900. if (diskTypeItem && diskTypeItem.key) {
  901. isDiskLocal = isLocal(diskTypeItem.key)
  902. }
  903. }
  904. this.isLocalDisk = isSysLocal && isDiskLocal
  905. },
  906. fetchCapability () {
  907. const params = {
  908. show_emulated: true,
  909. resource_type: 'shared',
  910. ...this.scopeParams,
  911. }
  912. let id = this.cloudregionZoneParams.cloudregion
  913. let resource = 'cloudregions'
  914. if (this.cloudregionZoneParams.zone) {
  915. id = this.cloudregionZoneParams.zone
  916. resource = 'zones'
  917. }
  918. const capabilityParams = { id, spec: 'capability', params }
  919. if (!id) return
  920. if (R.equals(this.capabilityParams, capabilityParams)) return // 和已有的参数一样则不发请求
  921. this.capabilityParams = capabilityParams
  922. new this.$Manager(resource).getSpecific(this.capabilityParams)
  923. .then(({ data }) => {
  924. let hypervisors = R.is(Object, data) ? (data.hypervisors || []) : []
  925. if (hypervisors.includes(HYPERVISORS_MAP.kvm.key)) { // kvm 排序为第一个
  926. hypervisors = [HYPERVISORS_MAP.kvm.key].concat(hypervisors).filter(val => val !== 'baremetal')
  927. }
  928. hypervisors = Array.from(new Set(hypervisors))
  929. this.form.fi.capability = {
  930. ...data,
  931. hypervisors,
  932. }
  933. this.form.fc.setFieldsValue({
  934. hypervisor: this.decorators.hypervisor[1].initialValue || hypervisors[0], // 赋值默认第一个平台
  935. })
  936. if (this.decorators.os_arch[1].initialValue) {
  937. setTimeout(() => {
  938. this.form.fc.setFieldsValue({ os_arch: this.decorators.os_arch[1].initialValue })
  939. }, 1000)
  940. }
  941. this.init()
  942. })
  943. },
  944. fetchInstanceSpecs () {
  945. if (!this.instanceSpecParmas.cloudregion) return
  946. this.serverskusM.get({ id: 'instance-specs', params: this.instanceSpecParmas })
  947. .then(({ data }) => {
  948. this.form.fi.cpuMem = data
  949. const vcpuDecorator = this.decorators.vcpu
  950. const vcpuInit = vcpuDecorator[1].initialValue
  951. const cpu = this.form.fd.vcpu || vcpuInit
  952. this.cpuChange(cpu)
  953. })
  954. },
  955. setBios (val) {
  956. if (val) {
  957. this.form.fc.getFieldDecorator(this.decorators.bios[0], { preserve: true })
  958. this.form.fc.setFieldsValue({ [this.decorators.bios[0]]: 'UEFI' })
  959. } else {
  960. this.form.fc.setFieldsValue({ [this.decorators.bios[0]]: 'BIOS' })
  961. }
  962. },
  963. gpuChange (val) {
  964. if (!val) {
  965. this.form.fc.setFieldsValue({ gpu: '' })
  966. }
  967. },
  968. init () {
  969. if (this.isFirstInit) {
  970. this.initOsArch()
  971. this.isFirstInit = false
  972. }
  973. },
  974. initOsArch () {
  975. this.timer = setTimeout(() => {
  976. const { os_arch } = this.$route.query
  977. // 数据延迟回填
  978. if (os_arch) {
  979. let canUseOsArch = ''
  980. if (os_arch.indexOf('x86') !== -1) {
  981. canUseOsArch = HOST_CPU_ARCHS.x86.key
  982. } else if (os_arch.indexOf('aarch') !== -1) {
  983. canUseOsArch = HOST_CPU_ARCHS.arm.key
  984. }
  985. if (!canUseOsArch) return
  986. this.form.fc.setFieldsValue({ os_arch: canUseOsArch })
  987. }
  988. }, 3000)
  989. },
  990. getMachineDecorator () {
  991. let initValue = 'pc'
  992. if (this.isArm) {
  993. initValue = 'virt'
  994. }
  995. return [
  996. 'machine',
  997. {
  998. initialValue: initValue,
  999. },
  1000. ]
  1001. },
  1002. },
  1003. }
  1004. </script>