Create.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{params.title}}</div>
  4. <div slot="body">
  5. <a-form
  6. v-bind="formItemLayout"
  7. :form="form.fc">
  8. <a-form-item v-if="isCloudflare" :label="$t('common.name')">
  9. <a-input v-decorator="decorators.name" :placeholder="$t('validator.resourceName')" />
  10. </a-form-item>
  11. <a-form-item :label="$t('network.text_249')">
  12. <a-radio-group v-decorator="decorators.backend_type" @change="handleBackendTypeChange">
  13. <a-radio-button v-for="(v, k) in backendTypes" :value="k" :key="k">{{v}}</a-radio-button>
  14. </a-radio-group>
  15. </a-form-item>
  16. <a-form-item key="server" :label="$t('dictionary.server')" v-if="backend_type === 'guest'">
  17. <base-select
  18. resource="servers"
  19. need-params
  20. :params="serverParams"
  21. v-decorator="decorators.guest_backend"
  22. show-sync
  23. remote
  24. :remote-fn="q => ({ search: q })"
  25. :mapper="serverlistMapper"
  26. :select-props="{ placeholder: $t('network.text_334', [$t('dictionary.server')]) }" />
  27. <div slot="extra">{{$t('network.text_335', [$t('dictionary.server')])}}<help-link :href="serverHref">{{$t('network.text_26')}}</help-link>
  28. </div>
  29. </a-form-item>
  30. <a-form-item key="host" :label="$t('dictionary.host')" v-if="backend_type === 'host'">
  31. <base-select
  32. show-sync
  33. class="w-100"
  34. v-decorator="decorators.host_backend"
  35. resource="hosts"
  36. remote
  37. :remote-fn="q => ({ search: q })"
  38. :params="hostParams"
  39. :select-props="{ placeholder: $t('network.text_62') }" />
  40. </a-form-item>
  41. <a-form-item key="ip" :label="$t('network.text_213')" v-if="backend_type === 'ip'" :extra="$t('network.text_337')">
  42. <a-input v-decorator="decorators.ip_backend" :placeholder="$t('network.text_338')" />
  43. </a-form-item>
  44. <a-form-item key="ip_or_domain" :label="$t('network.text_213')" v-if="backend_type === 'ip_or_domain'">
  45. <a-input v-decorator="decorators.ip_or_domain_backend" :placeholder="$t('network.ip_or_domain')" />
  46. </a-form-item>
  47. <a-form-item :label="$t('network.text_165')" :extra="$t('network.text_339')">
  48. <a-input-number v-decorator="decorators.port" />
  49. </a-form-item>
  50. <a-form-item :label="$t('network.text_166')" :extra="$t('network.text_333', [params.maxWeight])">
  51. <a-input-number v-decorator="decorators.weight" />
  52. </a-form-item>
  53. <a-form-item v-if="isOneCloud" label="SSL" :extra="$t('network.text_340')">
  54. <a-switch v-decorator="decorators.ssl" />
  55. </a-form-item>
  56. </a-form>
  57. </div>
  58. <div slot="footer">
  59. <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
  60. <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
  61. </div>
  62. </base-dialog>
  63. </template>
  64. <script>
  65. import DialogMixin from '@/mixins/dialog'
  66. import WindowsMixin from '@/mixins/windows'
  67. import { findPlatform } from '@/utils/common/hypervisor'
  68. import regexp from '@/utils/regexp'
  69. export default {
  70. name: 'LoadbalancerbackendCreateDialog',
  71. mixins: [DialogMixin, WindowsMixin],
  72. data () {
  73. return {
  74. loading: false,
  75. form: {
  76. fc: this.$form.createForm(this),
  77. },
  78. backend_type: this.params.lbBackendgroupData.provider === 'Cloudflare' ? 'ip_or_domain' : 'guest',
  79. formItemLayout: {
  80. wrapperCol: {
  81. span: 20,
  82. },
  83. labelCol: {
  84. span: 4,
  85. },
  86. },
  87. firstLbBackendVpc: undefined,
  88. }
  89. },
  90. computed: {
  91. isOneCloud () {
  92. return this.params.lbBackendgroupData.provider === 'OneCloud'
  93. },
  94. isCloudflare () {
  95. return this.params.lbBackendgroupData.provider === 'Cloudflare'
  96. },
  97. backendTypes () {
  98. if (this.isCloudflare) {
  99. return {
  100. ip_or_domain: this.$t('network.text_71'),
  101. }
  102. }
  103. if (!this.isOneCloud) {
  104. return {
  105. guest: this.$t('network.text_341'),
  106. }
  107. }
  108. const _ = {
  109. guest: this.$t('network.text_341'),
  110. host: this.$t('network.text_342'),
  111. ip: this.$t('network.text_71'),
  112. }
  113. const { isAdminMode, isDomainMode } = this.$store.getters
  114. if (!isAdminMode && !isDomainMode) {
  115. delete _.host
  116. }
  117. return _
  118. },
  119. decorators () {
  120. const isRequired = (k) => this.backend_type === k
  121. return {
  122. name: [
  123. 'name',
  124. {
  125. rules: [
  126. { required: true, message: `${this.$t('common.placeholder')}${this.$t('common.name')}` },
  127. { validator: this.$validate('resourceName') },
  128. ],
  129. },
  130. ],
  131. backend_type: [
  132. 'backend_type',
  133. {
  134. initialValue: this.params.lbBackendgroupData.provider === 'Cloudflare' ? 'ip_or_domain' : 'guest',
  135. rules: [
  136. { required: true, message: this.$t('network.text_343') },
  137. ],
  138. },
  139. ],
  140. guest_backend: [
  141. 'guest_backend',
  142. {
  143. rules: [
  144. { required: isRequired('guest'), message: this.$t('network.text_344') },
  145. ],
  146. },
  147. ],
  148. host_backend: [
  149. 'host_backend',
  150. {
  151. rules: [
  152. { required: isRequired('host'), message: this.$t('network.text_345') },
  153. ],
  154. },
  155. ],
  156. ip_backend: [
  157. 'ip_backend',
  158. {
  159. validateFirst: true,
  160. rules: [
  161. { required: isRequired('ip'), message: this.$t('network.text_346') },
  162. { validator: this.$validate('IPv4', false) },
  163. ],
  164. },
  165. ],
  166. ip_or_domain_backend: [
  167. 'ip_or_domain_backend',
  168. {
  169. rules: [
  170. {
  171. required: true,
  172. validator: (rule, value, callback) => {
  173. if (!value) {
  174. callback(new Error(this.$t('common.tips.input', [this.$t('network.ip_or_domain')])))
  175. }
  176. if (!regexp.isIPOrDomain(value)) {
  177. callback(new Error(this.$t('common.tips.input', [this.$t('network.ip_or_domain')])))
  178. }
  179. callback()
  180. },
  181. },
  182. ],
  183. },
  184. ],
  185. port: [
  186. 'port',
  187. {
  188. validateFirst: true,
  189. initialValue: 1,
  190. rules: [
  191. { required: true, message: this.$t('network.text_176') },
  192. { type: 'number', min: 1, max: 65535, message: this.$t('network.text_347') },
  193. ],
  194. },
  195. ],
  196. weight: [
  197. 'weight',
  198. {
  199. validateFirst: true,
  200. initialValue: 1,
  201. rules: [
  202. { required: true, message: this.$t('network.text_177') },
  203. { type: 'number', min: 0, max: this.params.maxWeight, message: this.$t('network.text_348', [this.params.maxWeight]) },
  204. ],
  205. },
  206. ],
  207. ssl: [
  208. 'ssl',
  209. {
  210. valuePropName: 'checked',
  211. },
  212. ],
  213. }
  214. },
  215. serverHref () {
  216. const { provider } = this.params.lbBackendgroupData
  217. const platform = findPlatform(provider, 'provider')
  218. const platformArr = ['idc', 'private', 'public']
  219. if (platformArr.includes(platform)) return `/vminstance/create?type=${platform}`
  220. return '/vminstance/create'
  221. },
  222. serverParams () {
  223. const params = {
  224. 'filter.0': 'status.equals(running,ready)',
  225. region: this.params.lbBackendgroupData.region_id,
  226. scope: this.$store.getters.scope,
  227. project: this.params.lbBackendgroupData.tenant_id,
  228. }
  229. if (this.params.lbData.vpc_id) {
  230. params.vpc = this.params.lbData.vpc_id
  231. }
  232. if (this.params.lbBackendgroupData.brand.toLowerCase() === 'openstack') {
  233. delete params.vpc
  234. } else if (this.isPublicAliyun) {
  235. // 网络是公网的阿里云LB实例,添加服务器时不应传参数vpc,但是如果已经有后端服务器数据,那么久取第一条的vpc
  236. delete params.vpc
  237. if (this.firstLbBackendVpc) {
  238. params.vpc = this.firstLbBackendVpc
  239. } else {
  240. params.manager_id = this.params.lbData.manager_id
  241. }
  242. }
  243. return params
  244. },
  245. hostParams () {
  246. const params = {
  247. baremetal: false,
  248. brand: 'OneCloud',
  249. 'filter.0': 'status.equals(running,ready)',
  250. }
  251. if (this.params.lbData.zone_id) {
  252. params.zone = this.params.lbData.zone_id
  253. }
  254. return params
  255. },
  256. isPublicAliyun () {
  257. return this.params.lbData.address_type === 'internet' && this.params.lbBackendgroupData.brand.toLowerCase() === 'aliyun'
  258. },
  259. },
  260. created () {
  261. if (this.isPublicAliyun) {
  262. this.fetchFirstdataVpc()
  263. }
  264. },
  265. methods: {
  266. handleBackendTypeChange (e) {
  267. this.form.fc.setFieldsValue({
  268. backend: undefined,
  269. }, () => {
  270. this.backend_type = e.target.value
  271. })
  272. },
  273. serverlistMapper (list) {
  274. return list.filter(v => {
  275. if (v.nics) { // is_exit=false 表示内网网卡,有一个为false既可做负载均衡服务器
  276. return v.nics.some(n => n.is_exit === false)
  277. }
  278. return true
  279. })
  280. },
  281. async doCreate (values) {
  282. const { backend_type } = values
  283. let data = {
  284. backend_group: this.params.lbBackendgroupData.id,
  285. ssl: values.ssl ? 'on' : 'off',
  286. backend: values[`${backend_type}_backend`],
  287. }
  288. if (this.isCloudflare) {
  289. data.generate_name = values.name
  290. data.address = values.ip_or_domain_backend
  291. data.backend_type = 'address'
  292. data.weight = values.weight
  293. data.port = values.port
  294. } else {
  295. data = { ...values, ...data }
  296. }
  297. await new this.$Manager('loadbalancerbackends').create({
  298. data,
  299. })
  300. },
  301. async handleConfirm () {
  302. this.loading = true
  303. try {
  304. const values = await this.form.fc.validateFields()
  305. await this.doCreate(values)
  306. this.loading = false
  307. this.cancelDialog()
  308. this.params.refresh()
  309. } catch (error) {
  310. this.loading = false
  311. }
  312. },
  313. async fetchFirstdataVpc () {
  314. try {
  315. const firstLbBackendList = Object.values(this.params.listData).filter(val => val.data.backend_type === 'guest')
  316. if (firstLbBackendList && firstLbBackendList.length) {
  317. const firstLbBackendData = firstLbBackendList[0]
  318. const firstId = firstLbBackendData.data.backend_id
  319. const { data } = await new this.$Manager('servers').get({ id: firstId })
  320. this.firstLbBackendVpc = data.vpc_id
  321. }
  322. } catch (error) {
  323. throw error
  324. }
  325. },
  326. },
  327. }
  328. </script>