| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- <template>
- <div>
- <page-header :title="$t('helm.text_25')" />
- <page-body needMarginBottom>
- <div>
- <template v-if="!chartDetail.name">
- <loading-block :layout="loadingLayout" />
- </template>
- <template v-else>
- <page-card-detail
- class="mt-3 mb-4"
- :img="chartDetail.chart.metadata.icon"
- :page-title="chartDetail.name"
- :description="chartDetail.chart.metadata.description">
- <div class="mt-1" style="font-size: 12px; color: #555; font-weight: 500;">{{ isVm ? $t('helm.text_26') : $t('helm.text_27') }}</div>
- </page-card-detail>
- <a-form
- v-bind="formItemLayout"
- :form="form.fc">
- <a-form-item :label="$t('helm.text_16')">
- <a-input v-decorator="decorators.release_name" :placeholder="$t('helm.text_28')" />
- </a-form-item>
- <a-form-item :label="$t('helm.text_29')">
- <a-select v-decorator="decorators.version" :placeholder="$t('helm.text_30')">
- <a-select-option
- v-for="item in versions"
- :key="item.key"
- :value="item.key">
- {{ item.label }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <template v-if="isVm">
- <a-form-item :label="$t('scope.text_573', [$t('dictionary.project')])">
- <domain-project :fc="form.fc" :decorators="{ project: decorators.project, domain: decorators.domain }" />
- </a-form-item>
- </template>
- <template v-else>
- <a-form-item :label="$t('helm.text_31')">
- <cluster-select v-decorator="decorators.cluster" @input="setCluster" />
- </a-form-item>
- <a-form-item :label="$t('helm.text_32')">
- <namespace-select v-decorator="decorators.namespace" @input="setNamespace" :cluster="cluster" :namespaceObj.sync="namespaceObj" />
- </a-form-item>
- </template>
- <a-collapse v-model="activeKey">
- <a-collapse-panel :header="$t('helm.text_46')" key="jsonschema">
- <json-schema-form v-if="isJsonSchema" :schema="schema" :extendFd="form.fd" :definition="definition" :hide-reset="false" :influxdbUrl="influxdbUrl" ref="formRef" />
- <form-yaml
- v-else
- :decorators="decorators"
- :activeTab.sync="formActiveTab"
- :localData="chartDetail.chart.values"
- :valueSearch="valueSearch" />
- </a-collapse-panel>
- <a-collapse-panel v-if="chartDetail.yaml !== ''" :header="$t('helm.text_33')" key="desc">
- <div v-html="compiledMarkdown" />
- </a-collapse-panel>
- <a-collapse-panel :header="$t('helm.text_34')" key="yaml" v-if="false">
- <template-preview :previewFiles="previewFiles" />
- </a-collapse-panel>
- </a-collapse>
- </a-form>
- </template>
- </div>
- </page-body>
- <page-footer>
- <div slot="right">
- <a-button class="mr-3" type="primary" @click="confirm" :loading="loading">{{$t('helm.text_35')}}</a-button>
- <a-button @click="cancel">{{$t('helm.text_36')}}</a-button>
- </div>
- </page-footer>
- </div>
- </template>
- <script>
- import _ from 'lodash'
- import * as R from 'ramda'
- import marked from 'marked'
- import { Base64 } from 'js-base64'
- import { mapGetters } from 'vuex'
- import ClusterSelect from '@K8S/sections/ClusterSelect'
- import NamespaceSelect from '@K8S/sections/NamespaceSelect'
- import TemplatePreview from '@K8S/sections/TemplatePreview'
- import k8sCreateMixin from '@K8S/mixins/create'
- import FormYaml from '@Helm/views/chart/create/FormYaml'
- import DomainProject from '@/sections/DomainProject'
- import { validateYaml, isRequired } from '@/utils/validate'
- import { HYPERVISORS_MAP } from '@/constants'
- import { compactObj } from '@/utils/utils'
- export default {
- name: 'K8SChartCreate',
- components: {
- ClusterSelect,
- NamespaceSelect,
- TemplatePreview,
- DomainProject,
- FormYaml,
- },
- mixins: [k8sCreateMixin],
- data () {
- const validator = (rule, value, _callback) => {
- validateYaml(value)
- .then(() => {
- return _callback()
- })
- .catch(() => {
- return _callback(this.$t('helm.text_37'))
- })
- }
- return {
- activeKey: ['jsonschema', 'desc', 'yaml'],
- formActiveTab: 'form',
- isJsonSchema: false,
- influxdbUrl: '',
- versions: [],
- previewFiles: [],
- loading: false,
- chartDetail: {
- readme: '',
- chart: {},
- },
- namespaceObj: {},
- formItemLayout: {
- labelCol: { span: 4 },
- wrapperCol: { span: 20 },
- },
- isVm: this.$route.query.type === 'internal',
- loadingLayout: [
- [10],
- [8, 9],
- [2, 4, 7, 5],
- [13, 9],
- [4, 3, 8],
- [8, 6, 8],
- [13, 9],
- ],
- form: {
- fc: this.$form.createForm(this, {
- onValuesChange: (props, values) => {
- Object.keys(values).forEach((key) => {
- this.$set(this.form.fd, key, values[key])
- })
- },
- }),
- fd: {},
- },
- schema: {},
- decorators: {
- release_name: [
- 'release_name',
- {
- validateFirst: true,
- rules: [
- { required: true, message: this.$t('helm.text_28') },
- { min: 2, max: 24, message: this.$t('helm.text_38'), trigger: 'blur' },
- { validator: this.$validate('k8sName') },
- ],
- },
- ],
- version: [
- 'version',
- {
- rules: [
- { required: true, message: this.$t('helm.text_30'), trigger: 'blur' },
- ],
- },
- ],
- domain: [
- 'domain',
- {
- rules: [
- { validator: isRequired(), message: this.$t('rules.domain'), trigger: 'change' },
- ],
- },
- ],
- project: [
- 'project',
- {
- rules: [
- { validator: isRequired(), message: this.$t('rules.project'), trigger: 'change' },
- ],
- },
- ],
- cluster: [
- 'cluster',
- {
- initialValue: this.$store.state.common.k8s.cluster,
- rules: [
- { required: true, message: this.$t('helm.text_39'), trigger: 'blur' },
- ],
- },
- ],
- namespace: [
- 'namespace',
- {
- initialValue: this.$store.state.common.k8s.namespace,
- rules: [
- { required: true, message: this.$t('helm.text_40'), trigger: 'blur' },
- ],
- },
- ],
- config: {
- key: i => [
- `keys[${i}]`,
- {
- rules: [
- { required: true, message: this.$t('helm.text_41') },
- ],
- },
- ],
- value: i => [
- `values[${i}]`,
- {
- rules: [
- { required: true, message: this.$t('helm.text_42') },
- ],
- },
- ],
- },
- yaml: [
- 'yaml',
- {
- validateFirst: true,
- rules: [
- { required: true, message: this.$t('helm.text_43') },
- { validator },
- ],
- },
- ],
- },
- definition: [
- // 'hypervisor',
- // 'preferRegion',
- // 'preferZone',
- // 'network',
- // 'virtualMachines',
- // 'virtualMachines.masterNode',
- // 'virtualMachines.slaveNode',
- // 'virtualMachines.masterNode.instanceType',
- // 'virtualMachines.masterNode.diskSizeGB',
- // 'virtualMachines.masterNode.storageBackend',
- // 'virtualMachines.masterNode.ansiblePlaybook',
- // 'virtualMachines.masterNode.ansiblePlaybook.jenkins',
- // 'virtualMachines.masterNode.ansiblePlaybook.telegraf',
- // 'virtualMachines.masterNode.ansiblePlaybook.jenkins.adminUsername',
- // 'virtualMachines.masterNode.ansiblePlaybook.jenkins.adminPassword',
- // 'virtualMachines.masterNode.ansiblePlaybook.jenkins.httpPort',
- // 'virtualMachines.masterNode.ansiblePlaybook.telegraf.influxdbName',
- // 'virtualMachines.masterNode.ansiblePlaybook.telegraf.influxdbUrl',
- // 'virtualMachines.slaveNode.count',
- // 'virtualMachines.slaveNode.instanceType',
- // 'virtualMachines.slaveNode.diskSizeGB',
- // 'virtualMachines.slaveNode.storageBackend',
- ],
- }
- },
- computed: {
- compiledMarkdown () {
- if (!this.chartDetail.readme) return this.$t('helm.text_47')
- const markdownDoc = Base64.decode(this.chartDetail.readme)
- return marked(markdownDoc, { sanitize: true })
- },
- ...mapGetters(['isAdminMode', 'isProjectMode', 'scope', 'isDomainMode', 'userInfo', 'l3PermissionEnable']),
- },
- watch: {
- 'form.fd.domain.key' () {
- this.getCapability()
- },
- },
- created () {
- this.chartsM = new this.$Manager('charts', 'v1')
- this.releaseM = new this.$Manager('releases', 'v1')
- this.endpointM = new this.$Manager('endpoints', 'v1')
- this.fetchChartData()
- },
- methods: {
- async getCapability () {
- if (!this.definition || !this.definition.length) return
- const params = { project_domain: _.get(this.form.fd, 'domain.key') }
- try {
- const { data: { data } } = await new this.$Manager('capabilities', 'v2').list({ params })
- if (data && data.length) {
- const index = this.definition.findIndex(val => {
- if (R.is(Object, val)) {
- if (R.is(Array, val.key)) {
- return val.key[0] === 'hypervisor'
- }
- return val.key === 'hypervisor'
- }
- return val === 'hypervisor'
- })
- const { hypervisors = [] } = data[0]
- const hyperItem = this.definition[index]
- const hyperObj = R.is(Object, hyperItem) ? hyperItem : { key: hyperItem }
- const hypervisorOpts = hypervisors.filter(v => v !== 'baremetal').map(v => ({ value: v, label: (_.get(HYPERVISORS_MAP, `${v}.label`) || v) }))
- this.definition.splice(index, 1, {
- ...hyperObj,
- type: 'a-select',
- options: hypervisorOpts,
- })
- this.$refs.formRef.form.fc.setFieldsValue({
- hypervisor: hypervisorOpts[0] ? hypervisorOpts[0].value : undefined,
- })
- }
- } catch (error) {
- throw error
- }
- },
- getDefinition (jsonshcema = this.schema) {
- this.definition = Object.keys(jsonshcema.properties).filter(val => val !== 'project')
- this.getCapability()
- },
- valueSearch (query, path) {
- const values = this.chartDetail.chart.values
- const value = _.get(values, path)
- if (value && (R.is(String, value) || R.is(Number, value))) {
- const opts = []
- if (!query || (value === query || (query && value.toLowerCase().includes(query.toLowerCase())))) opts.push(value)
- return opts
- }
- return []
- },
- async validateForm () {
- try {
- const values = await this.$refs.formRef.handleSubmit()
- const validData = compactObj(values) // 去除 属性值是 undefined,''和null的
- return validData
- } catch (error) {
- throw error
- }
- },
- async getChart (version) {
- const { repo, name } = this.$route.query
- const { data } = await this.chartsM.get({
- id: name,
- params: {
- version: version,
- repo: repo,
- },
- })
- // const ret = await this.endpointM.list({
- // params: {
- // service: 'influxdb',
- // interface: 'public',
- // },
- // })
- // const ends = ret.data.data || []
- // if (ends.length) {
- // this.influxdbUrl = ends[0].url
- // }
- if (data) {
- this.chartDetail = data
- this.previewFiles = data.files
- if (this.activeKey.indexOf('yaml')) {
- this.activeKey.push('yaml')
- }
- const jsonSchemaItem = data.files.find(val => val.name.endsWith('values.schema.json'))
- const clearInflushdbInfo = (schema) => {
- const telegraf = schema?.properties?.virtualMachines?.properties?.masterNode?.properties?.ansiblePlaybook?.properties?.telegraf
- if (telegraf) {
- const influxdb = telegraf?.properties
- if (influxdb) {
- influxdb.influxdbName.default = ''
- influxdb.influxdbUrl.default = ''
- }
- }
- return schema
- }
- if (R.is(Object, jsonSchemaItem)) {
- let schema = Base64.decode(jsonSchemaItem.data)
- if (R.is(String, schema)) {
- schema = JSON.parse(schema)
- }
- this.appendImageToVm(schema)
- delete schema.properties.envs
- this.schema = clearInflushdbInfo(schema)
- this.getDefinition()
- this.isJsonSchema = true
- }
- }
- },
- appendImageToVm (schema) {
- if (schema.properties && schema.properties.virtualMachines && schema.properties.virtualMachines.properties) {
- // 多节点
- for (const key in schema.properties.virtualMachines.properties) {
- this.appendImageToNode(schema.properties.virtualMachines.properties[key], key)
- }
- } else if (schema.properties.virtualMachine) {
- // 单节点
- this.appendImageToNode(schema.properties.virtualMachine, '')
- }
- },
- appendImageToNode (node, nodeName) {
- if (node.required && node.required.includes('image') && node.properties && !node.properties.image) {
- node.properties.image = {
- title: '镜像',
- type: 'string',
- componentType: 'ImageList',
- description: nodeName === 'slaveNode' ? '' : '请选择镜像',
- }
- const temp = { ...node.properties }
- node.properties = {}
- node.required.map(key => {
- node.properties[key] = temp[key]
- delete temp[key]
- })
- node.properties = { ...node.properties, ...temp }
- }
- },
- async fetchChartData () {
- const version = await this.getChartVersion()
- this.getChart(version)
- },
- async getChartVersion () {
- this.versionLoading = true
- const { repo, name } = this.$route.query
- const { data: { data = [] } } = await this.chartsM.list({
- params: {
- repo,
- name,
- all_version: true,
- },
- })
- if (data.length === 0) {
- this.$message.error(this.$t('helm.text_44'))
- return
- }
- this.versions = data.map(v => {
- return {
- label: `${v.repo} - ${v.version}`,
- key: `${v.repo} - ${v.version}`,
- }
- })
- this.form.fc.getFieldDecorator(this.decorators.version[0], this.decorators.version[1])
- this.form.fc.setFieldsValue({
- [this.decorators.version[0]]: this.versions[0].key,
- })
- return data[0].version
- },
- async doCreate (values, valuesJson) {
- const data = {
- chart_name: `${this.chartDetail.repo}/${this.chartDetail.name}`,
- release_name: values.release_name,
- }
- if (this.isVm) {
- if (this.isAdminMode) {
- data.project = values.project.key
- if (this.l3PermissionEnable) {
- data.domain = values.domain.key
- }
- }
- if (this.isDomainMode) {
- data.project = values.project.key
- data.domain = this.userInfo.projectDomainId
- }
- if (this.isProjectMode) {
- data.domain = this.userInfo.projectDomainId
- data.project = this.userInfo.projectId
- }
- } else {
- data.cluster = values.cluster
- data.namespace = values.namespace
- }
- if (!R.isNil(values.version) && !R.isEmpty(values.version)) {
- data.version = values.version.split(' - ')[1]
- }
- if (valuesJson) {
- data.values_json = valuesJson
- data.values_json.project = data.project
- data.values_json.envs = {
- project_id: data.project,
- domain_id: data.domain || 'default', // 兼容没开启三级权限情况
- }
- } else {
- const sets = {}
- if (this.formActiveTab === 'form') {
- R.forEachObjIndexed((value, key) => {
- sets[value] = values.values[key]
- }, values.keys)
- data.sets = sets
- } else {
- data.values = values.yaml
- }
- }
- await this.releaseM.create({ data })
- },
- async confirm () {
- this.loading = true
- const jobs = [this.form.fc.validateFields()]
- if (this.isJsonSchema) {
- jobs.push(this.validateForm())
- }
- try {
- const [values, valuesJson] = await Promise.all(jobs)
- await this.doCreate(values, valuesJson)
- this.$message.success(this.$t('helm.text_45'))
- this.loading = false
- this.cancel(true)
- } catch (error) {
- this.loading = false
- throw error
- }
- },
- cancel (isSuccess) {
- if (isSuccess) {
- if (this.isVm) {
- this.$router.push('/vm-release')
- } else {
- this.$router.push('/k8s-release')
- }
- } else {
- this.$router.push('/k8s-chart')
- }
- },
- },
- }
- </script>
|