SetHostCpuReserveResourceDialog.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{ title }}</div>
  4. <div slot="body">
  5. <a-alert class="mb-2" type="warning">
  6. <template v-slot:message>{{ $t('compute.host.cpu.revert.resource.message') }}</template>
  7. </a-alert>
  8. <a-alert class="mb-2" type="warning">
  9. <template v-slot:message>{{ $t('compute.host.cpu.revert.resource.message_1') }}</template>
  10. </a-alert>
  11. <dialog-selected-tips :name="$t('dictionary.host')" :count="params.data.length" :action="title" />
  12. <dialog-table :data="params.data" :columns="columns" />
  13. <a-form :form="form.fc" hideRequiredMark v-bind="formItemLayout">
  14. <a-form-item :label="$t('compute.executable_file_name')" :extra="$t('compute.executable_file_name.extra')">
  15. <a-textarea v-decorator="decorators.processes_prefix" :rows="5" />
  16. </a-form-item>
  17. <a-form-item :label="$t('compute.text_1058')" :extra="cpuExtra">
  18. <a-checkbox-group
  19. v-decorator="decorators.cpus"
  20. style="width: 100%; margin-top: 10px;">
  21. <a-row>
  22. <a-col :span="4" v-for="v in hostCpus" :key="v">
  23. <a-checkbox :value="v - 1">{{ v - 1 }}</a-checkbox>
  24. </a-col>
  25. </a-row>
  26. </a-checkbox-group>
  27. </a-form-item>
  28. <a-form-item label="Numa Node">
  29. <a-checkbox-group
  30. v-decorator="decorators.nodes"
  31. style="width: 100%; margin-top: 10px;">
  32. <a-row>
  33. <a-col :span="4" v-for="v in hostNodes" :key="v">
  34. <a-checkbox :value="v - 1">{{ v - 1 }}</a-checkbox>
  35. </a-col>
  36. </a-row>
  37. </a-checkbox-group>
  38. </a-form-item>
  39. </a-form>
  40. </div>
  41. <div slot="footer">
  42. <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
  43. <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
  44. </div>
  45. </base-dialog>
  46. </template>
  47. <script>
  48. import _ from 'lodash'
  49. import DialogMixin from '@/mixins/dialog'
  50. import WindowsMixin from '@/mixins/windows'
  51. import {
  52. getNameDescriptionTableColumn,
  53. } from '@/utils/common/tableColumn'
  54. export default {
  55. name: 'SetHostCpuReserveResourceDialog',
  56. mixins: [DialogMixin, WindowsMixin],
  57. data () {
  58. return {
  59. title: this.$t('compute.host.set_system_reserve_resource'),
  60. loading: false,
  61. form: {
  62. fc: this.$form.createForm(this, {
  63. onValuesChange: (props, values) => {
  64. Object.keys(values).forEach((key) => {
  65. this.form.fd[key] = values[key]
  66. })
  67. },
  68. }),
  69. fd: {
  70. cpus: [],
  71. processes_prefix: '',
  72. nodes: [],
  73. },
  74. },
  75. columns: [
  76. getNameDescriptionTableColumn({
  77. onManager: this.params.onManager,
  78. hideField: true,
  79. slotCallback: row => {
  80. return (
  81. <side-page-trigger onTrigger={ () => this.handleOpenSidepage(row, 'host-detail') }>{ row.name }</side-page-trigger>
  82. )
  83. },
  84. }),
  85. {
  86. field: 'custom_ip',
  87. title: 'IP',
  88. width: 200,
  89. showOverflow: 'ellipsis',
  90. slots: {
  91. default: ({ row }) => {
  92. const cellWrap = []
  93. if (row.access_ip) {
  94. cellWrap.push(
  95. <div class="d-flex">
  96. <list-body-cell-wrap row={row} field="access_ip" copy><span class="text-color-help">{this.$t('compute.text_1319')}</span></list-body-cell-wrap>
  97. </div>,
  98. )
  99. }
  100. if (row.ipmi_ip) {
  101. cellWrap.push(
  102. <div class="d-flex">
  103. <list-body-cell-wrap row={row} field="ipmi_ip" copy><span class="text-color-help">{this.$t('compute.text_1320')}</span></list-body-cell-wrap>
  104. </div>,
  105. )
  106. }
  107. return cellWrap
  108. },
  109. },
  110. },
  111. {
  112. field: 'nonsystem_guests',
  113. sortBy: 'order_by_server_count',
  114. title: '#VM',
  115. width: 60,
  116. sortable: true,
  117. slots: {
  118. default: ({ row }, h) => {
  119. if (this.isPreLoad && row.nonsystem_guests === undefined) return [<data-loading />]
  120. return `${row.nonsystem_guests}`
  121. },
  122. },
  123. },
  124. ],
  125. decorators: {
  126. processes_prefix: [
  127. 'processes_prefix',
  128. ],
  129. cpus: [
  130. 'cpus',
  131. ],
  132. nodes: [
  133. 'nodes',
  134. ],
  135. },
  136. formItemLayout: {
  137. wrapperCol: {
  138. span: 20,
  139. },
  140. labelCol: {
  141. span: 4,
  142. },
  143. },
  144. selectedItems: [],
  145. }
  146. },
  147. computed: {
  148. cpuExtra () {
  149. return this.form.fd.cpus.length === 0 ? this.$t('compute.host.cpu_reserve_extra') : null
  150. },
  151. selectedItem () {
  152. return this.selectedItems && this.selectedItems[0]
  153. },
  154. isSingle () {
  155. return this.selectedItems?.length === 1
  156. },
  157. hostCpus () {
  158. const cpuCounts = this.selectedItems.map(item => item.cpu_count)
  159. return Math.max(...cpuCounts)
  160. },
  161. hostNodes () {
  162. const cpuCounts = this.selectedItems.map(item => (item.sys_info?.topology?.nodes || []).length)
  163. return Math.max(...cpuCounts)
  164. },
  165. },
  166. created () {
  167. this.init()
  168. },
  169. methods: {
  170. // split(/\r*\n/)
  171. async init () {
  172. try {
  173. const res = await new this.$Manager('hosts').list({
  174. params: {
  175. filter: `id.in(${this.params.data.map(item => item.id).join(',')})`,
  176. },
  177. })
  178. this.selectedItems = res.data.data || []
  179. } catch (error) {
  180. throw error
  181. }
  182. if (this.selectedItems.length === 0) {
  183. this.selectedItems = this.params.data
  184. }
  185. const arr = this.selectedItems.map(item => {
  186. const reserved_cpus_info = JSON.parse(item.metadata.reserved_cpus_info || '{}')
  187. const cpus = item.metadata.reserved_cpus_info ? (reserved_cpus_info?.cpus || '').split(',').map(v => parseInt(v)) : []
  188. const processes_prefix = item.metadata.reserved_cpus_info ? reserved_cpus_info?.processes_prefix || [] : []
  189. const mems = item.metadata.reserved_cpus_info ? (reserved_cpus_info?.mems || '').split(',').map(v => parseInt(v)) : []
  190. return { cpus, mems, processes_prefix }
  191. })
  192. this.$nextTick(() => {
  193. this.form.fc.setFieldsValue({
  194. cpus: _.intersection(...(arr.map(item => item.cpus))),
  195. processes_prefix: _.intersection(...(arr.map(item => item.processes_prefix))).join('\n'),
  196. nodes: _.intersection(...(arr.map(item => item.mems))),
  197. })
  198. })
  199. },
  200. doReserveResourceSubmit (values) {
  201. const { cpus, nodes, processes_prefix = [] } = values
  202. const ids = this.params.data.map(item => item.id)
  203. const params = { cpus: cpus.join(','), mems: nodes.join(','), processes_prefix }
  204. if (this.isSingle) {
  205. if (cpus.length === 0) {
  206. return this.params.onManager('performAction', {
  207. id: ids[0],
  208. steadyStatus: ['ready'],
  209. managerArgs: {
  210. action: 'unreserve-cpus',
  211. },
  212. })
  213. }
  214. return this.params.onManager('performAction', {
  215. id: ids[0],
  216. steadyStatus: ['ready'],
  217. managerArgs: {
  218. action: 'reserve-cpus',
  219. data: params,
  220. },
  221. })
  222. } else {
  223. if (cpus.length === 0) {
  224. return this.params.onManager('batchPerformAction', {
  225. id: ids,
  226. steadyStatus: ['ready'],
  227. managerArgs: {
  228. action: 'unreserve-cpus',
  229. },
  230. })
  231. }
  232. return this.params.onManager('batchPerformAction', {
  233. id: ids,
  234. steadyStatus: ['ready'],
  235. managerArgs: {
  236. action: 'reserve-cpus',
  237. data: params,
  238. },
  239. })
  240. }
  241. },
  242. async handleConfirm () {
  243. this.loading = true
  244. try {
  245. const values = await this.form.fc.validateFields()
  246. values.processes_prefix = (values.processes_prefix || '').split(/\r*\n/).filter(v => v.trim() !== '')
  247. await this.doReserveResourceSubmit(values)
  248. this.params.refresh && this.params.refresh()
  249. this.cancelDialog()
  250. this.$message.success(this.$t('compute.text_423'))
  251. } catch (error) {
  252. throw error
  253. } finally {
  254. this.loading = false
  255. }
  256. },
  257. },
  258. }
  259. </script>