SnapshotCreate.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{$t('compute.disk_perform_create_snapshot')}}</div>
  4. <div slot="body">
  5. <a-alert class="mb-2" type="warning">
  6. <div slot="message">{{$t('compute.text_1251')}}</div>
  7. </a-alert>
  8. <dialog-selected-tips :name="$t('dictionary.server')" :count="params.data.length" :action="$t('compute.disk_perform_create_snapshot')" />
  9. <dialog-table
  10. :data="params.data"
  11. :columns="params.columns.slice(0, 3)" />
  12. <a-form :form="form.fc" v-bind="formItemLayout">
  13. <a-form-item :label="$t('compute.text_1071')" v-if="isKvm || isEsxi">
  14. <a-radio-group
  15. v-decorator="decorators.snapshotType"
  16. @change="snapshotTypeChangeHandle">
  17. <a-tooltip>
  18. <template slot="title" v-if="isEsxi">
  19. <span>{{$t('compute.text_1358')}}</span>
  20. </template>
  21. <a-radio value="disk" :disabled="isEsxi">{{$t('compute.text_101')}}</a-radio>
  22. </a-tooltip>
  23. <a-radio value="instance">{{$t('compute.text_102')}}</a-radio>
  24. </a-radio-group>
  25. </a-form-item>
  26. <a-form-item
  27. :label="$t('compute.text_1254')"
  28. v-if="isDiskSnapshot">
  29. <base-select
  30. style="width: 100%"
  31. v-decorator="decorators.disk"
  32. :params="diskParams"
  33. :select-props="{ placeholder: $t('compute.text_1085') }"
  34. resource="disks"
  35. idKey="disk_id"
  36. nameKey="disk"
  37. :label-format="getDiskLabel"
  38. :ctx="[['servers', this.params.data[0].id]]"
  39. :filterable="true"
  40. :isDefaultSelect="true"
  41. :item.sync="selectDisk" />
  42. </a-form-item>
  43. <a-form-item
  44. :label="$t('compute.text_415')">
  45. <a-input
  46. v-decorator="decorators.snapshotName"
  47. :placeholder="$t('validator.resourceName')" />
  48. <div slot="extra">
  49. <div v-if="showRepeatTips">{{$t('compute.text_1091')}}</div>
  50. <div v-show="!isDiskSnapshot">{{$t('compute.text_1255', [ diskCount ])}}</div>
  51. </div>
  52. </a-form-item>
  53. <a-form-item v-if="!isDiskSnapshot">
  54. <a-tooltip>
  55. <template v-if="!isRunningVm" slot="title">
  56. {{$t('compute.create_mem_snapshot_limit')}}
  57. </template>
  58. <a-checkbox
  59. v-decorator="decorators.with_memory"
  60. :disabled="!isRunningVm">
  61. {{$t('compute.create_mem_snapshot_same_time')}}
  62. </a-checkbox>
  63. </a-tooltip>
  64. </a-form-item>
  65. </a-form>
  66. </div>
  67. <div slot="footer">
  68. <a-button type="primary" @click="handleConfirm" :loading="loading" :disabled="disabledSubmit">{{
  69. $t("dialog.ok")
  70. }}</a-button>
  71. <a-button @click="cancelDialog">{{ $t("dialog.cancel") }}</a-button>
  72. </div>
  73. </base-dialog>
  74. </template>
  75. <script>
  76. import debounce from 'lodash/debounce'
  77. import * as R from 'ramda'
  78. import { DISK_TYPE } from '@Compute/constants'
  79. import { INPUT_DEBOUNCE_TIMER } from '@/constants/config'
  80. import DialogMixin from '@/mixins/dialog'
  81. import WindowsMixin from '@/mixins/windows'
  82. import { sizestr } from '@/utils/utils'
  83. import { typeClouds } from '@/utils/common/hypervisor'
  84. const hypervisorMap = typeClouds.hypervisorMap
  85. export default {
  86. name: 'VmSnapshotCreateDialog',
  87. mixins: [DialogMixin, WindowsMixin],
  88. data () {
  89. return {
  90. loading: false,
  91. showRepeatTips: false,
  92. form: {
  93. fc: this.$form.createForm(this, {
  94. name: 'snapshort_create_form',
  95. onFieldsChange: this.onFieldsChange,
  96. onValuesChange: this.onValuesChange,
  97. }),
  98. fd: {
  99. snapshotName: '',
  100. snapshotType: this.params.data[0].hypervisor === hypervisorMap.esxi.key ? 'instance' : 'disk',
  101. },
  102. },
  103. decorators: {
  104. snapshotType: [
  105. 'snapshotType',
  106. {
  107. initialValue: this.params.data[0].hypervisor === hypervisorMap.esxi.key ? 'instance' : 'disk',
  108. },
  109. ],
  110. disk: [
  111. 'disk',
  112. {
  113. rules: [
  114. { required: true, message: this.$t('compute.text_1085'), trigger: 'change' },
  115. ],
  116. },
  117. ],
  118. snapshotName: [
  119. 'snapshotName',
  120. {
  121. validateFirst: true,
  122. rules: [
  123. { required: true, message: this.$t('compute.text_1256') },
  124. { validator: this.$validate('resourceName') },
  125. ],
  126. },
  127. ],
  128. with_memory: [
  129. 'with_memory',
  130. ],
  131. },
  132. formItemLayout: {
  133. labelCol: { span: 4 },
  134. wrapperCol: { span: 20 },
  135. },
  136. selectDisk: {},
  137. disabledSubmit: false,
  138. }
  139. },
  140. computed: {
  141. isKvm () {
  142. return this.params.data[0].hypervisor === hypervisorMap.kvm.key
  143. },
  144. isEsxi () {
  145. return this.params.data[0].hypervisor === hypervisorMap.esxi.key
  146. },
  147. diskParams () {
  148. return {
  149. scope: this.$store.getters.scope,
  150. details: true,
  151. with_meta: true,
  152. }
  153. },
  154. isDiskSnapshot () {
  155. if (this.params.data[0].hypervisor === hypervisorMap.cnware.key) {
  156. return false
  157. }
  158. return this.form.fd.snapshotType === 'disk'
  159. },
  160. manager () {
  161. return new this.$Manager(this.isDiskSnapshot ? 'snapshots' : 'instance_snapshots', 'v2')
  162. },
  163. diskCount () {
  164. return this.params.data[0].disk_count
  165. },
  166. isRunningVm () {
  167. return this.params.data[0].status === 'running'
  168. },
  169. },
  170. watch: {
  171. 'form.fd.snapshotName' (val) {
  172. this.debounceCheckTemplateName()
  173. },
  174. 'selectDisk' (val) {
  175. this.disabledSubmit = val.storage_type === 'nova'
  176. },
  177. },
  178. created () {
  179. this.debounceCheckTemplateName = debounce(() => {
  180. this.checkTemplateName()
  181. }, INPUT_DEBOUNCE_TIMER)
  182. },
  183. methods: {
  184. checkTemplateName () {
  185. const snapshotName = this.form.fd.snapshotName
  186. if (!R.isNil(snapshotName) && !R.isEmpty(snapshotName)) {
  187. this.manager.get({ id: snapshotName, params: { scope: this.$store.getters.scope } })
  188. .then(res => {
  189. const data = res.data
  190. if (!R.isNil(data) && !R.isEmpty(data)) {
  191. this.showRepeatTips = true // 重复名字
  192. }
  193. }).catch(() => {
  194. this.showRepeatTips = false
  195. })
  196. } else {
  197. this.showRepeatTips = false
  198. }
  199. },
  200. validateForm (fileds = []) {
  201. return new Promise((resolve, reject) => {
  202. this.form.fc.validateFields(fileds, (err, values) => {
  203. if (!err) {
  204. resolve(values)
  205. } else {
  206. reject(err)
  207. }
  208. })
  209. })
  210. },
  211. async doCreateDiskSnapshot () {
  212. const values = await this.validateForm(['disk', 'snapshotName'])
  213. const params = {
  214. disk: values.disk,
  215. generate_name: values.snapshotName,
  216. }
  217. return this.manager.create({ data: params })
  218. },
  219. async doCreateInstanceSnapshot () {
  220. const values = await this.validateForm(['snapshotName', 'with_memory'])
  221. const params = {
  222. generate_name: values.snapshotName,
  223. }
  224. if (values.with_memory) {
  225. params.with_memory = true
  226. }
  227. return this.params.onManager('performAction', {
  228. id: this.params.data[0].id,
  229. steadyStatus: ['running', 'ready'],
  230. managerArgs: {
  231. action: 'instance-snapshot',
  232. data: params,
  233. },
  234. })
  235. },
  236. async handleConfirm () {
  237. this.loading = true
  238. try {
  239. if (this.isDiskSnapshot) {
  240. await this.doCreateDiskSnapshot()
  241. } else {
  242. await this.doCreateInstanceSnapshot()
  243. }
  244. this.loading = false
  245. this.params.refresh()
  246. this.cancelDialog()
  247. this.$message.success(this.$t('compute.text_322'))
  248. } catch (error) {
  249. this.loading = false
  250. this.cancelDialog()
  251. }
  252. },
  253. getDiskLabel (item) {
  254. return `${item.disk}(${
  255. item.disk_type === DISK_TYPE.sys.value
  256. ? DISK_TYPE.sys.text
  257. : DISK_TYPE.data.text
  258. }, ${sizestr(item.disk_size, 'M', 1024)})`
  259. },
  260. snapshotTypeChangeHandle (e) {
  261. this.$nextTick(() => {
  262. this.debounceCheckTemplateName()
  263. })
  264. },
  265. onValuesChange (props, values) {
  266. Object.keys(values).forEach((key) => {
  267. this.form.fd[key] = values[key]
  268. })
  269. },
  270. },
  271. }
  272. </script>