IDC.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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. <container-title :title="$t('compute.eci.container_group_config')" />
  10. <a-form-item :label="$t('compute.text_297', [$t('dictionary.project')])">
  11. <domain-project
  12. :fc="form.fc"
  13. :fd="form.fd"
  14. :decorators="{ project: decorators.project, domain: decorators.domain }"
  15. @fetchDomainCallback="fetchDomainCallback"
  16. @fetchProjectCallback="fetchProjectCallback" />
  17. </a-form-item>
  18. <a-form-item :label="$t('compute.text_177')" class="mb-0">
  19. <cloudregion-zone
  20. :zone-params="zoneParams"
  21. :cloudregion-params="cloudregionParams"
  22. :decorator="decorators.cloudregionZone"
  23. filterBrandResource="compute_engine" />
  24. </a-form-item>
  25. <a-form-item :label="$t('compute.text_228')">
  26. <a-input v-decorator="decorators.name" />
  27. <template v-slot:extra>
  28. <name-repeated res="servers" :name="form.fd.name" :default-text="$t('compute.text_893')" />
  29. </template>
  30. </a-form-item>
  31. <a-form-item :label="$t('common.description')">
  32. <a-textarea :auto-size="{ minRows: 1, maxRows: 3 }" v-decorator="decorators.description" :placeholder="$t('common_367')" />
  33. </a-form-item>
  34. <a-form-item :label="$t('compute.text_1041')" v-if="isOpenWorkflow">
  35. <a-input v-decorator="decorators.reason" :placeholder="$t('compute.text_1042')" />
  36. </a-form-item>
  37. <a-form-item :label="$t('compute.text_1132')">
  38. <duration :decorators="decorators.duration" :form="form" />
  39. </a-form-item>
  40. <a-form-item :label="$t('compute.text_294')">
  41. <a-input-number v-decorator="decorators.count" @blur="countBlur" :min="1" :max="100" />
  42. </a-form-item>
  43. <a-form-item
  44. :label="$t('compute.text_1365')" v-show="form.fi.capability.host_cpu_archs && form.fi.capability.host_cpu_archs.length > 1">
  45. <os-arch
  46. v-decorator="decorators.os_arch"
  47. :form="form"
  48. :options="archOptions" />
  49. </a-form-item>
  50. <a-form-item>
  51. <span slot="label">
  52. {{ $t('compute.text_1152') }}&nbsp;
  53. <a-tooltip :title="$t('compute.vgpu_check.tooltip')">
  54. <a-icon type="question-circle-o" />
  55. </a-tooltip>
  56. </span>
  57. <pci :decorators="decorators.pci" :pciDevTypeOptions="pciDevTypeOptions" :form="form" :pci-options="pciOptions" />
  58. </a-form-item>
  59. <a-form-item :label="$t('compute.text_1058')" class="mb-0">
  60. <cpu-radio :decorator="decorators.vcpu" :options="form.fi.cpuMem.cpus || []" :showUnlimited="true" :form="form" :hypervisor="form.fd.hypervisor" @change="cpuChange" />
  61. </a-form-item>
  62. <a-form-item :label="$t('compute.text_369')" class="mb-0">
  63. <mem-radio :decorator="decorators.vmem" :options="form.fi.cpuMem.mems_mb || []" :showUnlimited="true" />
  64. </a-form-item>
  65. <a-form-item :label="$t('compute.text_109')" v-if="showSku">
  66. <sku
  67. v-decorator="decorators.sku"
  68. :type="type"
  69. :sku-params="skuParam"
  70. :hypervisor="form.fd.hypervisor" />
  71. </a-form-item>
  72. <a-form-item :label="$t('compute.text_50')">
  73. <data-disk
  74. v-if="form.fd.hypervisor"
  75. ref="dataDiskRef"
  76. :decorator="decorators.dataDisk"
  77. :form="form"
  78. :type="type"
  79. :hypervisor="form.fd.hypervisor"
  80. :sku="form.fd.sku"
  81. :capability-data="form.fi.capability"
  82. :disabled="form.fi.dataDiskDisabled"
  83. :defaultType="form.fd.systemDiskType"
  84. :domain="project_domain"
  85. :isVminstanceContainer="true"
  86. :storageParams="dataDiskStorageParams"
  87. :storageHostParams="storageHostParams"
  88. @storageHostChange="storageHostChange" />
  89. </a-form-item>
  90. <a-form-item :label="$t('compute.text_104')" class="mb-0">
  91. <server-network
  92. hiddenAdd
  93. :form="form"
  94. :decorator="decorators.network"
  95. :network-list-params="networkParam"
  96. :schedtag-params="schedtagParams"
  97. :networkVpcParams="networkVpcParams"
  98. :vpcResource="vpcResource"
  99. :hypervisor="form.fd.hypervisor"
  100. :serverCount="form.fd.count"
  101. :vpcResourceMapper="vpcResourceMapper"
  102. :networkResourceMapper="networkResourceMapper"
  103. :showMacConfig="true"
  104. :showDeviceConfig="true" />
  105. </a-form-item>
  106. <a-form-item :label="$t('compute.text_1154')" class="mb-0">
  107. <tag
  108. v-decorator="decorators.tag" />
  109. </a-form-item>
  110. <a-collapse :bordered="false" v-model="collapseActive">
  111. <a-collapse-panel :header="$t('compute.text_309')" key="1">
  112. <eip-config
  113. v-if="showEip"
  114. :decorators="decorators.eip"
  115. :eip-params="eipParams"
  116. :hypervisor="form.fd.hypervisor"
  117. :showBind="false"
  118. :showNew="false"
  119. :cloud-env="type"
  120. :form="form"
  121. :formItemLayout="formItemLayout" />
  122. <a-form-item
  123. :validate-status="hostNameValidate.validateStatus"
  124. :help="hostNameValidate.errorMsg">
  125. <span slot="label">
  126. {{ $t('common_388') }}&nbsp;
  127. <a-tooltip :title="hostNameTips">
  128. <a-icon type="question-circle-o" />
  129. </a-tooltip>
  130. </span>
  131. <host-name v-decorator="decorators.hostName" :isWindows="isWindows" @change="handleHostNameChange" />
  132. </a-form-item>
  133. <a-form-item :label="$t('compute.text_105')">
  134. <secgroup-config
  135. :form="form"
  136. :isSnapshotImageType="isSnapshotImageType"
  137. :decorators="decorators.secgroup"
  138. :secgroup-params="secgroupParams"
  139. :hypervisor="form.fd.hypervisor"
  140. :showSecgroupBind="showSecgroupBind" />
  141. </a-form-item>
  142. <a-form-item :label="$t('compute.text_311')" class="mb-0">
  143. <sched-policy
  144. :form="form"
  145. :server-type="form.fi.createType"
  146. :disabled-host="policyHostDisabled"
  147. :policy-host-params="policyHostParams"
  148. :decorators="decorators.schedPolicy"
  149. :policy-schedtag-params="policySchedtagParams"
  150. :showSchedCloudprovider="showSchedCloudprovider"
  151. :cloudproviderParamsExtra="cloudproviderParamsExtra" />
  152. </a-form-item>
  153. <a-form-item :label="$t('dictionary.instancegroup')" :extra="$t('compute.text_1158')">
  154. <instance-groups :decorators="decorators.groups" :params="instanceGroupsParams" />
  155. </a-form-item>
  156. <a-form-item :label="$t('compute.repo.port_mapping')">
  157. <labels
  158. ref="labelRef"
  159. :decorators="decorators.portMapping"
  160. :disableConf="portMappingDisableConf"
  161. :title="$t('compute.repo.port_mapping')"
  162. :keyLabel="$t('compute.repo.container_port')"
  163. :valueLabel="$t('compute.repo.host_port')"
  164. :keyPlaceholder="$t('compute.repo.example', ['443'])"
  165. :valuePlaceholder="$t('compute.repo.example', ['443'])" />
  166. </a-form-item>
  167. </a-collapse-panel>
  168. </a-collapse>
  169. <container-title :title="$t('compute.eci.container_config')" />
  170. <spec-container
  171. :form="form"
  172. :panes.sync="form.fi.containerPanes"
  173. :errPanes="form.fi.errPanes"
  174. :decorators="decorators.containers" />
  175. <bottom-bar
  176. :loading="submiting"
  177. :form="form"
  178. :type="type"
  179. :dataDiskSizes="dataDiskSizes"
  180. :isOpenWorkflow="isOpenWorkflow"
  181. :errors.sync="errors"
  182. :hasMeterService="hasMeterService"
  183. @add-cart="addShopCart"
  184. @cancel="handleCancel" />
  185. </a-form>
  186. </div>
  187. </template>
  188. <script>
  189. import _ from 'lodash'
  190. import * as R from 'ramda'
  191. import SecgroupConfig from '@Compute/sections/SecgroupConfig'
  192. import EipConfig from '@Compute/sections/EipConfig'
  193. import Labels from '@Compute/sections/Labels'
  194. import SpecContainer from '@Compute/sections/SpecContainer'
  195. import { NETWORK_OPTIONS_MAP } from '@Compute/constants'
  196. import OsArch from '@/sections/OsArch'
  197. import { IMAGES_TYPE_MAP, STORAGE_TYPES, HOST_CPU_ARCHS } from '@/constants/compute'
  198. import { resolveValueChangeField } from '@/utils/common/ant'
  199. import { HYPERVISORS_MAP } from '@/constants'
  200. import { diskSupportTypeMedium, getOriginDiskKey } from '@/utils/common/hypervisor'
  201. import mixin from './mixin'
  202. import ContainerTitle from '../components/ContainerTitle'
  203. export default {
  204. name: 'VMContainer_IDCCreate',
  205. components: {
  206. SecgroupConfig,
  207. EipConfig,
  208. OsArch,
  209. ContainerTitle,
  210. SpecContainer,
  211. Labels,
  212. },
  213. mixins: [mixin],
  214. data () {
  215. return {
  216. isLocalDisk: true,
  217. timer: null,
  218. isFirstInit: true,
  219. storageHosts: {}, // 所有磁盘的storage-host
  220. storageHostParams: {}, // 第一个选择的块存储
  221. }
  222. },
  223. computed: {
  224. isKvm () {
  225. return this.form.fd.hypervisor === HYPERVISORS_MAP.kvm.key
  226. },
  227. isIso () {
  228. return this.form.fd.imageType === IMAGES_TYPE_MAP.iso.key
  229. },
  230. isArm () {
  231. return this.form.fd.os_arch === HOST_CPU_ARCHS.arm.key
  232. },
  233. isLoongarch64 () {
  234. return this.form.fd.os_arch === HOST_CPU_ARCHS.loongarch64.key
  235. },
  236. vdi () {
  237. return this.form.fd.vdi
  238. },
  239. hypervisors () {
  240. const { hypervisors = [] } = this.form.fi.capability
  241. return hypervisors
  242. },
  243. cloudregionParams () {
  244. return {
  245. cloud_env: 'onpremise',
  246. usable: true,
  247. show_emulated: true,
  248. ...this.scopeParams,
  249. }
  250. },
  251. zoneParams () {
  252. return {
  253. usable: true,
  254. show_emulated: true,
  255. order_by: 'created_at',
  256. order: 'asc',
  257. ...this.scopeParams,
  258. }
  259. },
  260. instanceGroupsParams () {
  261. return {
  262. ...this.scopeParams,
  263. enabled: true,
  264. }
  265. },
  266. cacheImageParams () {
  267. const params = {
  268. cloudregion_id: _.get(this.form.fd, 'cloudregion.key'),
  269. os_arch: HOST_CPU_ARCHS.x86.key,
  270. }
  271. if (!params.cloudregion_id) return {}
  272. if (this.form.fd.imageType === 'vmware') {
  273. params.image_type = 'system'
  274. }
  275. return params
  276. },
  277. showSku () {
  278. if (this.form.fd.hypervisor) {
  279. return true
  280. }
  281. return false
  282. },
  283. skuParam () {
  284. return {
  285. limit: 0,
  286. public_cloud: false,
  287. postpaid_status: 'available',
  288. cpu_core_count: this.form.fd.vcpu,
  289. memory_size_mb: this.form.fd.vmem,
  290. cloudregion: _.get(this.form, 'fd.cloudregion.key'),
  291. provider: 'OneCloud',
  292. ...this.scopeParams,
  293. }
  294. },
  295. policyHostParams () {
  296. const zone = _.get(this.form.fd, 'zone.key')
  297. if (zone) {
  298. const params = {
  299. enabled: 1,
  300. usable: true,
  301. zone,
  302. host_type: 'container',
  303. os_arch: HOST_CPU_ARCHS.x86.key,
  304. ...this.scopeParams,
  305. }
  306. if ([HYPERVISORS_MAP.esxi.key, HYPERVISORS_MAP.kvm.key].includes(params.hypervisor)) {
  307. if (this.form.fd[this.decorators.systemDisk.storage[0]]) {
  308. params.storage_id = this.form.fd[this.decorators.systemDisk.storage[0]]
  309. }
  310. if (this.storageHostParams.disk &&
  311. this.storageHostParams.disk !== 'system' &&
  312. this.storageHostParams.storageHosts &&
  313. this.storageHostParams.storageHosts.length &&
  314. !params.storage_id) {
  315. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  316. params.storage_id = this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]
  317. }
  318. }
  319. params.cloudprovider = this.form.fd.prefer_manager
  320. }
  321. if (this.isArm) params.os_arch = HOST_CPU_ARCHS.arm.key
  322. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  323. return params
  324. }
  325. return {}
  326. },
  327. networkParam () {
  328. if (!this.cloudregionZoneParams.cloudregion) return {}
  329. const params = {
  330. filter: 'server_type.notin(ipmi, pxe, eip, baremetal)',
  331. usable: true,
  332. ...this.cloudregionZoneParams,
  333. ...this.scopeParams,
  334. host_type: 'container',
  335. }
  336. if ([HYPERVISORS_MAP.kvm.key].includes(this.form.fd.hypervisor)) {
  337. if (this.storageHostParams.disk &&
  338. this.storageHostParams.disk !== 'system' &&
  339. this.storageHostParams.storageHosts &&
  340. this.storageHostParams.storageHosts.length &&
  341. !params.storage_id) {
  342. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  343. params.storage_id = this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]
  344. }
  345. }
  346. }
  347. return params
  348. },
  349. instanceSpecParmas () {
  350. return {
  351. usable: true,
  352. enabled: true,
  353. cloudregion: _.get(this.form.fd, 'cloudregion.key'),
  354. }
  355. },
  356. cloudproviderParamsExtra () {
  357. const params = {
  358. ...this.scopeParams,
  359. }
  360. if (this.form.fd.hypervisor && this.form.fd.hypervisor) {
  361. params.provider = HYPERVISORS_MAP[this.form.fd.hypervisor].provider
  362. }
  363. return params
  364. },
  365. showSchedCloudprovider () { // 创建VMware机器时,镜像类型不是 VMware 平台镜像时调度策略可以选择指定云账号
  366. return false
  367. },
  368. availableHostCount () { // 可用的宿主机数量
  369. if (R.is(Object, this.form.fi.capability)) {
  370. return this.form.fi.capability.available_host_count || 0
  371. }
  372. return 0
  373. },
  374. eipParams () {
  375. if (!this.cloudregionZoneParams.cloudregion) return {}
  376. return {
  377. project: this.project,
  378. region: this.cloudregionZoneParams.cloudregion,
  379. }
  380. },
  381. showEip () {
  382. const { vpcs, networkType } = this.form.fd
  383. if (networkType === NETWORK_OPTIONS_MAP.default.key) {
  384. return false
  385. }
  386. if (R.is(Object, vpcs)) {
  387. const vpcList = Object.values(vpcs)
  388. if (vpcList.length && !~vpcList.indexOf('default')) {
  389. return this.enableEip
  390. }
  391. }
  392. return false
  393. },
  394. storageParams () {
  395. const { systemDiskType = {}, hypervisor } = this.form.fd
  396. let key = systemDiskType.key || ''
  397. const params = {
  398. ...this.scopeParams,
  399. // usable: true, // 包含了 enable:true, status为online的数据
  400. brand: HYPERVISORS_MAP[this.form.fd.hypervisor]?.brand, // kvm,vmware支持指定存储
  401. manager: this.form.fd.prefer_manager,
  402. }
  403. // 磁盘区分介质
  404. if (diskSupportTypeMedium(hypervisor)) {
  405. const medium = getOriginDiskKey(key, true)
  406. key = getOriginDiskKey(key)
  407. params.filter = [
  408. `storage_type.contains("${key}")`,
  409. `medium_type.contains("${medium}")`,
  410. ]
  411. } else {
  412. params.filter = [
  413. `storage_type.contains("${key}")`,
  414. ]
  415. }
  416. return params
  417. },
  418. dataDiskStorageParams () {
  419. const { dataDiskSizes = {}, hypervisor } = this.form.fd
  420. let dataDiskType = ''
  421. let medium = ''
  422. for (const key in dataDiskSizes) {
  423. if (this.form.fd[`dataDiskTypes[${key}]`]) {
  424. dataDiskType = this.form.fd[`dataDiskTypes[${key}]`].key
  425. // 磁盘区分介质
  426. if (diskSupportTypeMedium(hypervisor)) {
  427. medium = getOriginDiskKey(dataDiskType, true)
  428. dataDiskType = getOriginDiskKey(dataDiskType)
  429. } else {
  430. dataDiskType = getOriginDiskKey(dataDiskType)
  431. }
  432. }
  433. }
  434. const params = {
  435. ...this.scopeParams,
  436. // usable: true, // 包含了 host status online 和 account 正常
  437. brand: HYPERVISORS_MAP[this.form.fd.hypervisor]?.brand, // kvm,vmware支持指定存储
  438. manager: this.form.fd.prefer_manager,
  439. }
  440. if (dataDiskType) {
  441. if (medium) {
  442. params.filter = [
  443. `storage_type.contains("${dataDiskType}")`,
  444. `medium_type.contains("${medium}")`,
  445. ]
  446. } else {
  447. params.filter = [`storage_type.contains("${dataDiskType}")`]
  448. }
  449. }
  450. return params
  451. },
  452. isStorageShow () { // 是否开启了指定存储
  453. if ([HYPERVISORS_MAP.esxi.key, HYPERVISORS_MAP.kvm.key].includes(this.form.fd.hypervisor)) {
  454. if (this.form.fd[this.decorators.systemDisk.storage[0]]) {
  455. return true
  456. }
  457. if (this.storageHostParams.disk &&
  458. this.storageHostParams.disk !== 'system' &&
  459. this.storageHostParams.storageHosts &&
  460. this.storageHostParams.storageHosts.length) {
  461. if (this.form.fd[`dataDiskStorages[${this.storageHostParams.disk}]`]) {
  462. return true
  463. }
  464. }
  465. }
  466. return false
  467. },
  468. imageParams () {
  469. const params = {
  470. ...this.scopeParams,
  471. os_arch: HOST_CPU_ARCHS.x86.key,
  472. }
  473. if (this.isArm) params.os_arch = HOST_CPU_ARCHS.arm.key
  474. if (this.isLoongarch64) params.os_arch = HOST_CPU_ARCHS.loongarch64.key
  475. return params
  476. },
  477. archOptions () {
  478. let opts = []
  479. if (this.form.fi.capability.host_cpu_archs && this.form.fi.capability.host_cpu_archs.length) {
  480. opts = this.form.fi.capability.host_cpu_archs.map(item => {
  481. if (item === HOST_CPU_ARCHS.arm.capabilityKey) return HOST_CPU_ARCHS.arm
  482. if (item === HOST_CPU_ARCHS.x86.capabilityKey) return HOST_CPU_ARCHS.x86
  483. if (item === HOST_CPU_ARCHS.loongarch64.capabilityKey) return HOST_CPU_ARCHS.loongarch64
  484. return item
  485. })
  486. }
  487. return opts.sort((a, b) => a.order - b.order)
  488. },
  489. extra () {
  490. if (this.isIso && this.isWindows) {
  491. return this.$t('compute.iso_windows_help')
  492. }
  493. return this.$t('compute.text_302')
  494. },
  495. enableEncryption () {
  496. return this.$appConfig.isPrivate
  497. },
  498. isMultiServer () {
  499. return this.form.fd.count > 1
  500. },
  501. portMappingDisableConf () {
  502. return {
  503. tooltip: '', // this.isMultiServer ? this.$t('compute.container.port_mapping.tooltip') : '',
  504. disabled: false, // this.isMultiServer,
  505. }
  506. },
  507. },
  508. watch: {
  509. 'form.fi.imageMsg': {
  510. deep: true,
  511. handler (val, oldVal) {
  512. if (R.equals(val, oldVal)) return
  513. this.$nextTick(() => {
  514. this.form.fi.dataDiskDisabled = false
  515. this.form.fi.sysDiskDisabled = false
  516. if (this.form.fd.imageType === IMAGES_TYPE_MAP.host.key) {
  517. const { root_image: rootImage, data_images: dataImages } = this.form.fi.imageMsg
  518. const systemDiskSize = rootImage.min_disk_mb / 1024
  519. const { hypervisor } = this.form.fd
  520. const { data_storage_types2 } = this.form.fi.capability
  521. const medium = data_storage_types2[hypervisor][0].split('/')[1]
  522. const systemDiskType = {
  523. key: data_storage_types2[hypervisor][0],
  524. label: STORAGE_TYPES[HYPERVISORS_MAP.kvm.key].local.label,
  525. }
  526. this.form.fc.setFieldsValue({
  527. systemDiskSize,
  528. systemDiskType,
  529. })
  530. // 重置数据盘数据
  531. this._resetDataDisk()
  532. if (dataImages) {
  533. dataImages.forEach(val => {
  534. this.$refs.dataDiskRef.add({ size: val.min_disk_mb / 1024, min: val.min_disk_mb / 1024, minusDisabled: true, medium })
  535. })
  536. }
  537. }
  538. if (this.form.fd.imageType === IMAGES_TYPE_MAP.snapshot.key || this.form.fd.imageType === IMAGES_TYPE_MAP.backup.key) {
  539. // 镜像类型为主机快照或主机备份的话要回填数据并禁用
  540. const snapshots = _.cloneDeep(this.form.fi.imageMsg.server_config.disks)
  541. if (!snapshots) return
  542. let sysDisk = snapshots.find(val => val.disk_type === 'sys')
  543. if (!sysDisk) {
  544. sysDisk = snapshots.shift()
  545. }
  546. const dataDisks = snapshots.filter(val => val.disk_type !== 'sys')
  547. const data = {
  548. systemDiskType: {
  549. key: `${sysDisk.backend}/${sysDisk.medium}`,
  550. label: STORAGE_TYPES[HYPERVISORS_MAP.kvm.key][sysDisk.backend].label,
  551. },
  552. systemDiskSize: sysDisk.size / 1024,
  553. }
  554. if (val && R.is(Object, val.server_config)) {
  555. if (val.server_config.vcpu_count) {
  556. const cpuValue = val.server_config.vcpu_count
  557. data[this.decorators.vcpu[0]] = cpuValue
  558. this.cpuChange(cpuValue)
  559. if (val.server_config.vmem_size) data[this.decorators.vmem[0]] = val.server_config.vmem_size
  560. }
  561. }
  562. this.form.fc.setFieldsValue(data)
  563. // 重置数据盘数据
  564. this._resetDataDisk()
  565. dataDisks.forEach(val => {
  566. this.$refs.dataDiskRef.add({ diskType: val.backend, size: val.size / 1024, sizeDisabled: true, medium: val.medium })
  567. })
  568. this.form.fi.dataDiskDisabled = true
  569. this.form.fi.sysDiskDisabled = true
  570. } else {
  571. if (oldVal && R.is(Object, oldVal.server_config)) { // 说明是从主机快照切换过去的
  572. const vcpuDecorator = this.decorators.vcpu
  573. const vcpuInit = vcpuDecorator[1].initialValue
  574. this.form.fc.setFieldsValue({
  575. [vcpuDecorator[0]]: vcpuInit,
  576. })
  577. this.cpuChange(vcpuInit)
  578. }
  579. }
  580. })
  581. },
  582. },
  583. isMultiServer (val) {
  584. if (val && this.$refs.labelRef) {
  585. this.$refs.labelRef.reset()
  586. this.form.fd.containerPorts = {}
  587. this.form.fd.hostPorts = {}
  588. }
  589. },
  590. },
  591. destroyed () {
  592. this.timer = null
  593. },
  594. methods: {
  595. vpcResourceMapper (list) {
  596. return list
  597. },
  598. onValuesChange (vm, changedFields) {
  599. this.$nextTick(() => {
  600. const formValue = this.form.fc.getFieldsValue()
  601. const newField = resolveValueChangeField(changedFields)
  602. this._setNewFieldToFd(newField, formValue)
  603. const keys = Object.keys(newField)
  604. if (keys.includes('zone') || keys.includes('cloudregion')) {
  605. this.fetchCapability()
  606. }
  607. if (keys.includes('cloudregion')) {
  608. this.$nextTick(this.fetchInstanceSpecs)
  609. }
  610. if (changedFields.schedPolicyType === 'host') {
  611. this.$set(this.form.fd, 'schedPolicyHost', undefined)
  612. }
  613. this.setIsLocalDisk()
  614. })
  615. },
  616. storageHostChange (val) {
  617. const { disk } = this.storageHostParams
  618. if (val.disk) {
  619. this.storageHosts[val.disk] = val
  620. }
  621. // 由第一块选择块存储的盘来确定块存储所在的host
  622. if (!disk || disk === val.disk) { // 第一块盘选
  623. if (val.storageHosts && val.storageHosts.length) {
  624. this.storageHostParams = val
  625. } else { // 清空操作
  626. let changeNew = false
  627. for (const key in this.storageHosts) {
  628. if (this.storageHosts[key].storageHosts && this.storageHosts[key].storageHosts.length) {
  629. this.storageHostParams = this.storageHosts[key] // 选其他已选的hosts作为新的范围
  630. changeNew = true
  631. break
  632. }
  633. }
  634. if (!changeNew) this.storageHostParams = {}
  635. }
  636. }
  637. },
  638. setIsLocalDisk () {
  639. const isLocal = (v = '') => { return v.startsWith('local') }
  640. const fd = this.form.fc.getFieldsValue()
  641. let isDiskLocal = true
  642. const { dataDiskTypes } = fd
  643. if (!R.is(Object, dataDiskTypes)) return
  644. const diskTypeItem = dataDiskTypes[Object.keys(dataDiskTypes)[0]]
  645. if (diskTypeItem && diskTypeItem.key) {
  646. isDiskLocal = isLocal(diskTypeItem.key)
  647. }
  648. this.isLocalDisk = isDiskLocal
  649. },
  650. fetchCapability () {
  651. const params = {
  652. show_emulated: true,
  653. resource_type: 'shared',
  654. ...this.scopeParams,
  655. }
  656. let id = this.cloudregionZoneParams.cloudregion
  657. let resource = 'cloudregions'
  658. if (this.cloudregionZoneParams.zone) {
  659. id = this.cloudregionZoneParams.zone
  660. resource = 'zones'
  661. }
  662. const capabilityParams = { id, spec: 'capability', params }
  663. if (!id) return
  664. if (R.equals(this.capabilityParams, capabilityParams)) return // 和已有的参数一样则不发请求
  665. this.capabilityParams = capabilityParams
  666. new this.$Manager(resource).getSpecific(this.capabilityParams)
  667. .then(({ data }) => {
  668. let hypervisors = R.is(Object, data) ? (data.hypervisors || []) : []
  669. if (hypervisors.includes(HYPERVISORS_MAP.kvm.key)) { // kvm 排序为第一个
  670. hypervisors = [HYPERVISORS_MAP.kvm.key].concat(hypervisors).filter(val => val !== 'baremetal')
  671. }
  672. hypervisors = Array.from(new Set(hypervisors))
  673. this.form.fi.capability = {
  674. ...data,
  675. hypervisors,
  676. }
  677. this.form.fc.setFieldsValue({
  678. hypervisor: hypervisors[0], // 赋值默认第一个平台
  679. })
  680. this.init()
  681. })
  682. },
  683. fetchInstanceSpecs () {
  684. if (!this.instanceSpecParmas.cloudregion) return
  685. this.serverskusM.get({ id: 'instance-specs', params: this.instanceSpecParmas })
  686. .then(({ data }) => {
  687. this.form.fi.cpuMem = data
  688. const vcpuDecorator = this.decorators.vcpu
  689. const vcpuInit = vcpuDecorator[1].initialValue
  690. const cpu = this.form.fd.vcpu || vcpuInit
  691. this.cpuChange(cpu)
  692. })
  693. },
  694. gpuChange (val) {
  695. if (!val) {
  696. this.form.fc.setFieldsValue({ gpu: '' })
  697. }
  698. },
  699. init () {
  700. if (this.isFirstInit) {
  701. this.initOsArch()
  702. this.isFirstInit = false
  703. }
  704. },
  705. initOsArch () {
  706. this.timer = setTimeout(() => {
  707. const { os_arch } = this.$route.query
  708. // 数据延迟回填
  709. if (os_arch) {
  710. let canUseOsArch = ''
  711. if (os_arch.indexOf('x86') !== -1) {
  712. canUseOsArch = HOST_CPU_ARCHS.x86.key
  713. } else if (os_arch.indexOf('aarch') !== -1) {
  714. canUseOsArch = HOST_CPU_ARCHS.arm.key
  715. }
  716. if (!canUseOsArch) return
  717. this.form.fc.setFieldsValue({ os_arch: canUseOsArch })
  718. }
  719. }, 3000)
  720. },
  721. getMachineDecorator () {
  722. let initValue = 'pc'
  723. if (this.isArm) {
  724. initValue = 'virt'
  725. }
  726. return [
  727. 'machine',
  728. {
  729. initialValue: initValue,
  730. },
  731. ]
  732. },
  733. },
  734. }
  735. </script>