actions.js 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142
  1. import qs from 'qs'
  2. import { SERVER_TYPE, SMART_SSH_FORM_DECORATORS } from '@Compute/constants'
  3. import VncInfoFetcher from '@Compute/sections/VncInfoFetcher'
  4. import { disableDeleteAction } from '@/utils/common/tableActions'
  5. import { typeClouds, findPlatform } from '@/utils/common/hypervisor'
  6. import i18n from '@/locales'
  7. import { HOST_CPU_ARCHS } from '@/constants/compute'
  8. import { PROVIDER_MAP, BRAND_MAP } from '@/constants'
  9. import { hasSetupKey, isLicense2 } from '@/utils/auth'
  10. import { KVM_SHARE_STORAGES } from '@/constants/storage'
  11. import { POLICY_RES_NAME_KEY_MAP } from '@/constants/policy'
  12. import { commonUnabled, cloudEnabled, cloudUnabledTip, commonEnabled, commonTip, validateRescueMode } from '../utils'
  13. const getSingleActions = function (ctx) {
  14. let hasBastionService = false
  15. const that = ctx || this
  16. const { services = [] } = that.$store?.getters?.userInfo || {}
  17. const bastionService = services.find(val => val.type === 'bastionhost')
  18. if (bastionService && bastionService.status === true) {
  19. hasBastionService = true
  20. }
  21. return [
  22. {
  23. label: i18n.t('compute.text_341'),
  24. permission: 'server_get_vnc',
  25. actions: obj => {
  26. let ret = []
  27. const vncRemote = {
  28. label: i18n.t('compute.text_1274'),
  29. action: () => {
  30. const success = () => {
  31. const isValidURL = str => {
  32. const regex = /(\w+):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!-/]))?/
  33. if (!regex.test(str)) {
  34. return false
  35. } else {
  36. return true
  37. }
  38. }
  39. const params = {}
  40. if (obj.hypervisor === typeClouds.hypervisorMap.openstack.key) {
  41. params.origin = true
  42. }
  43. this.webconsoleManager.performAction({
  44. id: 'server',
  45. action: obj.id,
  46. data: params,
  47. }).then(({ data }) => {
  48. if (isValidURL(data.connect_params)) {
  49. this.open(obj, data.connect_params)
  50. } else {
  51. this.openWebConsole(obj, data)
  52. }
  53. })
  54. }
  55. if (this.enableMFA) {
  56. this.createDialog('SecretVertifyDialog', {
  57. success,
  58. })
  59. } else {
  60. success()
  61. }
  62. },
  63. meta: () => {
  64. const ret = {
  65. validate: true,
  66. tooltip: '',
  67. }
  68. if (obj.provider === 'OneCloud') {
  69. ret.validate = obj.power_states === 'on'
  70. ret.tooltip = obj.power_states === 'on' ? '' : i18n.t('compute.power_states_check_tip', [i18n.t('common_239'), `【${i18n.t('compute.text_574')}】`])
  71. } else {
  72. ret.validate = obj.power_states === 'unknown' ? cloudEnabled('vnc', obj) : obj.power_states === 'on'
  73. ret.tooltip = obj.power_states === 'unknown' ? cloudUnabledTip('vnc', obj) : (obj.power_states === 'on' ? '' : i18n.t('compute.power_states_check_tip', [i18n.t('common_239'), `【${i18n.t('compute.text_574')}】`]))
  74. if (cloudEnabled('vnc', obj) === false) {
  75. ret.validate = false
  76. ret.tooltip = cloudUnabledTip('vnc', obj)
  77. }
  78. }
  79. return ret
  80. },
  81. }
  82. if (obj.provider === 'OneCloud' && obj.status === 'running') {
  83. vncRemote.render = (obj, params, h) => {
  84. return <VncInfoFetcher onManager={this.onManager} row={obj} buttonText={i18n.t('compute.text_1274')} buttonProps={params} />
  85. }
  86. }
  87. ret.push(vncRemote)
  88. const mapIpActions = (ipInfoList) => {
  89. const options = []
  90. ipInfoList.forEach(ipInfo => {
  91. const actionType = ipInfo.actionType
  92. const ipAddr = ipInfo.ipAddr
  93. const meta = () => {
  94. const ret = {
  95. validate: false,
  96. tooltip: null,
  97. }
  98. const rescueModeValid = validateRescueMode(obj)
  99. if (!rescueModeValid.validate) return rescueModeValid
  100. // if (obj.os_type === 'Windows') {
  101. // ret.tooltip = i18n.t('compute.text_344')
  102. // return ret
  103. // }
  104. ret.validate = cloudEnabled(actionType, obj)
  105. ret.tooltip = cloudUnabledTip(actionType, obj)
  106. return ret
  107. }
  108. const openWebconsole = async (prms, id) => {
  109. const params = {
  110. id: 'ssh',
  111. action: id,
  112. data: {
  113. id,
  114. ip: ipAddr,
  115. ...prms,
  116. type: 'server',
  117. },
  118. }
  119. this.webconsoleManager.performAction(params).then(({ data }) => {
  120. const connectParams = qs.parse(data.connect_params)
  121. // 验证账号密码
  122. if (connectParams.is_need_login === 'true') {
  123. this.createDialog('SshAuthDialog', {
  124. manager: this.webconsoleManager,
  125. params,
  126. errorMsg: connectParams.login_error_message,
  127. data: { name: obj.name, ip: ipAddr, id: obj.id, resource: 'servers' },
  128. success: (data) => {
  129. this.openWebConsole(obj, data, 'ws')
  130. },
  131. })
  132. return
  133. }
  134. // 无需验证账号密码
  135. this.openWebConsole(obj, data, 'ws')
  136. })
  137. }
  138. const isWindows = obj.os_type === 'Windows' || (obj.metadata?.os_distribution === 'Windows')
  139. if (!isWindows) {
  140. options.push({
  141. label: `SSH ${ipAddr}`,
  142. permission: 'server_perform_list_forward,server_perform_open_forward',
  143. meta,
  144. render: (obj, params, h) => {
  145. let styleObj = {
  146. padding: '0 10px',
  147. fontSize: '12px',
  148. }
  149. const isRunning = obj.power_states === 'on'
  150. if (!isRunning || obj.rescue_mode === true) {
  151. styleObj = {
  152. ...styleObj,
  153. cursor: 'not-allowed',
  154. color: 'rgba(0, 0, 0, 0.25)',
  155. }
  156. }
  157. const sshConnectHandle = () => {
  158. const success = () => {
  159. openWebconsole({ port: 22 }, obj.id)
  160. }
  161. if (this.enableMFA) {
  162. this.createDialog('SecretVertifyDialog', {
  163. success,
  164. })
  165. } else {
  166. success()
  167. }
  168. }
  169. const sshSettingInfoHandle = () => {
  170. this.createDialog('SmartFormDialog', {
  171. title: i18n.t('compute.custom_ssh_connect', ['SSH']),
  172. data: [obj],
  173. callback: async (data) => {
  174. openWebconsole({ port: data.port, username: data.username, password: data.password }, obj.id)
  175. },
  176. decorators: SMART_SSH_FORM_DECORATORS,
  177. })
  178. }
  179. return <a-tooltip placement="left" title={obj.rescue_mode ? i18n.t('compute.start_rescue.validate_tooltip') : !isRunning ? i18n.t('compute.text_1309', [i18n.t('compute.text_574')]) : ''}>
  180. <span style={styleObj} class='d-flex justify-content-between align-items-center' title={ipAddr}>
  181. <span onClick={isRunning ? sshConnectHandle : () => { }}>{`SSH ${ipAddr.length > 17 ? `${ipAddr.slice(0, 17)}...` : ipAddr}`}</span>
  182. {
  183. isRunning ? <span>
  184. <a-tooltip title={i18n.t('compute.custom_ssh_connect', ['SSH'])}>
  185. <a-icon class="ml-2" type="edit" onClick={isRunning ? sshSettingInfoHandle : () => { }} />
  186. </a-tooltip>
  187. </span> : null
  188. }
  189. </span>
  190. </a-tooltip>
  191. },
  192. })
  193. } else {
  194. const rdpSettingInfoHandle = () => {
  195. this.createDialog('SmartFormDialog', {
  196. title: i18n.t('compute.custom_ssh_connect', ['RDP']),
  197. data: [obj],
  198. callback: async (data) => {
  199. handleRdpConnect(obj, data, 'rdp')
  200. },
  201. decorators: SMART_SSH_FORM_DECORATORS,
  202. })
  203. }
  204. const handleRdpConnect = (obj, prms = {}) => {
  205. const width = window.innerWidth
  206. const height = window.innerHeight - 37
  207. const params = {
  208. id: 'server-rdp',
  209. action: obj.id,
  210. data: {
  211. host: ipAddr,
  212. width,
  213. height,
  214. ...prms,
  215. },
  216. }
  217. this.webconsoleManager.performAction(params).then(({ data }) => {
  218. const connectParams = qs.parse(data.connect_params)
  219. // 验证账号密码
  220. if (connectParams.is_need_login === 'true') {
  221. this.createDialog('RdpAuthDialog', {
  222. manager: this.webconsoleManager,
  223. params,
  224. errorMsg: connectParams.login_error_message,
  225. data: { name: obj.name, ip: ipAddr },
  226. success: (data) => {
  227. this.openWebConsole(obj, data, 'rdp')
  228. },
  229. })
  230. return
  231. }
  232. // 无需验证账号密码
  233. this.openWebConsole(obj, data, 'rdp')
  234. }).catch((ex) => {
  235. const { details } = ex.response.data
  236. this.createDialog('RdpAuthDialog', {
  237. manager: this.webconsoleManager,
  238. params,
  239. errorMsg: details,
  240. data: { name: obj.name, ip: ipAddr },
  241. success: (data) => {
  242. this.openWebConsole(obj, data, 'rdp')
  243. },
  244. })
  245. })
  246. }
  247. const rdpConnectHandle = () => {
  248. const success = () => {
  249. handleRdpConnect(obj)
  250. }
  251. if (this.enableMFA) {
  252. this.createDialog('SecretVertifyDialog', {
  253. success,
  254. })
  255. } else {
  256. success()
  257. }
  258. }
  259. options.push({
  260. label: `RDP ${ipAddr}`,
  261. permission: 'server_perform_list_forward,server_perform_open_forward',
  262. meta,
  263. render: (obj, params, h) => {
  264. let styleObj = {
  265. padding: '0 10px',
  266. fontSize: '12px',
  267. }
  268. const isRunning = obj.power_states === 'on'
  269. if (!isRunning || obj.rescue_mode === true) {
  270. styleObj = {
  271. ...styleObj,
  272. cursor: 'not-allowed',
  273. color: 'rgba(0, 0, 0, 0.25)',
  274. }
  275. }
  276. return <a-tooltip placement="left" title={obj.rescue_mode ? i18n.t('compute.start_rescue.validate_tooltip') : !isRunning ? i18n.t('compute.text_1309', [i18n.t('compute.text_574')]) : ''}>
  277. <span style={styleObj} class='d-flex justify-content-between align-items-center'>
  278. <span onClick={isRunning ? rdpConnectHandle : () => { }}>{`RDP ${ipAddr}`}</span>
  279. {
  280. isRunning ? <span>
  281. <a-tooltip title={!isRunning ? '' : i18n.t('compute.custom_ssh_connect', ['RDP'])}>
  282. <a-icon class="ml-2" type="edit" onClick={isRunning ? rdpSettingInfoHandle : () => { }} />
  283. </a-tooltip>
  284. </span> : null
  285. }
  286. </span>
  287. </a-tooltip>
  288. },
  289. })
  290. }
  291. })
  292. return options
  293. }
  294. const ipInfoList = []
  295. if (obj.eip) {
  296. obj.eip.split(',').filter(item => !!item).map(ip => {
  297. ipInfoList.push({
  298. actionType: 'EIP SSH',
  299. ipType: 'eip',
  300. ipAddr: ip,
  301. })
  302. })
  303. }
  304. if (obj.nics) {
  305. obj.nics.map(nic => {
  306. if ((((obj.provider === 'OneCloud' || obj.vpc_id === 'default') && nic.is_default) || obj.provider === 'InCloudSphere') && nic.ip_addr) {
  307. ipInfoList.push({
  308. actionType: 'IP SSH',
  309. ipType: 'nicIP',
  310. ipAddr: nic.ip_addr,
  311. vpcId: nic.vpc_id,
  312. provider: obj.provider,
  313. })
  314. }
  315. if ((((obj.provider === 'OneCloud' || obj.vpc_id === 'default') && nic.is_default) || obj.provider === 'InCloudSphere') && nic.ip6_addr) {
  316. ipInfoList.push({
  317. actionType: 'IP SSH',
  318. ipType: 'nicIP',
  319. ipAddr: nic.ip6_addr,
  320. vpcId: nic.vpc_id,
  321. provider: obj.provider,
  322. })
  323. }
  324. })
  325. }
  326. const sshActions = mapIpActions(ipInfoList)
  327. ret = ret.concat(sshActions)
  328. return ret
  329. },
  330. meta: (obj) => {
  331. let ret = {
  332. validate: true,
  333. tooltip: null,
  334. }
  335. ret = this.$isValidateResourceLock(obj)
  336. return ret
  337. },
  338. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_web_console'),
  339. },
  340. {
  341. label: i18n.t('compute.text_352'),
  342. actions: (obj) => {
  343. return [
  344. // * 实例状态
  345. {
  346. label: i18n.t('compute.text_353'),
  347. submenus: [
  348. // 同步状态
  349. {
  350. label: i18n.t('compute.perform_sync_status'),
  351. permission: 'server_perform_syncstatus',
  352. action: () => {
  353. this.onManager('performAction', {
  354. steadyStatus: ['running', 'ready'],
  355. id: obj.id,
  356. managerArgs: {
  357. action: 'syncstatus',
  358. },
  359. })
  360. },
  361. meta: () => {
  362. const ret = {
  363. validate: false,
  364. tooltip: null,
  365. }
  366. if (commonUnabled(obj)) return ret
  367. ret.validate = true
  368. return ret
  369. },
  370. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_syncstatus'),
  371. },
  372. // 开机
  373. {
  374. label: i18n.t('compute.text_272'),
  375. permission: 'server_perform_start',
  376. action: (obj) => {
  377. this.createDialog('VmStartDialog', {
  378. data: [obj],
  379. columns: this.columns,
  380. onManager: this.onManager,
  381. })
  382. },
  383. meta: () => {
  384. return {
  385. validate: cloudEnabled('start', obj),
  386. }
  387. },
  388. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_start'),
  389. },
  390. // 关机
  391. {
  392. label: i18n.t('compute.text_273'),
  393. permission: 'server_perform_stop',
  394. action: () => {
  395. this.createDialog('VmShutDownDialog', {
  396. data: [obj],
  397. columns: this.columns,
  398. onManager: this.onManager,
  399. })
  400. },
  401. meta: () => {
  402. return { validate: cloudEnabled('stop', obj) }
  403. },
  404. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_stop'),
  405. },
  406. // 重启
  407. {
  408. label: i18n.t('compute.text_274'),
  409. permission: 'server_perform_restart',
  410. action: () => {
  411. this.createDialog('VmRestartDialog', {
  412. data: [obj],
  413. columns: this.columns,
  414. onManager: this.onManager,
  415. })
  416. },
  417. meta: () => {
  418. return {
  419. validate: cloudEnabled('restart', obj),
  420. }
  421. },
  422. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_restart'),
  423. },
  424. // 重置
  425. {
  426. label: i18n.t('compute.text_354'),
  427. permission: 'server_perform_reset',
  428. action: () => {
  429. this.createDialog('VmResetDialog', {
  430. data: [obj],
  431. columns: this.columns,
  432. onManager: this.onManager,
  433. })
  434. },
  435. meta: () => {
  436. const provider = obj.provider
  437. const ret = {
  438. validate: false,
  439. tooltip: null,
  440. }
  441. if (obj.hypervisor === typeClouds.hypervisorMap.bingocloud.key) {
  442. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.bingocloud.label])
  443. return ret
  444. }
  445. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  446. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  447. return ret
  448. }
  449. return {
  450. validate: (obj.status === 'running' || obj.status === 'stop_fail') && !commonUnabled(obj),
  451. }
  452. },
  453. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_reset'),
  454. },
  455. // 挂起
  456. {
  457. label: i18n.t('compute.text_1128'),
  458. permission: 'server_perform_suspend',
  459. action: () => {
  460. this.createDialog('VmSuspendDialog', {
  461. data: [obj],
  462. columns: this.columns,
  463. onManager: this.onManager,
  464. })
  465. },
  466. meta: () => {
  467. const provider = obj.provider
  468. const ret = {
  469. validate: false,
  470. tooltip: null,
  471. }
  472. if (![BRAND_MAP.VMware.key, BRAND_MAP.OneCloud.key].includes(obj.brand)) {
  473. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  474. return ret
  475. }
  476. if (obj.status !== 'running') {
  477. ret.validate = false
  478. ret.tooltip = i18n.t('compute.text_1130')
  479. return ret
  480. }
  481. ret.validate = true
  482. return ret
  483. },
  484. hidden: () => !(hasSetupKey(['vmware'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_suspend'),
  485. },
  486. // 恢复
  487. {
  488. label: i18n.t('compute.text_478'),
  489. permission: 'server_perform_resume',
  490. action: () => {
  491. this.createDialog('VmResumeDialog', {
  492. data: [obj],
  493. columns: this.columns,
  494. onManager: this.onManager,
  495. })
  496. },
  497. meta: () => {
  498. const provider = obj.provider
  499. const ret = {
  500. validate: false,
  501. tooltip: null,
  502. }
  503. if (obj.brand !== BRAND_MAP.VMware.key && obj.brand !== BRAND_MAP.OneCloud.key) {
  504. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  505. return ret
  506. }
  507. if (obj.status !== 'suspend') {
  508. ret.validate = false
  509. ret.tooltip = i18n.t('compute.text_1131')
  510. return ret
  511. }
  512. ret.validate = true
  513. return ret
  514. },
  515. hidden: () => !(hasSetupKey(['vmware'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_resume'),
  516. },
  517. // 进入紧急模式
  518. {
  519. label: i18n.t('compute.start_rescue'),
  520. permission: 'server_perform_start_rescue',
  521. action: () => {
  522. this.createDialog('VmStartRescueDialog', {
  523. data: [obj],
  524. columns: this.columns,
  525. onManager: this.onManager,
  526. refresh: this.refresh,
  527. })
  528. },
  529. meta: () => {
  530. const ret = { validate: true }
  531. const provider = obj.provider
  532. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  533. ret.validate = false
  534. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  535. return ret
  536. }
  537. if (obj.rescue_mode === true) {
  538. ret.validate = false
  539. ret.tooltip = i18n.t('compute.start_rescue.validate_tooltip')
  540. return ret
  541. }
  542. return ret
  543. },
  544. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_start_rescue'),
  545. },
  546. // 退出紧急模式
  547. {
  548. label: i18n.t('compute.stop_rescue'),
  549. permission: 'server_perform_stop_rescue',
  550. action: () => {
  551. this.createDialog('VmStopRescueDialog', {
  552. data: [obj],
  553. columns: this.columns,
  554. onManager: this.onManager,
  555. refresh: this.refresh,
  556. })
  557. },
  558. meta: () => {
  559. const ret = { validate: true }
  560. const provider = obj.provider
  561. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  562. ret.validate = false
  563. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  564. return ret
  565. }
  566. if (obj.rescue_mode !== true) {
  567. ret.validate = false
  568. ret.tooltip = i18n.t('compute.stop_rescue.validate_tooltip')
  569. return ret
  570. }
  571. return ret
  572. },
  573. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_stop_rescue'),
  574. },
  575. // 推送配置
  576. {
  577. label: i18n.t('compute.sync_config'),
  578. permission: 'server_perform_sync_config',
  579. action: () => {
  580. this.createDialog('VmSyncConfigDialog', {
  581. data: [obj],
  582. columns: this.columns,
  583. onManager: this.onManager,
  584. })
  585. },
  586. meta: () => {
  587. const provider = obj.provider
  588. const ret = {
  589. validate: false,
  590. tooltip: null,
  591. }
  592. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  593. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  594. return ret
  595. }
  596. if (obj.status !== 'running' && obj.status !== 'ready') {
  597. ret.validate = false
  598. ret.tooltip = i18n.t('compute.text_1126')
  599. return ret
  600. }
  601. ret.validate = true
  602. return ret
  603. },
  604. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_sync_config'),
  605. },
  606. // VNC 截图
  607. {
  608. label: i18n.t('compute.vnc_panic_screenshot'),
  609. permission: 'server_perform_screen_dump',
  610. action: async () => {
  611. try {
  612. const res = await new this.$Manager('servers', 'v2').performAction({
  613. id: obj.id,
  614. action: 'screen-dump',
  615. })
  616. if (res.data?.screen_dump) {
  617. this.createDialog('VmVncScreenshotDialog', {
  618. data: obj,
  619. screenshotUrl: res.data.screen_dump,
  620. })
  621. } else {
  622. this.$message.error(this.$t('compute.get_screenshot_error'))
  623. }
  624. } catch (error) {
  625. this.$message.error(this.$t('compute.get_screenshot_error'))
  626. throw error
  627. }
  628. },
  629. meta: (row) => {
  630. const isOneCloud = row.brand === 'OneCloud'
  631. const provider = obj.provider
  632. if (!isOneCloud) {
  633. return {
  634. validate: false,
  635. tooltip: i18n.t('compute.text_473', [PROVIDER_MAP[provider].label]),
  636. }
  637. }
  638. return {
  639. validate: obj.power_states === 'on',
  640. tooltip: obj.power_states === 'on' ? '' : i18n.t('compute.power_states_check_tip', [i18n.t('common_239'), `【${i18n.t('compute.text_574')}】`]),
  641. }
  642. },
  643. hidden: (row) => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_screen_dump'),
  644. },
  645. // 手动触发无人值守安装完成
  646. {
  647. label: i18n.t('compute.kickstart_complete'),
  648. permission: 'server_perform_kickstart_complete',
  649. action: () => {
  650. this.createDialog('VmKickstartComplateDialog', {
  651. data: [obj],
  652. columns: this.columns,
  653. onManager: this.onManager,
  654. })
  655. },
  656. meta: () => {
  657. const ret = {
  658. validate: obj.status === 'kickstart_installing',
  659. tooltip: obj.status !== 'kickstart_installing' ? '' : i18n.t('compute.kickstart_complete_tip'),
  660. }
  661. return ret
  662. },
  663. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_kickstart_complete'),
  664. },
  665. ],
  666. },
  667. // * 属性设置
  668. {
  669. label: i18n.t('compute.text_356'),
  670. submenus: [
  671. // 修改属性
  672. {
  673. label: i18n.t('compute.text_247'),
  674. permission: 'server_update',
  675. action: () => {
  676. this.createDialog('VmUpdateDialog', {
  677. data: [obj],
  678. columns: this.columns,
  679. onManager: this.onManager,
  680. })
  681. },
  682. meta: (row) => {
  683. const isOneCloud = row.brand === 'OneCloud'
  684. const provider = obj.provider
  685. const rescueModeValid = validateRescueMode(obj)
  686. if (!rescueModeValid.validate) return rescueModeValid
  687. return {
  688. validate: isOneCloud,
  689. tooltip: !isOneCloud && i18n.t('compute.text_473', [PROVIDER_MAP[provider].label]),
  690. }
  691. },
  692. hidden: (row) => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_update'),
  693. },
  694. // 创建相同配置
  695. {
  696. label: i18n.t('compute.text_359'),
  697. permission: 'server_create',
  698. action: () => {
  699. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.create_same_configuration_callback_address', () => {
  700. this.createDialog('VmCloneDialog', {
  701. data: [obj],
  702. columns: this.columns,
  703. onManager: this.onManager,
  704. })
  705. })
  706. },
  707. meta: () => {
  708. const ret = {
  709. validate: false,
  710. tooltip: null,
  711. }
  712. const rescueModeValid = validateRescueMode(obj)
  713. if (!rescueModeValid.validate) return rescueModeValid
  714. if (obj.is_prepaid_recycle) {
  715. ret.tooltip = i18n.t('compute.text_285')
  716. return ret
  717. }
  718. if (obj.brand !== BRAND_MAP.OneCloud.key &&
  719. obj.hypervisor !== typeClouds.hypervisorMap.esxi.key &&
  720. obj.hypervisor !== typeClouds.hypervisorMap.sangfor.key &&
  721. findPlatform(obj.hypervisor) !== SERVER_TYPE.public) {
  722. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap[obj.hypervisor]?.label || ''])
  723. return ret
  724. }
  725. ret.validate = true
  726. return ret
  727. },
  728. hidden: () => !(hasSetupKey(['onecloud', 'public'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_create_same_config'),
  729. },
  730. // 更改项目
  731. {
  732. label: i18n.t('compute.perform_change_owner', [i18n.t('dictionary.project')]),
  733. permission: 'server_perform_change_owner',
  734. action: () => {
  735. this.createDialog('ChangeOwenrDialog', {
  736. data: [obj],
  737. columns: this.columns,
  738. onManager: this.onManager,
  739. name: i18n.t('dictionary.server'),
  740. resource: 'servers',
  741. })
  742. },
  743. meta: () => {
  744. const ret = {
  745. validate: false,
  746. tooltip: null,
  747. }
  748. const rescueModeValid = validateRescueMode(obj)
  749. if (!rescueModeValid.validate) return rescueModeValid
  750. if (!this.isAdminMode && !this.isDomainMode) {
  751. ret.tooltip = i18n.t('compute.text_613')
  752. return ret
  753. }
  754. if (commonUnabled(obj)) return ret
  755. ret.validate = true
  756. return ret
  757. },
  758. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_change_owner'),
  759. },
  760. // 到期释放
  761. {
  762. label: i18n.t('compute.text_1132'),
  763. permission: 'server_perform_cancel_expire',
  764. action: () => {
  765. this.createDialog('SetDurationDialog', {
  766. data: [obj],
  767. columns: this.columns,
  768. onManager: this.onManager,
  769. alert: i18n.t('compute.text_1391'),
  770. refresh: this.refresh,
  771. })
  772. },
  773. meta: () => {
  774. const ret = {
  775. validate: false,
  776. tooltip: null,
  777. }
  778. const rescueModeValid = validateRescueMode(obj)
  779. if (!rescueModeValid.validate) return rescueModeValid
  780. if (obj.billing_type === 'prepaid') {
  781. ret.tooltip = i18n.t('compute.text_285')
  782. return ret
  783. }
  784. if (obj.hypervisor === typeClouds.hypervisorMap.bingocloud.key) {
  785. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.bingocloud.label])
  786. return ret
  787. }
  788. if (obj.hypervisor === typeClouds.hypervisorMap.sangfor.key) {
  789. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.sangfor.label])
  790. return ret
  791. }
  792. ret.validate = true
  793. return ret
  794. },
  795. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_cancel_expire'),
  796. },
  797. // 加入反亲和组
  798. {
  799. label: i18n.t('compute.text_1181', [i18n.t('dictionary.instancegroup')]),
  800. permission: 'server_perform_bind_groups,server_perform_unbind_groups',
  801. action: () => {
  802. this.createDialog('VmBindInstanceGroupDialog', {
  803. data: [obj],
  804. columns: this.columns,
  805. onManager: this.onManager,
  806. refresh: this.refresh,
  807. name: i18n.t('dictionary.server'),
  808. })
  809. },
  810. meta: () => {
  811. const provider = obj.provider
  812. const ret = {
  813. validate: false,
  814. tooltip: null,
  815. }
  816. const rescueModeValid = validateRescueMode(obj)
  817. if (!rescueModeValid.validate) return rescueModeValid
  818. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  819. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  820. return ret
  821. }
  822. if (!['running', 'ready'].includes(obj.status)) {
  823. ret.tooltip = i18n.t('compute.text_1126')
  824. return ret
  825. }
  826. if (obj.backup_host_id) {
  827. ret.tooltip = i18n.t('compute.text_1283')
  828. return ret
  829. }
  830. ret.validate = true
  831. return ret
  832. },
  833. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_add_instancegroup'),
  834. },
  835. // 主机克隆
  836. {
  837. label: i18n.t('compute.text_1208'),
  838. permission: 'server_perform_snapshot_and_clone',
  839. action: () => {
  840. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.host_clone_callback_address', () => {
  841. this.createDialog('VmCloneDeepDialog', {
  842. data: [obj],
  843. columns: this.columns,
  844. onManager: this.onManager,
  845. refresh: this.refresh,
  846. })
  847. })
  848. },
  849. meta: () => {
  850. const provider = obj.provider
  851. const ret = {
  852. validate: false,
  853. tooltip: null,
  854. }
  855. const rescueModeValid = validateRescueMode(obj)
  856. if (!rescueModeValid.validate) return rescueModeValid
  857. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  858. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  859. return ret
  860. }
  861. if (!['running', 'ready'].includes(obj.status)) {
  862. ret.tooltip = i18n.t('compute.text_1126')
  863. return ret
  864. }
  865. if (obj.backup_host_id) {
  866. ret.tooltip = i18n.t('compute.text_1283')
  867. return ret
  868. }
  869. ret.validate = true
  870. return ret
  871. },
  872. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_clone'),
  873. },
  874. // 续费
  875. {
  876. label: i18n.t('compute.text_1117'),
  877. permission: 'server_perform_renew',
  878. action: () => {
  879. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.renew_callback_address', () => {
  880. this.createDialog('VmResourceFeeDialog', {
  881. data: [obj],
  882. columns: this.columns,
  883. onManager: this.onManager,
  884. })
  885. })
  886. },
  887. meta: () => {
  888. const ret = {
  889. validate: false,
  890. tooltip: null,
  891. }
  892. const rescueModeValid = validateRescueMode(obj)
  893. if (!rescueModeValid.validate) return rescueModeValid
  894. if (findPlatform(obj.hypervisor) !== SERVER_TYPE.public) {
  895. ret.tooltip = i18n.t('compute.text_1118')
  896. return ret
  897. }
  898. if (obj.billing_type !== 'prepaid') {
  899. ret.tooltip = i18n.t('compute.text_1119')
  900. return ret
  901. }
  902. ret.validate = true
  903. return ret
  904. },
  905. hidden: () => !(hasSetupKey(['aliyun', 'qcloud', 'huawei', 'ucloud', 'ecloud', 'jdcloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_Renew'),
  906. },
  907. // 自动续费设置
  908. {
  909. label: i18n.t('compute.text_1120'),
  910. permission: 'server_perform_aet_auto_renew',
  911. action: () => {
  912. this.createDialog('VmResourceRenewFeeDialog', {
  913. data: [obj],
  914. columns: this.columns,
  915. onManager: this.onManager,
  916. refresh: this.refresh,
  917. })
  918. },
  919. meta: () => {
  920. const ret = {
  921. validate: false,
  922. tooltip: null,
  923. }
  924. const rescueModeValid = validateRescueMode(obj)
  925. if (!rescueModeValid.validate) return rescueModeValid
  926. if (findPlatform(obj.hypervisor) !== SERVER_TYPE.public) {
  927. ret.tooltip = i18n.t('compute.text_1118')
  928. return ret
  929. }
  930. if (obj.billing_type !== 'prepaid') {
  931. ret.tooltip = i18n.t('compute.text_1119')
  932. return ret
  933. }
  934. ret.validate = true
  935. return ret
  936. },
  937. hidden: () => !(hasSetupKey(['aliyun', 'qcloud', 'huawei', 'ucloud', 'ecloud', 'jdcloud', 'ctyun'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_auto_renewal'),
  938. },
  939. // 更改计费模式
  940. {
  941. label: i18n.t('compute.change_billing_type'),
  942. permission: 'server_perform_change_billing_type',
  943. action: () => {
  944. this.createDialog('VmChangeBillingTypeDialog', {
  945. steadyStatus: ['running', 'ready'],
  946. data: [obj],
  947. columns: this.columns,
  948. onManager: this.onManager,
  949. refresh: this.refresh,
  950. })
  951. },
  952. meta: () => {
  953. const ret = {
  954. validate: false,
  955. tooltip: null,
  956. }
  957. const rescueModeValid = validateRescueMode(obj)
  958. if (!rescueModeValid.validate) return rescueModeValid
  959. if (obj.brand !== BRAND_MAP.Aliyun.key && obj.brand !== BRAND_MAP.Qcloud.key) {
  960. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[obj.provider].label])
  961. return ret
  962. }
  963. ret.validate = true
  964. return ret
  965. },
  966. hidden: () => !(hasSetupKey(['aliyun', 'qcloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_change_billing_type'),
  967. },
  968. ],
  969. },
  970. // * 配置修改
  971. {
  972. label: i18n.t('compute.group_action.update_config'),
  973. submenus: [
  974. // 重装系统
  975. {
  976. label: i18n.t('compute.text_357'),
  977. permission: 'server_perform_rebuild_root',
  978. action: () => {
  979. this.createDialog('VmRebuildRootDialog', {
  980. data: [obj],
  981. columns: this.columns,
  982. onManager: this.onManager,
  983. })
  984. },
  985. meta: () => {
  986. const ret = {
  987. validate: false,
  988. tooltip: null,
  989. }
  990. const rescueModeValid = validateRescueMode(obj)
  991. if (!rescueModeValid.validate) return rescueModeValid
  992. if (obj.shutdown_mode === 'stop_charging' && obj.status === 'ready') {
  993. ret.validate = false
  994. ret.tooltip = i18n.t('compute.server.shutdown_mode.tooltip')
  995. return ret
  996. }
  997. if (commonUnabled(obj)) return ret
  998. ret.validate = cloudEnabled('rebuildRoot', obj)
  999. ret.tooltip = cloudUnabledTip('rebuildRoot', obj)
  1000. return ret
  1001. },
  1002. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_rebuild_root'),
  1003. },
  1004. // 调整配置
  1005. {
  1006. label: i18n.t('compute.text_1100'),
  1007. permission: 'server_perform_change_config',
  1008. action: () => {
  1009. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.adjust_configuration_callback_address', () => {
  1010. this.$router.push({
  1011. name: 'VMInstanceAdjustConfig',
  1012. query: {
  1013. id: obj.id,
  1014. },
  1015. })
  1016. })
  1017. },
  1018. meta: () => {
  1019. const ret = {
  1020. validate: false,
  1021. tooltip: null,
  1022. }
  1023. const rescueModeValid = validateRescueMode(obj)
  1024. if (!rescueModeValid.validate) return rescueModeValid
  1025. if (obj.backup_host_id) {
  1026. ret.tooltip = i18n.t('compute.text_1111')
  1027. return ret
  1028. }
  1029. if (obj.os_arch === HOST_CPU_ARCHS.arm.key && obj.status === 'running') {
  1030. ret.tooltip = i18n.t('compute.text_1371')
  1031. return ret
  1032. }
  1033. if (obj.shutdown_mode === 'stop_charging' && obj.status === 'ready') {
  1034. ret.validate = false
  1035. ret.tooltip = i18n.t('compute.server.shutdown_mode.tooltip')
  1036. return ret
  1037. }
  1038. if (commonUnabled(obj)) return ret
  1039. ret.validate = cloudEnabled('adjustConfig', obj)
  1040. ret.tooltip = cloudUnabledTip('adjustConfig', obj)
  1041. return ret
  1042. },
  1043. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_change_config'),
  1044. },
  1045. // 设置GPU卡
  1046. {
  1047. label: i18n.t('compute.text_1112'),
  1048. permission: 'server_perform_set_isolated_device,attach-isolated-device,server_perform_detach_isolated_device',
  1049. action: () => {
  1050. this.createDialog('VmAttachGpuDialog', {
  1051. data: [obj],
  1052. columns: this.columns,
  1053. onManager: this.onManager,
  1054. })
  1055. },
  1056. meta: () => {
  1057. const provider = obj.provider
  1058. const ret = {
  1059. validate: false,
  1060. tooltip: null,
  1061. }
  1062. const rescueModeValid = validateRescueMode(obj)
  1063. if (!rescueModeValid.validate) return rescueModeValid
  1064. if (!this.isAdminMode && !this.isDomainMode) {
  1065. ret.tooltip = i18n.t('compute.text_1279', [i18n.t('dictionary.domain')])
  1066. return ret
  1067. }
  1068. if (findPlatform(obj.hypervisor, 'hypervisor') !== SERVER_TYPE.idc) {
  1069. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1070. return ret
  1071. }
  1072. ret.validate = cloudEnabled('acttachGpu', obj)
  1073. ret.tooltip = cloudUnabledTip('acttachGpu', obj)
  1074. return ret
  1075. },
  1076. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_set_gpu'),
  1077. },
  1078. // 设置USB透传
  1079. {
  1080. label: i18n.t('compute.text_1399'),
  1081. permission: 'server_perform_set_isolated_device,attach-isolated-device,server_perform_detach_isolated_device',
  1082. action: () => {
  1083. this.createDialog('VmAttachUsbDialog', {
  1084. data: [obj],
  1085. columns: this.columns,
  1086. onManager: this.onManager,
  1087. })
  1088. },
  1089. meta: () => {
  1090. const provider = obj.provider
  1091. const ret = {
  1092. validate: false,
  1093. tooltip: null,
  1094. }
  1095. const rescueModeValid = validateRescueMode(obj)
  1096. if (!rescueModeValid.validate) return rescueModeValid
  1097. if (!this.isAdminMode && !this.isDomainMode) {
  1098. ret.tooltip = i18n.t('compute.text_1279', [i18n.t('dictionary.domain')])
  1099. return ret
  1100. }
  1101. if (findPlatform(obj.hypervisor, 'hypervisor') !== SERVER_TYPE.idc) {
  1102. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1103. return ret
  1104. }
  1105. ret.validate = cloudEnabled('acttachUsb', obj)
  1106. ret.tooltip = cloudUnabledTip('acttachUsb', obj)
  1107. return ret
  1108. },
  1109. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_set_usb'),
  1110. },
  1111. // 修改启动顺序
  1112. {
  1113. label: i18n.t('compute.change_boot_index'),
  1114. permission: 'server_perform_set_boot_index',
  1115. action: () => {
  1116. this.createDialog('VmChangeBootIndexDialog', {
  1117. data: [obj],
  1118. columns: this.columns,
  1119. onManager: this.onManager,
  1120. })
  1121. },
  1122. meta: (row) => {
  1123. const isOneCloud = row.brand === 'OneCloud'
  1124. const provider = obj.provider
  1125. const rescueModeValid = validateRescueMode(obj)
  1126. if (!rescueModeValid.validate) return rescueModeValid
  1127. return {
  1128. validate: isOneCloud,
  1129. tooltip: !isOneCloud && i18n.t('compute.text_473', [PROVIDER_MAP[provider].label]),
  1130. }
  1131. },
  1132. hidden: (row) => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_set_boot_index'),
  1133. },
  1134. // 更换块存储
  1135. {
  1136. label: i18n.t('compute.vminstance.change_disk_storage'),
  1137. permission: 'server_perform_change_storage',
  1138. action: () => {
  1139. this.createDialog('VmChangeBlockStorageDialog', {
  1140. data: [obj],
  1141. columns: this.columns,
  1142. onManager: this.onManager,
  1143. refresh: this.refresh,
  1144. })
  1145. },
  1146. meta: () => {
  1147. const provider = obj.provider
  1148. const ret = {
  1149. validate: true,
  1150. }
  1151. const rescueModeValid = validateRescueMode(obj)
  1152. if (!rescueModeValid.validate) return rescueModeValid
  1153. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1154. ret.validate = false
  1155. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1156. return ret
  1157. }
  1158. return {
  1159. validate: cloudEnabled('changeBlockStorage', obj),
  1160. tooltip: cloudUnabledTip('changeBlockStorage', obj),
  1161. }
  1162. },
  1163. hidden: () => !hasSetupKey(['onecloud']) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_change_disk_storage'),
  1164. },
  1165. // 绑定物理CPU
  1166. {
  1167. label: i18n.t('compute.bind_physical_cpu'),
  1168. permission: 'server_perform_cpuset',
  1169. action: () => {
  1170. this.createDialog('BindPhysicalCpuDialog', {
  1171. data: [obj],
  1172. columns: this.columns,
  1173. onManager: this.onManager,
  1174. alert: i18n.t('compute.text_1391'),
  1175. refresh: this.refresh,
  1176. })
  1177. },
  1178. meta: () => {
  1179. const ret = {
  1180. validate: false,
  1181. tooltip: null,
  1182. }
  1183. const rescueModeValid = validateRescueMode(obj)
  1184. if (!rescueModeValid.validate) return rescueModeValid
  1185. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1186. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[obj.provider].label])
  1187. return ret
  1188. }
  1189. return {
  1190. ...ret,
  1191. validate: true,
  1192. }
  1193. },
  1194. hidden: () => !hasSetupKey(['onecloud']) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_cpuset_cores'),
  1195. },
  1196. // 设置磁盘速度
  1197. {
  1198. label: i18n.t('compute.text_1249'),
  1199. permission: 'server_perform_io_throttle',
  1200. action: () => {
  1201. this.createDialog('VmSetSpeedDialog', {
  1202. data: [obj],
  1203. columns: this.columns,
  1204. onManager: this.onManager,
  1205. })
  1206. },
  1207. meta: () => {
  1208. const provider = obj.provider
  1209. const ret = {
  1210. validate: false,
  1211. tooltip: null,
  1212. }
  1213. const rescueModeValid = validateRescueMode(obj)
  1214. if (!rescueModeValid.validate) return rescueModeValid
  1215. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1216. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1217. return ret
  1218. }
  1219. if (obj.status !== 'running') {
  1220. ret.tooltip = i18n.t('compute.text_1282')
  1221. return ret
  1222. }
  1223. ret.validate = true
  1224. return ret
  1225. },
  1226. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_set_disk_speed'),
  1227. },
  1228. ],
  1229. },
  1230. // * 密码密钥
  1231. {
  1232. label: i18n.t('compute.text_360'),
  1233. submenus: [
  1234. // 重置密码
  1235. {
  1236. label: i18n.t('compute.text_276'),
  1237. permission: 'server_perform_set_password',
  1238. action: () => {
  1239. this.createDialog('VmResetPasswordDialog', {
  1240. data: [obj],
  1241. columns: this.columns,
  1242. onManager: this.onManager,
  1243. })
  1244. },
  1245. meta: () => {
  1246. const ret = {
  1247. validate: false,
  1248. tooltip: null,
  1249. }
  1250. const rescueModeValid = validateRescueMode(obj)
  1251. if (!rescueModeValid.validate) return rescueModeValid
  1252. if (commonUnabled(obj)) return ret
  1253. if (obj.keypair_id && obj.keypair_id.toLowerCase() !== 'none') {
  1254. ret.tooltip = i18n.t('compute.text_277')
  1255. return ret
  1256. }
  1257. ret.validate = cloudEnabled('resetPassword', obj)
  1258. ret.tooltip = cloudUnabledTip('resetPassword', obj)
  1259. return ret
  1260. },
  1261. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_reset_password'),
  1262. },
  1263. // 绑定密钥
  1264. {
  1265. label: i18n.t('compute.text_361'),
  1266. permission: 'server_perform_deploy',
  1267. action: () => {
  1268. this.createDialog('VmBindKeypairDialog', {
  1269. data: [obj],
  1270. columns: this.columns,
  1271. onManager: this.onManager,
  1272. })
  1273. },
  1274. meta: () => {
  1275. const ret = {
  1276. validate: false,
  1277. tooltip: null,
  1278. }
  1279. const rescueModeValid = validateRescueMode(obj)
  1280. if (!rescueModeValid.validate) return rescueModeValid
  1281. if (obj.hypervisor === typeClouds.hypervisorMap.openstack.key) {
  1282. ret.tooltip = i18n.t('compute.text_1284')
  1283. return ret
  1284. }
  1285. if (obj.os_type === 'Windows') {
  1286. ret.tooltip = i18n.t('compute.text_1285')
  1287. return ret
  1288. }
  1289. const osType = obj.metadata && obj.metadata.os_name
  1290. if (['aws', 'azure', 'google', 'aliyun', 'ksyun'].includes(obj.hypervisor) && osType === 'Windows') {
  1291. ret.tooltip = i18n.t('compute.text_1285')
  1292. return ret
  1293. }
  1294. if (commonUnabled(obj)) return ret
  1295. if (obj.keypair) {
  1296. ret.tooltip = i18n.t('compute.text_363')
  1297. return ret
  1298. }
  1299. ret.validate = cloudEnabled('bindKeyPair', obj)
  1300. ret.tooltip = cloudUnabledTip('bindKeyPair', obj)
  1301. return ret
  1302. },
  1303. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_bind_key'),
  1304. },
  1305. // 解绑密钥
  1306. {
  1307. label: i18n.t('compute.text_364'),
  1308. permission: 'server_perform_deploy',
  1309. action: () => {
  1310. this.createDialog('VmUnbindKeypairDialog', {
  1311. data: [obj],
  1312. columns: this.columns,
  1313. onManager: this.onManager,
  1314. })
  1315. },
  1316. meta: () => {
  1317. const ret = {
  1318. validate: false,
  1319. tooltip: null,
  1320. }
  1321. const rescueModeValid = validateRescueMode(obj)
  1322. if (!rescueModeValid.validate) return rescueModeValid
  1323. if (commonUnabled(obj)) return ret
  1324. if (!obj.keypair) {
  1325. ret.tooltip = i18n.t('compute.text_365')
  1326. return ret
  1327. }
  1328. ret.validate = cloudEnabled('unBindKeyPair', obj)
  1329. ret.tooltip = cloudUnabledTip('unBindKeyPair', obj)
  1330. return ret
  1331. },
  1332. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_unbind_key'),
  1333. },
  1334. // 设置免密登录
  1335. {
  1336. label: i18n.t('compute.vminstance.actions.setup_ssh_authentication'),
  1337. permission: 'server_perform_setup_ssh_proxy',
  1338. action: () => {
  1339. this.createDialog('SetupSSHDialog', {
  1340. data: [obj],
  1341. columns: this.columns,
  1342. onManager: this.onManager,
  1343. })
  1344. },
  1345. meta: () => {
  1346. const ret = {
  1347. validate: true,
  1348. tooltip: null,
  1349. }
  1350. if (obj.hypervisor === typeClouds.hypervisorMap.sangfor.key) {
  1351. ret.validate = false
  1352. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.sangfor.label])
  1353. return ret
  1354. }
  1355. const rescueModeValid = validateRescueMode(obj)
  1356. if (!rescueModeValid.validate) return rescueModeValid
  1357. const isLinux = obj.os_type && obj.os_type.toLowerCase() === 'linux'
  1358. if (!isLinux) {
  1359. ret.validate = false
  1360. ret.tooltip = i18n.t('compute.text_362')
  1361. return ret
  1362. }
  1363. if (!commonEnabled(obj, ['running'])) {
  1364. ret.validate = false
  1365. ret.tooltip = i18n.t('db.text_156')
  1366. return ret
  1367. }
  1368. return ret
  1369. },
  1370. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_setup_ssh_proxy'),
  1371. },
  1372. // 探测免密登录
  1373. {
  1374. label: i18n.t('compute.vminstance.actions.detect_ssh_authentication'),
  1375. permission: 'server_perform_make_sshable',
  1376. action: () => {
  1377. this.createDialog('DetectSSHDialog', {
  1378. data: [obj],
  1379. columns: this.columns,
  1380. onManager: this.onManager,
  1381. })
  1382. },
  1383. meta: () => {
  1384. const ret = {
  1385. validate: true,
  1386. tooltip: null,
  1387. }
  1388. if (obj.hypervisor === typeClouds.hypervisorMap.sangfor.key) {
  1389. ret.validate = false
  1390. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.sangfor.label])
  1391. return ret
  1392. }
  1393. const rescueModeValid = validateRescueMode(obj)
  1394. if (!rescueModeValid.validate) return rescueModeValid
  1395. if (!commonEnabled(obj, ['running'])) {
  1396. ret.validate = false
  1397. ret.tooltip = i18n.t('db.text_156')
  1398. return ret
  1399. }
  1400. return ret
  1401. },
  1402. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_detect_ssh_proxy'),
  1403. },
  1404. ],
  1405. },
  1406. // * 镜像与备份
  1407. {
  1408. label: i18n.t('compute.group_action.mirror_backup'),
  1409. submenus: [
  1410. // 保存镜像
  1411. {
  1412. label: i18n.t('compute.text_1236'),
  1413. permission: 'server_perform_save_image',
  1414. action: () => {
  1415. this.createDialog('VmSaveImageDialog', {
  1416. data: [obj],
  1417. columns: this.columns,
  1418. onManager: this.onManager,
  1419. })
  1420. },
  1421. meta: () => {
  1422. const ret = {
  1423. validate: false,
  1424. tooltip: null,
  1425. }
  1426. const rescueModeValid = validateRescueMode(obj)
  1427. if (!rescueModeValid.validate) return rescueModeValid
  1428. // if (findPlatform(obj.hypervisor) === SERVER_TYPE.public) {
  1429. // ret.tooltip = i18n.t('compute.text_1286')
  1430. // return ret
  1431. // }
  1432. const noSupportBrand = [
  1433. typeClouds.hypervisorMap.openstack?.brand,
  1434. typeClouds.hypervisorMap.zstack?.brand,
  1435. // typeClouds.hypervisorMap.dstack?.brand,
  1436. typeClouds.hypervisorMap.ucloud?.brand,
  1437. typeClouds.hypervisorMap.ctyun?.brand,
  1438. typeClouds.hypervisorMap.nutanix?.brand,
  1439. typeClouds.hypervisorMap.proxmox?.brand,
  1440. typeClouds.hypervisorMap.sangfor?.brand,
  1441. ]
  1442. if (noSupportBrand.includes(obj.brand)) {
  1443. ret.tooltip = i18n.t('compute.text_1287', [obj.brand])
  1444. return ret
  1445. }
  1446. if (commonUnabled(obj)) return ret
  1447. ret.validate = commonEnabled(obj)
  1448. ret.tooltip = commonTip(obj)
  1449. return ret
  1450. },
  1451. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_save_image'),
  1452. },
  1453. // 挂载ISO
  1454. {
  1455. label: i18n.t('compute.text_366'),
  1456. permission: 'server_perform_insertiso',
  1457. action: () => {
  1458. this.createDialog('VmMountIsoDialog', {
  1459. data: [obj],
  1460. columns: this.columns,
  1461. onManager: this.onManager,
  1462. refresh: this.refresh,
  1463. })
  1464. },
  1465. meta: () => {
  1466. const provider = obj.provider
  1467. const ret = {
  1468. validate: false,
  1469. tooltip: null,
  1470. }
  1471. const rescueModeValid = validateRescueMode(obj)
  1472. if (!rescueModeValid.validate) return rescueModeValid
  1473. if (obj.hypervisor === typeClouds.hypervisorMap.esxi.key) {
  1474. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1475. return ret
  1476. }
  1477. if (findPlatform(obj.hypervisor) === SERVER_TYPE.public) {
  1478. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1479. return ret
  1480. }
  1481. if (obj.hypervisor === typeClouds.hypervisorMap.sangfor.key) {
  1482. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.sangfor.label])
  1483. return ret
  1484. }
  1485. if (commonUnabled(obj)) return ret
  1486. if (obj.cdrom) {
  1487. ret.tooltip = i18n.t('compute.text_1288')
  1488. return ret
  1489. }
  1490. ret.validate = cloudEnabled('insertiso', obj)
  1491. ret.tooltip = cloudUnabledTip('insertiso', obj)
  1492. return ret
  1493. },
  1494. hidden: () => !(hasSetupKey(['vmware', 'onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_mount_iso'),
  1495. },
  1496. // 卸载ISO
  1497. {
  1498. label: i18n.t('compute.text_367'),
  1499. permission: 'server_perform_ejectiso',
  1500. action: () => {
  1501. this.createDialog('VmUnmountIsoDialog', {
  1502. data: [obj],
  1503. columns: this.columns,
  1504. onManager: this.onManager,
  1505. refresh: this.refresh,
  1506. })
  1507. },
  1508. meta: () => {
  1509. const provider = obj.provider
  1510. const ret = {
  1511. validate: false,
  1512. tooltip: null,
  1513. }
  1514. const rescueModeValid = validateRescueMode(obj)
  1515. if (!rescueModeValid.validate) return rescueModeValid
  1516. if (obj.hypervisor === typeClouds.hypervisorMap.esxi.key) {
  1517. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1518. return ret
  1519. }
  1520. if (findPlatform(obj.hypervisor) === SERVER_TYPE.public) {
  1521. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1522. return ret
  1523. }
  1524. if (obj.hypervisor === typeClouds.hypervisorMap.sangfor.key) {
  1525. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.sangfor.label])
  1526. return ret
  1527. }
  1528. if (commonUnabled(obj)) return ret
  1529. if (!obj.cdrom) {
  1530. ret.tooltip = i18n.t('compute.text_1289')
  1531. return ret
  1532. }
  1533. ret.validate = cloudEnabled('ejectiso', obj)
  1534. ret.tooltip = cloudUnabledTip('ejectiso', obj)
  1535. return ret
  1536. },
  1537. hidden: () => !(hasSetupKey(['vmware', 'onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_unmount_iso'),
  1538. },
  1539. // 创建快照
  1540. {
  1541. label: i18n.t('compute.text_1276'),
  1542. permission: 'snapshots_create,server_perform_instance_backup',
  1543. action: () => {
  1544. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.create_snapshot_callback_address', () => {
  1545. this.createDialog('VmSnapshotCreateDialog', {
  1546. data: [obj],
  1547. columns: this.columns,
  1548. onManager: this.onManager,
  1549. refresh: this.refresh,
  1550. })
  1551. })
  1552. },
  1553. meta: () => {
  1554. const ret = {
  1555. validate: false,
  1556. tooltip: null,
  1557. }
  1558. const rescueModeValid = validateRescueMode(obj)
  1559. if (!rescueModeValid.validate) return rescueModeValid
  1560. if (obj.is_prepaid_recycle) {
  1561. ret.tooltip = i18n.t('compute.text_285')
  1562. return ret
  1563. }
  1564. if (obj.backup_host_id) {
  1565. ret.tooltip = i18n.t('compute.text_1277')
  1566. return ret
  1567. }
  1568. if (commonUnabled(obj)) return ret
  1569. ret.validate = cloudEnabled('createSnapshot', obj)
  1570. ret.tooltip = cloudUnabledTip('createSnapshot', obj)
  1571. return ret
  1572. },
  1573. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_create_snapshot'),
  1574. },
  1575. // 创建备份
  1576. {
  1577. label: i18n.t('compute.create_disk_backup2'),
  1578. permission: 'server_perform_instance_backup,diskbackups_create,instancebackups_create',
  1579. action: () => {
  1580. this.createDialog('VmBackupCreateDialog', {
  1581. data: [obj],
  1582. columns: this.columns,
  1583. onManager: this.onManager,
  1584. refresh: this.refresh,
  1585. })
  1586. },
  1587. meta: () => {
  1588. const ret = {
  1589. validate: false,
  1590. tooltip: null,
  1591. }
  1592. const rescueModeValid = validateRescueMode(obj)
  1593. if (!rescueModeValid.validate) return rescueModeValid
  1594. if (obj.is_prepaid_recycle) {
  1595. ret.tooltip = i18n.t('compute.text_285')
  1596. return ret
  1597. }
  1598. if (obj.backup_host_id) {
  1599. ret.tooltip = i18n.t('compute.text_1277')
  1600. return ret
  1601. }
  1602. if (commonUnabled(obj)) return ret
  1603. ret.validate = cloudEnabled('createBackup', obj)
  1604. ret.tooltip = cloudUnabledTip('createBackup', obj)
  1605. return ret
  1606. },
  1607. hidden: () => !hasSetupKey(['onecloud']) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_create_backup'),
  1608. },
  1609. ],
  1610. },
  1611. // * 网络与安全
  1612. {
  1613. label: i18n.t('compute.text_1290'),
  1614. submenus: [
  1615. // 关联安全组
  1616. {
  1617. label: i18n.t('compute.text_1116'),
  1618. permissionLabels: [i18n.t('compute.text_1116'), i18n.t('compute.revoke_secgroup'), i18n.t('compute.set_secgroup')],
  1619. permission: 'server_perform_add_secgroup,server_perform_revoke_secgroup,server_perform_set_secgroup',
  1620. action: () => {
  1621. this.createDialog('VmSetSecgroupDialog', {
  1622. vm: this,
  1623. data: [obj],
  1624. columns: this.columns,
  1625. onManager: this.onManager,
  1626. refresh: this.refresh,
  1627. type: 'vminstance',
  1628. })
  1629. },
  1630. meta: () => {
  1631. const rescueModeValid = validateRescueMode(obj)
  1632. if (!rescueModeValid.validate) return rescueModeValid
  1633. const ret = {
  1634. validate: cloudEnabled('assignSecgroup', obj),
  1635. tooltip: cloudUnabledTip('assignSecgroup', obj),
  1636. }
  1637. return ret
  1638. },
  1639. hidden: () => !(hasSetupKey(['onestack', 'onecloud', 'public', 'openstack', 'dstack', 'zstack', 'apsara', 'cloudpods', 'hcso', 'hcs'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_add_secgroup'),
  1640. },
  1641. // 绑定eip
  1642. {
  1643. label: i18n.t('compute.text_1179'),
  1644. permission: 'server_perform_create_eip',
  1645. action: () => {
  1646. this.createDialog('VmBindEipDialog', {
  1647. data: [obj],
  1648. columns: this.columns,
  1649. refresh: this.refresh,
  1650. onManager: this.onManager,
  1651. })
  1652. },
  1653. meta: () => {
  1654. const ret = {
  1655. validate: false,
  1656. tooltip: null,
  1657. }
  1658. const rescueModeValid = validateRescueMode(obj)
  1659. if (!rescueModeValid.validate) return rescueModeValid
  1660. if (commonUnabled(obj)) return ret
  1661. if (obj.eip_mode === 'public_ip' && obj.hypervisor !== 'aws') {
  1662. ret.tooltip = i18n.t('compute.public_ip_tooltip')
  1663. return ret
  1664. }
  1665. if (obj.eip_mode !== 'public_ip' && obj.eip) {
  1666. ret.tooltip = i18n.t('compute.text_1291')
  1667. return ret
  1668. }
  1669. if (obj.brand === 'OneCloud' && obj.vpc_id === 'default') {
  1670. ret.tooltip = i18n.t('compute.text_1292')
  1671. return ret
  1672. }
  1673. if (obj.vpc_external_access_mode === 'none') {
  1674. ret.tooltip = i18n.t('compute.disable_bind_eip')
  1675. return ret
  1676. }
  1677. ret.validate = cloudEnabled('bindEip', obj)
  1678. ret.tooltip = cloudUnabledTip('bindEip', obj)
  1679. return ret
  1680. },
  1681. hidden: () => !(hasSetupKey(['onestack', 'onecloud', 'public', 'openstack', 'dstack', 'zstack', 'apsara', 'cloudpods', 'hcso', 'hcs'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_bind_elastic_public_ip'),
  1682. },
  1683. // 解绑eip
  1684. {
  1685. label: i18n.t('compute.text_1264'),
  1686. permission: 'server_perform_dissociate_eip',
  1687. action: () => {
  1688. this.createDialog('VmUnbindEipDialog', {
  1689. data: [obj],
  1690. columns: this.columns,
  1691. onManager: this.onManager,
  1692. refresh: this.refresh,
  1693. })
  1694. },
  1695. meta: () => {
  1696. const ret = {
  1697. validate: false,
  1698. tooltip: null,
  1699. }
  1700. const rescueModeValid = validateRescueMode(obj)
  1701. if (!rescueModeValid.validate) return rescueModeValid
  1702. if (commonUnabled(obj)) return ret
  1703. if (obj.eip_mode !== 'elastic_ip') {
  1704. ret.tooltip = i18n.t('compute.text_1293')
  1705. return ret
  1706. }
  1707. if (obj.eip_mode === 'public_ip') {
  1708. ret.tooltip = i18n.t('compute.text_1294')
  1709. return ret
  1710. }
  1711. ret.validate = cloudEnabled('unbindEip', obj)
  1712. ret.tooltip = cloudUnabledTip('unbindEip', obj)
  1713. return ret
  1714. },
  1715. hidden: () => !(hasSetupKey(['onestack', 'onecloud', 'public', 'openstack', 'dstack', 'zstack', 'apsara', 'cloudpods', 'hcso', 'hcs'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_unbind_elastic_public_ip'),
  1716. },
  1717. // 公网IP转EIP
  1718. {
  1719. label: i18n.t('compute.text_1121'),
  1720. permission: 'server_perform_publicip_to_eip',
  1721. action: () => {
  1722. this.createDialog('VmPublicIpToEipDialog', {
  1723. data: [obj],
  1724. columns: this.columns,
  1725. onManager: this.onManager,
  1726. refresh: this.refresh,
  1727. })
  1728. },
  1729. meta: () => {
  1730. const ret = {
  1731. validate: false,
  1732. tooltip: null,
  1733. }
  1734. const rescueModeValid = validateRescueMode(obj)
  1735. if (!rescueModeValid.validate) return rescueModeValid
  1736. if (obj.eip && obj.eip_mode === 'elastic_ip') {
  1737. ret.tooltip = i18n.t('compute.text_1122')
  1738. return ret
  1739. }
  1740. if (obj.eip_mode !== 'public_ip') {
  1741. ret.tooltip = i18n.t('compute.text_1123')
  1742. return ret
  1743. }
  1744. ret.validate = cloudEnabled('publicIpToEip', obj)
  1745. ret.tooltip = cloudUnabledTip('publicIpToEip', obj)
  1746. return ret
  1747. },
  1748. hidden: () => !(hasSetupKey(['aliyun', 'qcloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_public_ip_to_eip'),
  1749. },
  1750. // 设置源/目标检查
  1751. {
  1752. label: i18n.t('compute.text_1124'),
  1753. permission: 'server_perform_modify_src_check',
  1754. action: () => {
  1755. this.createDialog('VmSourceTargetCheckDialog', {
  1756. data: [obj],
  1757. columns: this.columns,
  1758. onManager: this.onManager,
  1759. refresh: this.refresh,
  1760. })
  1761. },
  1762. meta: () => {
  1763. const provider = obj.provider
  1764. const ret = { validate: true, tooltip: null }
  1765. const rescueModeValid = validateRescueMode(obj)
  1766. if (!rescueModeValid.validate) return rescueModeValid
  1767. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1768. ret.validate = false
  1769. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1770. return ret
  1771. }
  1772. if (!['running', 'ready'].includes(obj.status)) {
  1773. ret.validate = false
  1774. ret.tooltip = i18n.t('compute.text_1126')
  1775. return ret
  1776. }
  1777. return ret
  1778. },
  1779. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_set_source_check'),
  1780. },
  1781. {
  1782. label: i18n.t('compute.add_to_bastion'),
  1783. permission: 'bastion_servers_create',
  1784. action: () => {
  1785. this.createDialog('VmAddToBastionDialog', {
  1786. data: [obj],
  1787. columns: this.columns,
  1788. onManager: this.onManager,
  1789. refresh: this.refresh,
  1790. })
  1791. },
  1792. meta: (obj) => {
  1793. const ret = { validate: true }
  1794. if (obj.metadata?.bastion_server) {
  1795. ret.validate = false
  1796. ret.tooltip = i18n.t('compute.already_in_bastion')
  1797. return ret
  1798. }
  1799. if (obj.status !== 'running') {
  1800. ret.validate = false
  1801. ret.tooltip = i18n.t('compute.text_1282')
  1802. return ret
  1803. }
  1804. return validateRescueMode(obj)
  1805. },
  1806. hidden: () => {
  1807. if (!this.$appConfig.isPrivate || this.$store.getters.isSysCE || this.$isScopedPolicyMenuHidden('sub_hidden_menus.bastion_host') || (isLicense2() && !hasSetupKey('bastionhost')) || !hasBastionService) {
  1808. return true
  1809. }
  1810. return false
  1811. },
  1812. },
  1813. {
  1814. label: i18n.t('compute.remove_from_bastion'),
  1815. permission: 'bastion_servers_delete',
  1816. action: () => {
  1817. this.createDialog('VmRemoveFromBastionDialog', {
  1818. data: [obj],
  1819. columns: this.columns,
  1820. onManager: this.onManager,
  1821. refresh: this.refresh,
  1822. })
  1823. },
  1824. meta: (obj) => {
  1825. const ret = { validate: true }
  1826. if (!obj.metadata?.bastion_server) {
  1827. ret.validate = false
  1828. return ret
  1829. }
  1830. if (!['running', 'ready'].includes(obj.status)) {
  1831. ret.validate = false
  1832. ret.tooltip = i18n.t('compute.text_1126')
  1833. return ret
  1834. }
  1835. return ret
  1836. },
  1837. hidden: () => {
  1838. if (!this.$appConfig.isPrivate || this.$store.getters.isSysCE || this.$isScopedPolicyMenuHidden('sub_hidden_menus.bastion_host') || (isLicense2() && !hasSetupKey('bastionhost')) || !hasBastionService) {
  1839. return true
  1840. }
  1841. return false
  1842. },
  1843. },
  1844. ],
  1845. },
  1846. // * 高可用
  1847. {
  1848. label: i18n.t('compute.text_1295'),
  1849. submenus: [
  1850. // 添加备份机
  1851. {
  1852. label: i18n.t('compute.text_1162'),
  1853. permission: 'server_perform_create_backup',
  1854. action: () => {
  1855. this.createDialog('VmAddBackupDialog', {
  1856. data: [obj],
  1857. columns: this.columns,
  1858. onManager: this.onManager,
  1859. })
  1860. },
  1861. meta: () => {
  1862. const provider = obj.provider
  1863. const ret = {
  1864. validate: false,
  1865. tooltip: null,
  1866. }
  1867. const rescueModeValid = validateRescueMode(obj)
  1868. if (!rescueModeValid.validate) return rescueModeValid
  1869. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1870. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1871. return ret
  1872. }
  1873. if (!['ready'].includes(obj.status)) {
  1874. ret.tooltip = i18n.t('compute.text_1308')
  1875. return ret
  1876. }
  1877. if (obj.backup_host_id) {
  1878. ret.tooltip = i18n.t('compute.text_1296')
  1879. return ret
  1880. }
  1881. if (obj.is_gpu) {
  1882. ret.tooltip = i18n.t('compute.gpu_not_support_add_host')
  1883. return ret
  1884. }
  1885. if (!this.isAdminMode && !this.isDomainMode) {
  1886. ret.tooltip = i18n.t('migration.project.error')
  1887. return ret
  1888. }
  1889. const isLvm = obj.disks_info.some(item => item.storage_type.includes('lvm'))
  1890. if (isLvm) {
  1891. ret.tooltip = i18n.t('compute.lvm_shared_storage.validate_tooltip')
  1892. return ret
  1893. }
  1894. ret.validate = true
  1895. return ret
  1896. },
  1897. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_add_backup'),
  1898. },
  1899. // 删除备份机
  1900. {
  1901. label: i18n.t('compute.text_1209'),
  1902. permission: 'server_perform_delete_backup',
  1903. action: () => {
  1904. this.createDialog('VmDeleteBackupDialog', {
  1905. data: [obj],
  1906. columns: this.columns,
  1907. onManager: this.onManager,
  1908. })
  1909. },
  1910. meta: () => {
  1911. const provider = obj.provider
  1912. const ret = {
  1913. validate: false,
  1914. tooltip: null,
  1915. }
  1916. const rescueModeValid = validateRescueMode(obj)
  1917. if (!rescueModeValid.validate) return rescueModeValid
  1918. if (!obj.backup_host_id) {
  1919. ret.tooltip = i18n.t('compute.text_1383')
  1920. return ret
  1921. }
  1922. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  1923. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[provider].label])
  1924. return ret
  1925. }
  1926. if (!this.isAdminMode && !this.isDomainMode) {
  1927. ret.tooltip = i18n.t('migration.project.error')
  1928. return ret
  1929. }
  1930. ret.validate = true
  1931. return ret
  1932. },
  1933. hidden: () => !(hasSetupKey(['onecloud'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_delete_backup'),
  1934. },
  1935. // 迁移
  1936. {
  1937. label: i18n.t('compute.text_1127'),
  1938. permission: 'server_perform_migrate,server_perform_live_migrate',
  1939. action: () => {
  1940. this.createDialog('VmTransferDialog', {
  1941. data: [obj],
  1942. columns: this.columns,
  1943. onManager: this.onManager,
  1944. })
  1945. },
  1946. meta: () => {
  1947. const ret = { validate: true, tooltip: null }
  1948. const rescueModeValid = validateRescueMode(obj)
  1949. if (!rescueModeValid.validate) return rescueModeValid
  1950. if (!this.isAdminMode && !this.isDomainMode) {
  1951. ret.validate = false
  1952. ret.tooltip = this.$t('compute.tooltip.check_domain_permission')
  1953. return ret
  1954. }
  1955. if (!['running', 'ready'].includes(obj.status)) {
  1956. ret.validate = false
  1957. ret.tooltip = this.$t('compute.tooltip.check_status_transfer')
  1958. return ret
  1959. }
  1960. if (obj.backup_host_id) {
  1961. ret.validate = false
  1962. ret.tooltip = this.$t('compute.tooltip.check_backup_host_transfer')
  1963. return ret
  1964. }
  1965. if (obj.is_gpu) {
  1966. ret.validate = false
  1967. ret.tooltip = this.$t('compute.tooltip.check_gpu_transfer')
  1968. return ret
  1969. }
  1970. if (obj.cdrom) {
  1971. ret.validate = false
  1972. ret.tooltip = this.$t('compute.tooltip.check_cdrom_transfer')
  1973. return ret
  1974. }
  1975. ret.validate = cloudEnabled('transfer', obj)
  1976. ret.tooltip = cloudUnabledTip('transfer', obj)
  1977. return ret
  1978. },
  1979. hidden: () => !(hasSetupKey(['openstack', 'onecloud', 'vmware'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_transfer'),
  1980. },
  1981. // V2V迁移
  1982. {
  1983. label: i18n.t('compute.v2vtransfer.label'),
  1984. permission: 'server_perform_migrate',
  1985. action: () => {
  1986. this.createDialog('VmV2vTransferDialog', {
  1987. data: [obj],
  1988. columns: this.columns,
  1989. onManager: this.onManager,
  1990. successCallback: this.refresh,
  1991. })
  1992. },
  1993. meta: () => {
  1994. const ret = { validate: true, tooltip: null }
  1995. const rescueModeValid = validateRescueMode(obj)
  1996. if (!rescueModeValid.validate) return rescueModeValid
  1997. if (!this.isAdminMode && !this.isDomainMode) {
  1998. ret.validate = false
  1999. ret.tooltip = this.$t('compute.tooltip.check_domain_permission')
  2000. return ret
  2001. }
  2002. if (![BRAND_MAP.Cloudpods.key, BRAND_MAP.VMware.key].includes(obj.brand)) {
  2003. ret.validate = false
  2004. ret.tooltip = i18n.t('compute.brand_support', [`${BRAND_MAP.Cloudpods.label},${BRAND_MAP.VMware.label}`])
  2005. return ret
  2006. }
  2007. if (!['ready'].includes(obj.status)) {
  2008. ret.validate = false
  2009. ret.tooltip = this.$t('compute.tooltip.check_ready_status_transfer')
  2010. return ret
  2011. }
  2012. if (obj.backup_host_id) {
  2013. ret.validate = false
  2014. ret.tooltip = this.$t('compute.tooltip.check_backup_host_transfer')
  2015. return ret
  2016. }
  2017. if (!obj.ips) {
  2018. ret.validate = false
  2019. ret.tooltip = this.$t('compute.fill_ip_tooltip')
  2020. return ret
  2021. }
  2022. ret.validate = cloudEnabled('v2vTransfer', obj)
  2023. ret.tooltip = cloudUnabledTip('v2vTransfer', obj)
  2024. return ret
  2025. },
  2026. hidden: () => !(hasSetupKey(['vmware'])) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_transfer'),
  2027. },
  2028. // 快速恢复
  2029. {
  2030. label: i18n.t('compute.server.quick.recovery'),
  2031. action: () => {
  2032. this.createDialog('VmQuickRecoveryDialog', {
  2033. data: [obj],
  2034. columns: this.columns,
  2035. onManager: this.onManager,
  2036. })
  2037. },
  2038. meta: () => {
  2039. const ret = {
  2040. validate: true,
  2041. tooltip: '',
  2042. }
  2043. const rescueModeValid = validateRescueMode(obj)
  2044. if (!rescueModeValid.validate) return rescueModeValid
  2045. if (obj.brand !== BRAND_MAP.OneCloud.key) {
  2046. ret.validate = false
  2047. ret.tooltip = i18n.t('compute.text_473', [PROVIDER_MAP[obj.provider].label])
  2048. return ret
  2049. }
  2050. if (obj.host_service_status !== 'offline') {
  2051. ret.validate = false
  2052. ret.tooltip = i18n.t('compute.quick.recovery.validate.host_status_tooltip')
  2053. return ret
  2054. }
  2055. const isAllKVMShareStorages = obj.disks_info.every(item => KVM_SHARE_STORAGES.includes(item.storage_type))
  2056. if (!isAllKVMShareStorages) {
  2057. ret.validate = false
  2058. ret.tooltip = i18n.t('compute.quick.recovery.validate.host_status_tooltip')
  2059. return ret
  2060. }
  2061. return ret
  2062. },
  2063. hidden: () => !hasSetupKey(['onecloud']) || this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_migrate'),
  2064. },
  2065. ],
  2066. },
  2067. // * 删除
  2068. {
  2069. label: i18n.t('compute.perform_delete'),
  2070. submenus: [
  2071. // 设置删除保护
  2072. disableDeleteAction(Object.assign(this, {
  2073. permission: 'server_update',
  2074. }), {
  2075. name: i18n.t('dictionary.server'),
  2076. meta: () => {
  2077. const ret = { validate: true }
  2078. if (obj.hypervisor === typeClouds.hypervisorMap.bingocloud.key) {
  2079. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.bingocloud.label])
  2080. ret.validate = false
  2081. return ret
  2082. }
  2083. return ret
  2084. },
  2085. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_set_delete_protection'),
  2086. }),
  2087. // 删除
  2088. {
  2089. label: i18n.t('compute.perform_delete'),
  2090. permission: 'server_delete',
  2091. action: () => {
  2092. this.$openNewWindowForMenuHook('vminstance_configured_callback_address.delete_callback_address', () => {
  2093. this.createDialog('DeleteVmDialog', {
  2094. vm: this,
  2095. data: [obj],
  2096. columns: this.columns,
  2097. onManager: this.onManager,
  2098. title: i18n.t('compute.perform_delete'),
  2099. success: () => {
  2100. this.destroySidePages()
  2101. },
  2102. })
  2103. })
  2104. },
  2105. meta: () => {
  2106. const ret = { validate: false }
  2107. if (obj.hypervisor === typeClouds.hypervisorMap.bingocloud.key) {
  2108. ret.tooltip = i18n.t('compute.text_473', [typeClouds.hypervisorMap.bingocloud.label])
  2109. return ret
  2110. }
  2111. const { server_delete_limit = false } = this.$store.getters.globalSetting.value || {}
  2112. if (server_delete_limit && obj.status === 'running') {
  2113. ret.tooltip = i18n.t('compute.delete_limit')
  2114. return ret
  2115. }
  2116. return this.$getDeleteResult(obj)
  2117. },
  2118. hidden: () => this.$isScopedPolicyMenuHidden('vminstance_hidden_menus.server_perform_delete'),
  2119. },
  2120. ],
  2121. },
  2122. ]
  2123. },
  2124. meta: (obj) => {
  2125. let ret = {
  2126. validate: true,
  2127. tooltip: null,
  2128. }
  2129. ret = this.$isValidateResourceLock(obj)
  2130. return ret
  2131. },
  2132. },
  2133. ]
  2134. }
  2135. export default {
  2136. name: POLICY_RES_NAME_KEY_MAP.vminstance.key,
  2137. getSingleActions,
  2138. }