singleActions.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. import { mapGetters } from 'vuex'
  2. // import { Base64 } from 'js-base64'
  3. import qs from 'qs'
  4. import { typeClouds, getDisabledProvidersActionMeta } from '@/utils/common/hypervisor'
  5. import { getDomainChangeOwnerAction, getSetPublicAction, getEnabledSwitchActions } from '@/utils/common/tableActions'
  6. import i18n from '@/locales'
  7. import { HOST_CPU_ARCHS } from '@/constants/compute'
  8. import { SMART_SSH_FORM_DECORATORS } from '@Compute/constants'
  9. import { solWebConsole, jnlpConsole } from '../../../utils/webconsole'
  10. export default {
  11. destroyed () {
  12. this.manager = null
  13. },
  14. created () {
  15. this.webconsoleManager = new this.$Manager('webconsole', 'v1')
  16. },
  17. computed: {
  18. ...mapGetters(['isAdminMode', 'userInfo', 'auth', 'common']),
  19. enableMFA () {
  20. return this.userInfo.enable_mfa && this.auth.auth.system_totp_on
  21. },
  22. singleActions () {
  23. const _frontSingleActions = this.frontSingleActions ? this.frontSingleActions.bind(this)() || [] : []
  24. return _frontSingleActions.concat([
  25. {
  26. label: i18n.t('compute.text_567'),
  27. permission: 'hosts_perform_login_info',
  28. actions: obj => {
  29. const ret = []
  30. if (obj.is_baremetal || obj.host_type === 'baremetal') {
  31. ret.push(solWebConsole(this.webconsoleManager, obj, this.openWebConsole, this.createDialog))
  32. ret.push({ ...jnlpConsole(this.onManager, obj, this.createDialog), permission: 'server_get_jnlp' })
  33. }
  34. let ips = (obj.server_ips || '').split(',').filter(item => !!item)
  35. if (obj.access_ip) {
  36. ips = [obj.access_ip, ...ips]
  37. }
  38. const openWebConsole = (params) => {
  39. this.webconsoleManager.performAction(params).then(({ data }) => {
  40. const connectParams = qs.parse(data.connect_params)
  41. // 验证账号密码
  42. if (connectParams.is_need_login === 'true') {
  43. this.createDialog('SshAuthDialog', {
  44. manager: this.webconsoleManager,
  45. params,
  46. errorMsg: connectParams.login_error_message,
  47. data: { name: obj.name, ip: params.action },
  48. success: (data) => {
  49. this.openWebConsole(obj, data, 'ws')
  50. },
  51. })
  52. return
  53. }
  54. // 无需验证账号密码
  55. this.openWebConsole(obj, data, 'ws')
  56. })
  57. }
  58. const actionGenerator = ip => {
  59. return (sshData) => {
  60. const success = () => {
  61. const params = {
  62. action: ip,
  63. data: { type: 'host', ...sshData },
  64. id: 'ssh',
  65. }
  66. openWebConsole(params)
  67. }
  68. if (this.enableMFA) {
  69. this.createDialog('SecretVertifyDialog', {
  70. success,
  71. })
  72. } else {
  73. success()
  74. }
  75. }
  76. }
  77. ips.forEach(ip => {
  78. const meta = () => ({ validate: true })
  79. ret.push({
  80. label: `SSH ${ip}`,
  81. action: actionGenerator(ip),
  82. meta,
  83. extraMeta: obj => {
  84. return getDisabledProvidersActionMeta({
  85. row: obj,
  86. disabledProviders: ['BingoCloud'],
  87. })
  88. },
  89. render: (obj, params, h) => {
  90. let styleObj = {
  91. padding: '0 10px',
  92. fontSize: '12px',
  93. }
  94. const isRunning = obj.status === 'running'
  95. if (!isRunning) {
  96. styleObj = {
  97. ...styleObj,
  98. cursor: 'not-allowed',
  99. color: 'rgba(0, 0, 0, 0.25)',
  100. }
  101. }
  102. const sshConnectHandle = () => {
  103. const success = () => {
  104. openWebConsole({
  105. action: ip,
  106. data: { type: 'host', id: obj.id, port: 22 },
  107. id: 'ssh',
  108. }, obj.id)
  109. }
  110. if (this.enableMFA) {
  111. this.createDialog('SecretVertifyDialog', {
  112. success,
  113. })
  114. } else {
  115. success()
  116. }
  117. }
  118. const sshSettingInfoHandle = () => {
  119. this.createDialog('SmartFormDialog', {
  120. title: i18n.t('compute.custom_ssh_connect', ['SSH']),
  121. data: [obj],
  122. callback: async (data) => {
  123. const pms = {
  124. action: ip,
  125. data: { type: 'host', id: obj.id, port: data.port, username: data.username, password: data.password },
  126. id: 'ssh',
  127. }
  128. openWebConsole(pms, obj.id)
  129. },
  130. decorators: SMART_SSH_FORM_DECORATORS,
  131. })
  132. }
  133. return <a-tooltip placement="left" title={!isRunning ? i18n.t('compute.text_1282') : ''}>
  134. <span style={styleObj} class='d-flex justify-content-between align-items-center'>
  135. <span onClick={isRunning ? sshConnectHandle : () => { }}>{`SSH ${ip}`}</span>
  136. {
  137. isRunning ? <span>
  138. <a-tooltip title={i18n.t('compute.custom_ssh_connect', ['SSH'])}>
  139. <a-icon class="ml-2" type="edit" onClick={isRunning ? sshSettingInfoHandle : () => { }} />
  140. </a-tooltip>
  141. </span> : null
  142. }
  143. </span>
  144. </a-tooltip>
  145. },
  146. })
  147. })
  148. return ret
  149. },
  150. },
  151. {
  152. label: i18n.t('compute.text_352'),
  153. actions: (obj) => {
  154. const ownerDomain = this.$store.getters.isAdminMode || obj.domain_id === this.$store.getters.userInfo.projectDomainId
  155. return [
  156. ...getEnabledSwitchActions(this, obj, ['hosts_perform_enable', 'hosts_perform_disable'], {
  157. actions: [
  158. async (obj) => {
  159. await this.onManager('batchPerformAction', {
  160. id: [obj.id],
  161. managerArgs: {
  162. action: 'enable',
  163. },
  164. })
  165. this.$store.dispatch('auth/getCapabilities')
  166. },
  167. async (obj) => {
  168. await this.onManager('batchPerformAction', {
  169. id: [obj.id],
  170. managerArgs: {
  171. action: 'disable',
  172. },
  173. })
  174. this.$store.dispatch('auth/getCapabilities')
  175. },
  176. ],
  177. metas: [
  178. () => ({
  179. validate: !obj.enabled && ownerDomain,
  180. }),
  181. () => ({
  182. validate: obj.enabled && ownerDomain,
  183. }),
  184. ],
  185. extraMetas: [
  186. obj => {
  187. return getDisabledProvidersActionMeta({
  188. row: obj,
  189. disabledProviders: ['BingoCloud'],
  190. })
  191. },
  192. obj => {
  193. return getDisabledProvidersActionMeta({
  194. row: obj,
  195. disabledProviders: ['BingoCloud'],
  196. })
  197. },
  198. ],
  199. }),
  200. {
  201. label: i18n.t('compute.text_540'),
  202. permission: 'hosts_perform_set_schedtag',
  203. action: () => {
  204. this.createDialog('HostsAdjustLabelDialog', {
  205. data: [obj],
  206. columns: this.columns,
  207. name: this.$t('dictionary.host'),
  208. onManager: this.onManager,
  209. })
  210. },
  211. meta: obj => ({
  212. validate: ownerDomain,
  213. }),
  214. extraMeta: obj => {
  215. return getDisabledProvidersActionMeta({
  216. row: obj,
  217. disabledProviders: ['BingoCloud'],
  218. })
  219. },
  220. },
  221. {
  222. label: i18n.t('compute.text_513'),
  223. permission: 'hosts_update,hosts_perform_set_commit_bound',
  224. action: () => {
  225. this.createDialog('HostAdjustOversoldRatioDialog', {
  226. data: [obj],
  227. columns: this.columns,
  228. onManager: this.onManager,
  229. name: this.$t('dictionary.host'),
  230. refresh: this.refresh,
  231. })
  232. },
  233. meta: obj => ({
  234. validate: obj.brand.toLowerCase() !== 'zstack' && ownerDomain,
  235. }),
  236. extraMeta: obj => {
  237. return getDisabledProvidersActionMeta({
  238. row: obj,
  239. disabledProviders: ['BingoCloud'],
  240. })
  241. },
  242. },
  243. getDomainChangeOwnerAction(this, {
  244. name: this.$t('dictionary.host'),
  245. resource: 'hosts',
  246. }, {
  247. permission: 'hosts_perform_change_owner',
  248. meta: (obj) => {
  249. if (!this.$store.getters.l3PermissionEnable) {
  250. return {
  251. validate: false,
  252. tooltip: i18n.t('common_281'),
  253. }
  254. }
  255. return {
  256. validate: ownerDomain,
  257. }
  258. },
  259. extraMeta: obj => {
  260. return getDisabledProvidersActionMeta({
  261. row: obj,
  262. disabledProviders: ['BingoCloud'],
  263. })
  264. },
  265. }),
  266. getSetPublicAction(this, {
  267. name: this.$t('dictionary.host'),
  268. scope: 'domain',
  269. resource: 'hosts',
  270. }, {
  271. permission: 'hosts_perform_public',
  272. meta: function (obj) {
  273. return {
  274. validate: ownerDomain,
  275. }
  276. },
  277. extraMeta: obj => {
  278. return getDisabledProvidersActionMeta({
  279. row: obj,
  280. disabledProviders: ['BingoCloud'],
  281. })
  282. },
  283. }),
  284. {
  285. label: i18n.t('compute.text_547'),
  286. permission: 'hosts_perform_auto_migrate_on_host_down',
  287. action: () => {
  288. this.createDialog('DowntimeMigrateDialog', {
  289. data: [obj],
  290. columns: this.columns,
  291. onManager: this.onManager,
  292. name: i18n.t('compute.text_547'),
  293. refresh: this.refresh,
  294. })
  295. },
  296. meta: () => {
  297. if (obj.provider.toLowerCase() === 'onecloud' && obj.allow_health_check && ownerDomain) {
  298. return {
  299. validate: true,
  300. }
  301. }
  302. return {
  303. validate: false,
  304. tooltip: obj.provider.toLowerCase() !== 'onecloud' ? i18n.t('compute.text_570') : '',
  305. }
  306. },
  307. extraMeta: obj => {
  308. return getDisabledProvidersActionMeta({
  309. row: obj,
  310. disabledProviders: ['BingoCloud'],
  311. })
  312. },
  313. },
  314. {
  315. label: i18n.t('compute.text_508'),
  316. permission: 'hosts_perform_undo_convert',
  317. action: () => {
  318. this.createDialog('HostUnconvertDialog', {
  319. data: [obj],
  320. columns: this.columns,
  321. onManager: this.onManager,
  322. name: this.$t('dictionary.host'),
  323. refresh: this.refresh,
  324. })
  325. },
  326. meta: () => {
  327. if (obj.host_type !== 'hypervisor') {
  328. return {
  329. validate: false,
  330. tooltip: i18n.t('compute.text_510'),
  331. }
  332. } else if (obj.nonsystem_guests > 0) {
  333. return {
  334. validate: false,
  335. tooltip: i18n.t('compute.text_511'),
  336. }
  337. } else if (obj.enabled) {
  338. return {
  339. validate: false,
  340. tooltip: i18n.t('compute.text_512'),
  341. }
  342. } else if (!obj.is_baremetal) {
  343. return {
  344. validate: false,
  345. tooltip: '',
  346. }
  347. } else if (!ownerDomain) {
  348. return {
  349. validate: false,
  350. tooltip: '',
  351. }
  352. } else if (obj.cpu_architecture === HOST_CPU_ARCHS.arm.capabilityKey) {
  353. return {
  354. validate: false,
  355. tooltip: i18n.t('compute.text_1364'),
  356. }
  357. }
  358. return {
  359. validate: true,
  360. }
  361. },
  362. extraMeta: obj => {
  363. return getDisabledProvidersActionMeta({
  364. row: obj,
  365. disabledProviders: ['BingoCloud'],
  366. })
  367. },
  368. },
  369. {
  370. label: i18n.t('compute.text_550'),
  371. permission: 'hosts_perform_host_maintenance',
  372. action: () => {
  373. this.createDialog('HostMaintenanceInDialog', {
  374. data: [obj],
  375. columns: this.columns,
  376. onManager: this.onManager,
  377. name: this.$t('dictionary.host'),
  378. refresh: this.refresh,
  379. })
  380. },
  381. meta: () => {
  382. if (obj.host_type !== 'hypervisor') {
  383. return {
  384. validate: false,
  385. }
  386. }
  387. if (obj.host_type === 'hypervisor' && obj.host_status === 'offline') {
  388. return {
  389. validate: false,
  390. tooltip: this.$t('compute.text_1377'),
  391. }
  392. }
  393. return {
  394. validate: ['running', 'maintain_fail'].includes(obj.status) && ownerDomain,
  395. tooltip: obj.status !== 'running' ? i18n.t('compute.text_571') : '',
  396. }
  397. },
  398. extraMeta: obj => {
  399. return getDisabledProvidersActionMeta({
  400. row: obj,
  401. disabledProviders: ['BingoCloud'],
  402. })
  403. },
  404. },
  405. {
  406. label: i18n.t('compute.text_559'),
  407. permission: 'hosts_perform_host_maintenance',
  408. action: () => {
  409. this.createDialog('HostMaintenanceOutDialog', {
  410. data: [obj],
  411. columns: this.columns,
  412. onManager: this.onManager,
  413. name: this.$t('dictionary.host'),
  414. refresh: this.refresh,
  415. })
  416. },
  417. meta: () => {
  418. if (obj.host_type !== 'hypervisor') {
  419. return {
  420. validate: false,
  421. }
  422. }
  423. return {
  424. validate: ['maintaining', 'maintain_fail'].includes(obj.status) && ownerDomain,
  425. }
  426. },
  427. extraMeta: obj => {
  428. return getDisabledProvidersActionMeta({
  429. row: obj,
  430. disabledProviders: ['BingoCloud'],
  431. })
  432. },
  433. },
  434. {
  435. label: i18n.t('compute.set_numa'),
  436. permission: 'hosts_update',
  437. action: () => {
  438. this.createDialog('HostSetNumaDialog', {
  439. onManager: this.onManager,
  440. data: [obj],
  441. columns: this.columns,
  442. refresh: this.refresh,
  443. })
  444. },
  445. },
  446. {
  447. label: this.$t('compute.host.set_system_reserve_resource'),
  448. action: obj => {
  449. this.createDialog('SetHostCpuReserveResourceDialog', {
  450. onManager: this.onManager,
  451. data: [obj],
  452. columns: this.columns,
  453. refresh: this.refresh,
  454. })
  455. },
  456. meta: () => {
  457. const ret = {
  458. validate: false,
  459. tooltip: null,
  460. }
  461. if (!ownerDomain) {
  462. ret.tooltip = this.$t('compute.host.cpu.revert.share')
  463. return ret
  464. }
  465. if (obj.provider !== typeClouds.providerMap.OneCloud.key) {
  466. ret.tooltip = i18n.t('compute.text_515')
  467. return ret
  468. }
  469. if (obj.running_guests > 0) {
  470. ret.tooltip = i18n.t('compute.host.cpu.revert.running_guest_tooltip')
  471. return ret
  472. }
  473. return {
  474. validate: true,
  475. }
  476. },
  477. },
  478. {
  479. label: i18n.t('compute.setup_passthrough_reserve'),
  480. permission: 'hosts_perform_set_reserved_resource_for_isolated_device',
  481. action: obj => {
  482. this.createDialog('SetHostReserveResourceDialog', {
  483. onManager: this.onManager,
  484. data: [obj],
  485. columns: this.columns,
  486. refresh: this.refresh,
  487. })
  488. },
  489. meta: () => {
  490. const ret = {
  491. validate: false,
  492. tooltip: null,
  493. }
  494. if (obj.provider !== typeClouds.providerMap.OneCloud.key) {
  495. ret.tooltip = i18n.t('compute.text_515')
  496. return ret
  497. }
  498. if (!obj.reserved_resource_for_gpu) {
  499. ret.tooltip = i18n.t('compute.text_516')
  500. return ret
  501. }
  502. return {
  503. validate: ownerDomain,
  504. }
  505. },
  506. extraMeta: obj => {
  507. return getDisabledProvidersActionMeta({
  508. row: obj,
  509. disabledProviders: ['BingoCloud'],
  510. })
  511. },
  512. },
  513. {
  514. label: i18n.t('compute.perform_delete'),
  515. permission: 'hosts_delete',
  516. action: () => {
  517. this.createDialog('DeleteResDialog', {
  518. vm: this,
  519. data: [obj],
  520. columns: this.columns,
  521. title: i18n.t('compute.perform_delete'),
  522. name: this.$t('dictionary.host'),
  523. onManager: this.onManager,
  524. success: () => {
  525. this.$store.dispatch('auth/getCapabilities')
  526. },
  527. })
  528. },
  529. meta: () => {
  530. const deleteResult = this.$getDeleteResult(obj)
  531. if (!deleteResult.validate) {
  532. return deleteResult
  533. }
  534. return {
  535. validate: ownerDomain,
  536. }
  537. },
  538. extraMeta: obj => {
  539. return getDisabledProvidersActionMeta({
  540. row: obj,
  541. disabledProviders: ['BingoCloud'],
  542. })
  543. },
  544. },
  545. ]
  546. },
  547. },
  548. ])
  549. },
  550. enableWaterMark () {
  551. const { globalConfig = {} } = this.common
  552. const { enable_watermark = true } = globalConfig
  553. return enable_watermark
  554. },
  555. },
  556. methods: {
  557. openWebConsole (obj, data, protocol) {
  558. this.$openWebConsole(data)
  559. },
  560. },
  561. }