CreateKubemachinesDialog.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{$t('k8s.create')}}</div>
  4. <div slot="body">
  5. <a-alert :showIcon="false" banner class="mt-2">
  6. <template slot="message">
  7. <div>
  8. <p>{{$t('k8s.text_147')}}</p>
  9. <p>{{$t('k8s.text_148')}}</p>
  10. </div>
  11. </template>
  12. </a-alert>
  13. <a-form
  14. class="mt-3"
  15. :form="form.fc">
  16. <a-form-item :label="$t('k8s.text_152')" v-bind="formItemLayout">
  17. <server-config
  18. :decorator="decorators.serverConfig"
  19. :networkParams="networkParams"
  20. :form="form"
  21. :cloudregionId="params.data.cloudregion_id"
  22. :hypervisor="hypervisor"
  23. :platform="platform"
  24. @vmAdd="vmAdd">
  25. <template v-slot:hypervisor="slotProps">
  26. <a-form-item :label="$t('k8s.platform')" v-if="hypervisorsC.length" v-bind="slotProps.formItemLayout">
  27. <a-radio-group v-decorator="decorators.serverConfig.hypervisor(slotProps.i)">
  28. <a-radio-button v-for="item in hypervisorsC" :key="item.value" :value="item.value">
  29. {{ item.label }}
  30. </a-radio-button>
  31. </a-radio-group>
  32. </a-form-item>
  33. </template>
  34. </server-config>
  35. </a-form-item>
  36. </a-form>
  37. </div>
  38. <div slot="footer">
  39. <a-button type="primary" @click="handleConfirm" :loading="loading">{{$t('common.create')}}</a-button>
  40. <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
  41. </div>
  42. </base-dialog>
  43. </template>
  44. <script>
  45. import _ from 'lodash'
  46. import { mapGetters } from 'vuex'
  47. import ServerConfig from '@K8S/sections/serverConfig'
  48. import { IMAGES_TYPE_MAP } from '@/constants/compute'
  49. import { HYPERVISORS_MAP } from '@/constants'
  50. import { hyperOpts } from '@K8S/views/cluster/constants'
  51. import { isWithinRange, isRequired } from '@/utils/validate'
  52. import DialogMixin from '@/mixins/dialog'
  53. import WindowsMixin from '@/mixins/windows'
  54. import { typeClouds, findPlatform } from '@/utils/common/hypervisor'
  55. import i18n from '@/locales'
  56. function checkIpInSegment (i, networkData) {
  57. return (rule, value, _callback) => {
  58. const isIn = isWithinRange(value, networkData.guest_ip_start, networkData.guest_ip_end)
  59. if (isIn) {
  60. _callback()
  61. } else {
  62. _callback(this.$t('k8s.text_163'))
  63. }
  64. }
  65. }
  66. export default {
  67. name: 'CreateKubemachinesDialog',
  68. components: {
  69. ServerConfig,
  70. },
  71. mixins: [DialogMixin, WindowsMixin],
  72. data () {
  73. const hypervisor = _.get(typeClouds.providerlowcaseMap, `[${this.params.data.provider}].hypervisor`) || 'kvm'
  74. return {
  75. loading: false,
  76. form: {
  77. fc: this.$form.createForm(this, {
  78. onValuesChange: (props, values) => {
  79. /*
  80. * if (values.zone && values.zone.key) {
  81. * this.param.network = {
  82. * vpc: this.data.vpc_id,
  83. * filter: 'server_type.notin(ipmi, pxe)',
  84. * scope: this.scope,
  85. * }
  86. * this.fetchCapability(values.zone.key, 'zone')
  87. * }
  88. */
  89. /*
  90. * if (values.cloudregion && values.cloudregion.key) {
  91. * this.fetchCapability(values.cloudregion.key, 'cloudregion')
  92. * }
  93. */
  94. Object.keys(values).forEach((key) => {
  95. this.form.fd[key] = values[key]
  96. })
  97. },
  98. }),
  99. fi: {
  100. capability: {},
  101. clusterHypervisor: hypervisor, // 该集群的默认 hypervisor
  102. },
  103. fd: {
  104. hypervisor,
  105. },
  106. },
  107. decorators: {
  108. serverConfig: {
  109. hypervisor: i => [
  110. `hypervisors[${i}]`,
  111. {
  112. initialValue: hypervisor,
  113. rules: [
  114. { required: true, message: this.$t('k8s.text_99') },
  115. ],
  116. },
  117. ],
  118. sku: i => [
  119. `sku[${i}]`,
  120. {
  121. rules: [
  122. { validator: isRequired(true, 'id'), message: this.$t('compute.text_216') },
  123. ],
  124. },
  125. ],
  126. disk: i => ({
  127. type: [
  128. `systemDiskType[${i}]`,
  129. {
  130. rules: [
  131. { validator: isRequired(), message: this.$t('compute.text_121') },
  132. ],
  133. },
  134. ],
  135. size: [
  136. `systemDiskSize[${i}]`,
  137. {
  138. rules: [
  139. { required: true, message: this.$t('compute.text_122') },
  140. ],
  141. },
  142. ],
  143. schedtag: [
  144. `systemDiskSchedtag[${i}]`,
  145. {
  146. validateTrigger: ['change', 'blur'],
  147. rules: [{
  148. required: true,
  149. message: this.$t('compute.text_123'),
  150. }],
  151. },
  152. ],
  153. policy: [
  154. `systemDiskPolicy[${i}]`,
  155. {
  156. validateTrigger: ['blur', 'change'],
  157. rules: [{
  158. required: true,
  159. message: this.$t('compute.text_123'),
  160. }],
  161. },
  162. ],
  163. }),
  164. network: i => [
  165. `network[${i}]`,
  166. {
  167. rules: [
  168. { required: true, message: this.$t('k8s.text_122') },
  169. ],
  170. },
  171. ],
  172. ip: (i, networkData) => [
  173. `ip[${i}]`,
  174. {
  175. validateFirst: true,
  176. validateTrigger: ['blur', 'change'],
  177. rules: [{
  178. required: true,
  179. message: this.$t('k8s.text_169'),
  180. }, {
  181. validator: checkIpInSegment(i, networkData),
  182. }],
  183. },
  184. ],
  185. num: i => [
  186. `num[${i}]`,
  187. {
  188. initialValue: 1,
  189. rules: [
  190. { required: true, message: this.$t('k8s.text_170') },
  191. ],
  192. },
  193. ],
  194. role: i => [
  195. `role[${i}]`,
  196. {
  197. initialValue: 'controlplane',
  198. },
  199. ],
  200. imageOS: i => [
  201. `imageOS[${i}]`,
  202. {
  203. os: [
  204. `os[${i}]`,
  205. {
  206. initialValue: '',
  207. rules: [
  208. { required: true, message: i18n.t('compute.text_153') },
  209. ],
  210. },
  211. ],
  212. image: [
  213. `image[${i}]`,
  214. {
  215. initialValue: { key: '', label: '' },
  216. rules: [
  217. { validator: isRequired(), message: i18n.t('compute.text_214') },
  218. ],
  219. },
  220. ],
  221. imageType: [
  222. `imageType[${i}]`,
  223. {
  224. initialValue: IMAGES_TYPE_MAP.standard.key,
  225. },
  226. ],
  227. },
  228. ],
  229. },
  230. },
  231. formItemLayout: {
  232. wrapperCol: { span: 20 },
  233. labelCol: { span: 3 },
  234. },
  235. param: {
  236. zone: {
  237. usable: true,
  238. show_emulated: true,
  239. order_by: 'created_at',
  240. order: 'asc',
  241. scope: this.scope,
  242. },
  243. region: {
  244. usable: true,
  245. scope: this.scope,
  246. cloud_env: 'onpremise',
  247. },
  248. network: {},
  249. k8sVersions: {
  250. provider: this.hypervisor,
  251. resource_type: 'guest',
  252. },
  253. },
  254. }
  255. },
  256. provide () {
  257. return {
  258. form: this.form,
  259. }
  260. },
  261. computed: {
  262. ...mapGetters(['scope']),
  263. hypervisorsC () {
  264. const opts = hyperOpts.filter(item => {
  265. return (_.get(this.form.fi, 'capability.hypervisors') || []).find(val => val === item.value.toLowerCase())
  266. })
  267. return opts
  268. },
  269. networkParams () {
  270. return {
  271. vpc: this.params.data.vpc_id,
  272. filter: 'server_type.notin(ipmi, pxe)',
  273. scope: this.scope,
  274. }
  275. },
  276. hypervisor () {
  277. return this.form.fd.hypervisor
  278. },
  279. platform () {
  280. return findPlatform(this.hypervisor, 'hypervisor')
  281. },
  282. },
  283. created () {
  284. this.form.fc.getFieldDecorator('cloudregion', { preserve: true })
  285. this.form.fc.getFieldDecorator('zone', { preserve: true })
  286. },
  287. methods: {
  288. validator (type) {
  289. return (rule, value, _callback) => {
  290. if (type === 'vcpu_count') {
  291. if (value < 4 || value > 32) {
  292. return _callback(this.$t('k8s.text_172'))
  293. }
  294. } else if (type === 'vmem_size') {
  295. if (value < 4 || value > 128) {
  296. return _callback(this.$t('k8s.text_173'))
  297. }
  298. } else if (type === 'disk') {
  299. if (value < 1 || value > 128) {
  300. return _callback(this.$t('k8s.text_174'))
  301. }
  302. }
  303. return _callback()
  304. }
  305. },
  306. doCreate (data) {
  307. return new this.$Manager('kubeclusters', 'v1').performAction({
  308. id: this.params.data.id,
  309. action: 'add-machines',
  310. data,
  311. })
  312. },
  313. genData (data) {
  314. const values = {
  315. machines: [],
  316. }
  317. Object.keys(data.sku).map(key => {
  318. const disks = [{
  319. index: 0,
  320. size: data.systemDiskSize[key] * 1024,
  321. backend: data.systemDiskType[key].key,
  322. }]
  323. if (data.systemDiskSchedtag) {
  324. if (data.systemDiskSchedtag[key] && data.systemDiskPolicy[key]) {
  325. disks[0].schedtags = [{ id: data.systemDiskSchedtag[key], strategy: data.systemDiskPolicy[key] }]
  326. }
  327. }
  328. if (this.hypervisor === HYPERVISORS_MAP.kvm.key || this.hypervisor === HYPERVISORS_MAP.cloudpods.key) {
  329. const backend = disks[0].backend
  330. disks[0].backend = backend.split('/')[0]
  331. disks[0].medium = backend.split('/')[1]
  332. }
  333. if (data.image && data.image[key]) {
  334. disks[0].image_id = data.image[key].key
  335. }
  336. const machinesItem = {
  337. vm: {
  338. /*
  339. * vcpu_count: data.vcpu_count[key],
  340. * vmem_size: data.vmem_size[key] * 1024,
  341. */
  342. instance_type: data.sku[key].name,
  343. hypervisor: this.hypervisor,
  344. disks,
  345. nets: [{ network: data.network[key] }],
  346. },
  347. }
  348. if (data.ip && data.ip[key]) machinesItem.vm.nets[0].address = data.ip[key]
  349. if (data.num[key] > 1) {
  350. for (let i = 0; i < data.num[key]; i++) {
  351. values.machines.push({ config: machinesItem, role: data.role[key], resource_type: 'vm' })
  352. }
  353. } else {
  354. values.machines.push({ config: machinesItem, role: data.role[key], resource_type: 'vm' })
  355. }
  356. })
  357. return values
  358. },
  359. async handleConfirm () {
  360. this.loading = true
  361. try {
  362. const values = await this.form.fc.validateFields()
  363. const genValues = this.genData(values)
  364. await this.doCreate(genValues)
  365. this.loading = false
  366. this.$message.success(this.$t('k8s.text_281'))
  367. this.params.refresh()
  368. this.cancelDialog()
  369. } catch (error) {
  370. this.loading = false
  371. throw error
  372. }
  373. },
  374. async fetchCapability (id, resource) {
  375. const params = {
  376. show_emulated: true,
  377. resource_type: 'shared',
  378. scope: this.scope,
  379. }
  380. const capabilityParams = { id, spec: 'capability', params }
  381. if (!id) return
  382. this.capabilityParams = capabilityParams
  383. try {
  384. const { data } = await new this.$Manager(`${resource}s`).getSpecific(this.capabilityParams)
  385. this.form.fi.capability = data
  386. await this.$nextTick()
  387. if (this.hypervisorsC.length) {
  388. const hasDefaultHypervisor = this.hypervisorsC.find(val => val.value === this.form.fi.clusterHypervisor)
  389. if (!hasDefaultHypervisor) {
  390. const { hypervisors } = this.form.fc.getFieldsValue()
  391. const values = {}
  392. for (const key in hypervisors) {
  393. values[`hypervisors[${key}]`] = this.hypervisorsC[0].value
  394. }
  395. this.form.fc.setFieldsValue(values)
  396. }
  397. }
  398. } catch (error) {
  399. throw error
  400. }
  401. },
  402. vmAdd ({ key }) {
  403. if (this.hypervisorsC.length) {
  404. this.form.fc.setFieldsValue({
  405. [`hypervisors[${key}]`]: this.hypervisorsC[0].value,
  406. })
  407. }
  408. },
  409. },
  410. }
  411. </script>