index.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <template>
  2. <div>
  3. <page-header :title="$t('k8s.text_307')" />
  4. <a-form
  5. class="mt-3"
  6. :form="form.fc">
  7. <a-form-item
  8. :label="$t('k8s.text_348')"
  9. v-bind="formItemLayout">
  10. <a-radio-group v-decorator="decorators.storageType">
  11. <a-radio-button value="cephCSI">
  12. Ceph RBD
  13. </a-radio-button>
  14. </a-radio-group>
  15. </a-form-item>
  16. <a-form-item
  17. :label="$t('k8s.text_41')"
  18. v-bind="formItemLayout">
  19. <a-input v-decorator="decorators.name" :placeholder="$t('k8s.text_60')" />
  20. </a-form-item>
  21. <a-form-item
  22. :label="$t('k8s.text_19')"
  23. v-bind="formItemLayout">
  24. <cluster-select
  25. v-decorator="decorators.cluster"
  26. @input="setCluster"
  27. style="width: 140px;" />
  28. </a-form-item>
  29. <a-form-item
  30. :label="$t('k8s.text_18')"
  31. class="mb-0"
  32. required
  33. v-bind="formItemLayout">
  34. <a-row :gutter="8">
  35. <a-col :span="12">
  36. <a-form-item>
  37. <namespace-select
  38. size="small"
  39. v-decorator="decorators.secretNamespace"
  40. :cluster="cluster"
  41. @change="secretNamespaceChange" />
  42. </a-form-item>
  43. </a-col>
  44. <a-col :span="12">
  45. <a-form-item>
  46. <base-select
  47. resource="secrets"
  48. v-decorator="decorators.secretName"
  49. :params="secretsParams"
  50. version="v1"
  51. :need-params="true"
  52. filterable
  53. showSync
  54. :placeholder="$t('k8s.text_349')" />
  55. <div slot="extra">{{$t('k8s.text_306')}} <help-link class="pl-1" slot="extra" :href="`/k8s-secret/create?storageType=${form.fc.getFieldValue('storageType')}`">{{$t('k8s.text_350')}}</help-link></div>
  56. </a-form-item>
  57. </a-col>
  58. </a-row>
  59. </a-form-item>
  60. <a-form-item
  61. :label="$t('k8s.text_351')"
  62. v-bind="formItemLayout">
  63. <a-select v-decorator="decorators.clusterId" :placeholder="$t('k8s.text_77')">
  64. <a-select-option v-for="item in cephcsiOpts" :value="item.clusterId" :key="item.clusterId">{{item.clusterId}}</a-select-option>
  65. </a-select>
  66. </a-form-item>
  67. <a-form-item
  68. label="Pool"
  69. v-bind="formItemLayout">
  70. <a-select v-decorator="decorators.pool" :placeholder="$t('k8s.text_352')">
  71. <a-select-option v-for="item in poolOpts" :value="item" :key="item">{{item}}</a-select-option>
  72. </a-select>
  73. </a-form-item>
  74. <a-form-item
  75. :label="$t('k8s.text_353')"
  76. v-bind="formItemLayout">
  77. <a-select v-decorator="decorators.csiFsType">
  78. <a-select-option value="ext4">ext4</a-select-option>
  79. <a-select-option value="xfs">xfs</a-select-option>
  80. </a-select>
  81. </a-form-item>
  82. <a-form-item :wrapper-col="{ span: 20, offset: 3 }">
  83. <a-button class="mr-2" type="primary" @click="handleConfirm" :loading="loading">{{$t('common.create')}}</a-button>
  84. <a-button @click="cancel">{{$t('k8s.text_162')}}</a-button>
  85. </a-form-item>
  86. </a-form>
  87. <base-dialog v-if="showCreateCephCSI" @cancel="() => showCreateCephCSI = false">
  88. <div slot="header">{{$t('k8s.text_354')}}</div>
  89. <div slot="body">{{$t('k8s.text_355')}}</div>
  90. <div slot="footer">
  91. <a-button type="primary" @click="createCephCSI">{{$t('common.create')}}</a-button>
  92. </div>
  93. </base-dialog>
  94. </div>
  95. </template>
  96. <script>
  97. import { mapGetters } from 'vuex'
  98. import _ from 'lodash'
  99. import ClusterSelect from '@K8S/sections/ClusterSelect'
  100. import NamespaceSelect from '@K8S/sections/NamespaceSelect'
  101. import k8sCreateMixin from '@K8S/mixins/create'
  102. export default {
  103. name: 'StorageClassCreate',
  104. components: {
  105. ClusterSelect,
  106. NamespaceSelect,
  107. },
  108. mixins: [k8sCreateMixin],
  109. data () {
  110. const initCluster = _.get(this.$route, 'query.cluster') || this.$store.state.common.k8s.cluster
  111. return {
  112. loading: false,
  113. form: {
  114. fc: this.$form.createForm(this, {
  115. onValuesChange: (props, values) => {
  116. if (values.cluster) {
  117. this.form.fd.cluster = values.cluster
  118. }
  119. this.$nextTick(() => {
  120. this.fetchPoolOpts()
  121. })
  122. },
  123. }),
  124. fd: {
  125. cluster: initCluster,
  126. },
  127. },
  128. decorators: {
  129. storageType: [
  130. 'storageType',
  131. {
  132. initialValue: 'cephCSI',
  133. },
  134. ],
  135. name: [
  136. 'name',
  137. {
  138. validateTrigger: 'blur',
  139. rules: [
  140. { required: true, message: this.$t('k8s.text_60') },
  141. ],
  142. },
  143. ],
  144. cluster: [
  145. 'cluster',
  146. {
  147. initialValue: initCluster,
  148. rules: [
  149. { required: true, message: this.$t('k8s.text_30') },
  150. ],
  151. },
  152. ],
  153. secretNamespace: [
  154. 'secretNamespace',
  155. {
  156. rules: [
  157. { required: true, message: this.$t('k8s.text_61') },
  158. ],
  159. },
  160. ],
  161. secretName: [
  162. 'secretName',
  163. {
  164. rules: [
  165. { required: true, message: this.$t('k8s.text_349') },
  166. ],
  167. },
  168. ],
  169. clusterId: [
  170. 'clusterId',
  171. {
  172. rules: [
  173. { required: true, message: this.$t('k8s.text_356') },
  174. ],
  175. },
  176. ],
  177. pool: [
  178. 'pool',
  179. {
  180. rules: [
  181. { required: true, message: this.$t('k8s.text_357') },
  182. ],
  183. },
  184. ],
  185. csiFsType: [
  186. 'csiFsType',
  187. {
  188. initialValue: 'ext4',
  189. },
  190. ],
  191. },
  192. formItemLayout: {
  193. wrapperCol: { span: 20 },
  194. labelCol: { span: 3 },
  195. },
  196. secretNamespace: '',
  197. cephcsiOpts: [],
  198. poolOpts: [],
  199. showCreateCephCSI: false,
  200. }
  201. },
  202. computed: {
  203. ...mapGetters(['userInfo', 'scope', 'isAdminMode']),
  204. secretsParams () {
  205. if (this.secretNamespace && this.cluster) {
  206. return {
  207. type: 'yunion.io/ceph-csi',
  208. namespace: this.secretNamespace,
  209. cluster: this.cluster,
  210. limit: 0,
  211. }
  212. }
  213. return {}
  214. },
  215. },
  216. watch: {
  217. 'form.fd.cluster': {
  218. handler (val) {
  219. if (val) {
  220. this.fetchCephcsiOpts(val)
  221. this.fetchClusterStatus(val)
  222. }
  223. },
  224. immediate: true,
  225. },
  226. },
  227. methods: {
  228. async fetchClusterStatus (cluster) {
  229. const { data } = await new this.$Manager('kubeclusters', 'v1').get({
  230. id: `${cluster}/components-status`,
  231. })
  232. if (data && data.cephCSI && data.cephCSI.created === false) this.showCreateCephCSI = true
  233. },
  234. createCephCSI () {
  235. this.$router.push({
  236. path: '/k8s-kubecomponent/create',
  237. query: {
  238. kubeComponent: 'cephCSI',
  239. cluster: this.cluster,
  240. },
  241. })
  242. },
  243. async fetchPoolOpts () {
  244. const { clusterId, secretName, secretNamespace, cluster } = this.form.fc.getFieldsValue(['clusterId', 'secretName', 'secretNamespace', 'cluster'])
  245. if (clusterId && secretName && secretNamespace && cluster) {
  246. const params = {
  247. cephCSIRBD: {
  248. clusterId,
  249. secretName,
  250. secretNamespace,
  251. },
  252. cluster,
  253. name: 'rbd-climc',
  254. provisioner: 'rbd.csi.ceph.com',
  255. }
  256. const { data } = await new this.$Manager('storageclasses', 'v1').performClassAction({
  257. action: 'connection-test',
  258. data: params,
  259. })
  260. if (data && data.cephCSIRBD && data.cephCSIRBD.pools) {
  261. this.poolOpts = data.cephCSIRBD.pools
  262. this.form.fc.getFieldDecorator('pool', {
  263. preserve: true,
  264. initialValue: data.cephCSIRBD.pools[0],
  265. })
  266. }
  267. }
  268. },
  269. async fetchCephcsiOpts (cluster) {
  270. const { data } = await new this.$Manager('kubeclusters', 'v1').get({
  271. id: `${cluster}/component-setting`,
  272. params: { type: 'cephCSI' },
  273. })
  274. if (data && data.cephCSI && data.cephCSI.config) {
  275. this.cephcsiOpts = data.cephCSI.config
  276. if (this.cephcsiOpts.length) {
  277. this.form.fc.getFieldDecorator('clusterId', {
  278. preserve: true,
  279. initialValue: this.cephcsiOpts[0].clusterId,
  280. })
  281. }
  282. }
  283. },
  284. secretNamespaceChange (e) {
  285. this.secretNamespace = e
  286. },
  287. toCreateCluster () {
  288. this.$router.push('/k8s-cluster/create')
  289. window.open(`${this.$router.resolve('/k8s-cluster/create').href}`)
  290. },
  291. doCreate (values) {
  292. const data = {
  293. cephCSIRBD: {
  294. clusterId: values.clusterId,
  295. csiFsType: values.csiFsType,
  296. imageFeatures: 'layering',
  297. pool: values.pool,
  298. secretName: values.secretName,
  299. secretNamespace: values.secretNamespace,
  300. },
  301. cluster: values.cluster,
  302. name: values.name,
  303. provisioner: 'rbd.csi.ceph.com',
  304. }
  305. return new this.$Manager('storageclasses', 'v1').create({ data })
  306. },
  307. async handleConfirm () {
  308. this.loading = true
  309. try {
  310. const values = await this.form.fc.validateFields()
  311. await this.doCreate(values)
  312. this.loading = false
  313. this.$message.success(this.$t('k8s.text_184'))
  314. this.$router.push('/k8s-storageclass')
  315. } catch (error) {
  316. this.loading = false
  317. throw error
  318. }
  319. },
  320. cancel () {
  321. this.$router.push('/k8s-storageclass')
  322. },
  323. },
  324. }
  325. </script>