ui/lib/logging/addon/components/logging/new-edit/component.js

552 lines
15 KiB
JavaScript

import Component from '@ember/component';
import { inject as service } from '@ember/service';
import {
get, set, observer, setProperties, computed
} from '@ember/object';
import { reads } from '@ember/object/computed';
import NewOrEdit from 'ui/mixins/new-or-edit';
import parseUri from 'shared/utils/parse-uri';
import { resolve } from 'rsvp';
import { next, later } from '@ember/runloop';
import C from 'ui/utils/constants';
const INVALID_PREFIX_CHAR = ['\\', '/', '*', '?', '"', '<', '>', '|', ` `, ',', '#'];
export default Component.extend(NewOrEdit, {
scope: service(),
globalStore: service(),
intl: service(),
// input
errors: null,
targetType: null,
configMap: null,
esEndpointValidate: true,
fluentdEndpointValidate: true,
esErrors: [],
pasteOrUpload: false,
testing: false,
testOk: true,
tested: false,
pageScope: reads('scope.currentPageScope'),
cluster: reads('scope.currentCluster'),
project: reads('scope.currentProject'),
clusterTargetType: reads('clusterLogging.targetType'),
originalModelTargetType: reads('originalModel.targetType'),
init() {
this._super(...arguments)
this.initCustomContent()
},
actions: {
test() {
if (get(this, 'testing') || get(this, 'tested')) {
return resolve();
}
const clone = get(this, 'model').clone()
const ok = this.willSave();
if (!ok) {
return resolve();
}
const data = get(this, 'model');
const gs = get(this, 'globalStore');
const pageScope = this.get('pageScope');
set(this, 'testing', true);
let url = `${ pageScope }loggings?action=test`
if (get(this, 'targetType') === 'customTarget') {
url = `${ pageScope }loggings?action=dryRun`
}
return gs.rawRequest({
url,
method: 'POST',
data,
}).then(() => {
setProperties(this, {
testOk: true,
errors: null,
});
}).catch((xhr) => {
setProperties(this, {
testOk: false,
errors: [xhr.body.message || xhr.body.code],
});
}).finally(() => {
setProperties(this, {
tested: true,
testing: false,
model: clone,
})
next(() => {
later(() => {
set(this, 'tested', false);
}, 3000);
});
});
},
cancel() {
setProperties(this, {
targetType: get(this, 'preTargetType'),
pasteOrUpload: false,
})
},
showPaste() {
setProperties(this, {
preTargetType: get(this, 'targetType'),
targetType: 'customTarget',
pasteOrUpload: true,
})
},
},
targetTypeChange: observer('targetType', function() {
set(this, 'errors', [])
}),
pasteOrUploadChange: observer('pasteOrUpload', function() {
const { fileObj, deepStrs = [] } = get(this, 'parseValue')
const preTargetType = get(this, 'preTargetType')
if (!get(this, 'pasteOrUpload')) {
const type = fileObj['@type']
let targetType = type
switch (type) {
case 'splunk_hec':
targetType = 'splunk'
break;
case 'remote_syslog':
targetType = 'syslog'
break;
case 'kafka_buffered':
targetType = 'kafka'
break;
case 'forward':
targetType = 'fluentForwarder'
break;
}
set(this, 'targetType', targetType)
} else {
let type = preTargetType
switch (preTargetType) {
case 'splunk':
type = 'splunk_hec'
break;
case 'syslog':
type = 'remote_syslog'
break;
case 'kafka':
type = 'kafka_buffered'
break;
case 'fluentForwarder':
type = 'forward'
break;
}
set(fileObj, '@type', type)
let body = ''
let str = ''
deepStrs.map((s) => {
str += s
})
for (let key in fileObj) {
body += `${ key } ${ fileObj[key] }
`
}
const out = `<match *>
${ body }${ str }
</match>`
set(this, 'customContent', out)
}
}),
headerLabel: computed('pageScope', function() {
const ps = get(this, 'pageScope');
if (ps === 'cluster') {
return 'loggingPage.clusterHeader';
} else {
return 'loggingPage.projectHeader';
}
}),
isClusterLevel: computed('pageScope', function() {
return get(this, 'pageScope') === 'cluster';
}),
saveDisabled: computed('originalModel.{id,targetType}', 'targetType', 'pasteOrUpload', function() {
return get(this, 'originalModel.targetType') === 'none'
&& get(this, 'targetType') === 'none'
&& !get(this, 'pasteOrUpload');
}),
parseValue: computed('customContent', function() {
let fileObj = {}
const removeMacth = get(this, 'customContent').replace(/.*<match.*>.*(\r\n|\n|\r) {2}/ig, '').replace(/(\r\n|\n|\r).*<\/match.*>/ig, '')
const deepStrs = removeMacth.match(/<(.|\r\n|\n|\r)*<\/.*>/ig, '') || []
const removedDeep = removeMacth.replace(/<(.|\r\n|\n|\r)*<\/.*>/ig, '')
const myString = removedDeep.replace(/(\r\n|\n|\r)/gm, '<br />');
const keyAndValue = myString.split('<br />').filter((f) => f !== '<br />').filter((f = '') => !f.startsWith('#') && !f.startsWith('<'))
keyAndValue.map((item = '') => {
const arr = item.split(' ').filter((f) => f !== '')
if (arr[0] && arr[1]) {
set(fileObj, arr[0], arr[1])
}
})
return {
fileObj,
deepStrs
}
}),
willSave() {
const {
targetType, pageScope, model, intl
} = this
set(model, 'clusterId', get(this, 'cluster.id'));
if (pageScope === 'project') {
set(model, 'projectId', get(this, 'project.id'));
}
setProperties(model, {
elasticsearchConfig: null,
splunkConfig: null,
kafkaConfig: null,
syslogConfig: null,
fluentForwarderConfig: null,
customTargetConfig: null,
});
if (targetType === 'none') {
return true;
}
const errors = set(this, 'errors', [])
if (get(this, 'pasteOrUpload')) {
const { fileObj } = get(this, 'parseValue')
const targetType = fileObj['@type']
const types = Object.keys(C.LOGGING_TPYE_TO_CONFIG) || []
if (!types.includes(targetType)) {
errors.pushObject(intl.t('loggingPage.customTarget.type.error'))
}
setProperties(model, {
customTargetConfig: {
clientKey: get(this, 'model.customTarget.config.clientKey'),
clientCert: get(this, 'model.customTarget.config.clientCert'),
certificate: get(this, 'model.customTarget.config.certificate'),
content: (get(this, 'customContent') || '').replace(/.*<match.*>.*(\r\n|\n|\r) {2}/ig, '').replace(/(\r\n|\n|\r).*<\/match.*>/ig, ''),
}
})
const {
outputFlushInterval, outputTags, dockerRoot, includeSystemComponent
} = get(this, 'model.customTarget');
setProperties(model, {
outputFlushInterval,
outputTags,
dockerRoot,
includeSystemComponent,
})
} else {
if (targetType === 'fluentForwarder') {
const fluentServers = get(model, 'fluentForwarder.config.fluentServers') || [];
let filter = fluentServers.filter((f) => !f.endpoint)
if (filter.length > 0) {
errors.pushObject(intl.t('loggingPage.fluentd.endpoint.required'))
} else {
if (!get(this, 'endpointValidate')) {
errors.pushObject(intl.t('loggingPage.fluentd.endpoint.invalid'))
}
}
filter = fluentServers.filter((f) => !f.standby)
if (filter.length === 0) {
errors.pushObject(intl.t('loggingPage.fluentd.standby.none'))
}
if (errors.length === 0) {
const enableTls = get(model, 'fluentForwarder.config.enableTls')
if (!enableTls) {
set(model, 'fluentForwarder.config.certificate', null)
}
}
}
let formatConfig = get(model, `${ targetType }.config`)
setProperties(model, {
outputFlushInterval: get(model, `${ targetType }.outputFlushInterval`),
outputTags: get(model, `${ targetType }.outputTags`),
dockerRoot: get(model, `${ targetType }.dockerRoot`),
[`${ targetType }Config`]: formatConfig,
includeSystemComponent: get(model, `${ targetType }.includeSystemComponent`),
})
if (targetType === 'elasticsearch') {
const elasticsearchErrors = this.elasticsearchWillSave()
errors.pushObjects(elasticsearchErrors)
}
if (targetType === 'splunk') {
const splunkErrors = this.splunkWillSave()
errors.pushObjects(splunkErrors)
}
if (targetType === 'kafka') {
const kafkaErrors = this.kafkaWillSave()
errors.pushObjects(kafkaErrors)
}
if (targetType === 'syslog') {
const syslogErrors = this.syslogWillSave()
errors.pushObjects(syslogErrors)
}
}
if (errors.length > 0) {
return false
}
return this._super(...arguments);
},
formatUrl(url) {
const urlParser = parseUri(url) || {}
if (!urlParser.port) {
if (urlParser.protocol === 'http') {
return `${ urlParser.protocol }://${ urlParser.host }:80`
}
if (urlParser.protocol === 'https') {
return `${ urlParser.protocol }://${ urlParser.host }:443`
}
}
return url
},
doneSaving() {
if (get(this, 'targetType') !== 'customTarget') {
set(this, 'customContent', `<match *>\n</match>`)
}
this.sendAction('refreshModel');
},
initCustomContent() {
if (get(this, 'originalModelTargetType') === 'customTarget') {
setProperties(this, {
pasteOrUpload: true,
customContent: `<match *>\n ${ get(this, 'model.customTargetConfig.content') }\n</match>`,
})
} else {
set(this, 'customContent', get(this, 'model.customTarget.config.content'))
}
},
kafkaWillSave() {
const { model, intl } = this
const errors = []
let kt;
const brokerEndpoints = get(model, 'kafka.config.brokerEndpoints');
const zookeeperEndpoint = get(model, 'kafka.config.zookeeperEndpoint');
const kafkaConfig = get(model, 'kafkaConfig') || {}
if (brokerEndpoints && brokerEndpoints.length > 0) {
kt = 'broker';
} else if (zookeeperEndpoint) {
kt = 'zookeeper';
} else {
errors.pushObject(intl.t('loggingPage.kafka.endpoint.required'))
}
if (kt === 'broker') {
if (get(kafkaConfig, 'saslUsername') && get(kafkaConfig, 'saslPassword')) {
if ( get(kafkaConfig, 'saslType') === 'plain' ) {
set(kafkaConfig, 'saslScramMechanism', null)
}
} else {
setProperties(kafkaConfig, {
saslType: null,
saslScramMechanism: null,
})
}
setProperties(kafkaConfig, {
zookeeperEndpoint: null,
brokerEndpoints,
});
} else if (kt === 'zookeeper') {
setProperties(kafkaConfig, {
zookeeperEndpoint,
brokerEndpoints: null,
saslScramMechanism: null,
saslPassword: null,
saslType: null,
saslUsername: null,
clientKey: null,
clientCert: null,
certificate: null,
});
}
if (!get(kafkaConfig, 'topic')) {
errors.pushObject(intl.t('loggingPage.kafka.topic.required'))
}
return errors
},
syslogWillSave() {
const { model = {}, intl } = this
const errors = []
const config = get(model, 'syslog.config') || {}
const {
endpoint, protocol, enableTls, sslVerify
} = config
const syslogConfig = get(model, 'syslogConfig') || {}
if (!endpoint) {
errors.pushObject(intl.t('loggingPage.syslog.endpoint.required'))
}
if (protocol === 'udp') {
setProperties(syslogConfig, {
certificate: null,
clientKey: null,
clientCert: null,
sslVerify: null,
enableTls: null,
})
}
if (protocol === 'tcp') {
if (!enableTls) {
setProperties(syslogConfig, {
certificate: null,
clientKey: null,
clientCert: null,
sslVerify: null,
})
} else {
if (!sslVerify) {
set(syslogConfig, 'certificate', null)
}
}
}
return errors
},
splunkWillSave() {
const { model = {}, intl } = this
const errors = []
if (!get(model, 'splunk.config.endpoint')) {
errors.pushObject(intl.t('loggingPage.splunk.endpointRequired'))
}
if (!get(model, 'splunk.config.token')) {
errors.pushObject(intl.t('loggingPage.splunk.tokenRequired'))
}
const config = get(model, 'splunk.config') || {}
const { endpoint = '', sslVerify } = config
const splunkConfig = get(model, 'splunkConfig') || {}
if (endpoint.startsWith('https')) {
if (!sslVerify) {
set(splunkConfig, 'certificate', null)
}
} else {
setProperties(splunkConfig, {
certificate: null,
clientKey: null,
clientCert: null,
clientKeyPass: null,
sslVerify: false,
})
}
return errors
},
elasticsearchWillSave() {
const { model = {}, intl } = this
const errors = []
const config = get(model, 'elasticsearch.config') || {}
const elasticsearchConfig = get(model, 'elasticsearchConfig') || {}
set(elasticsearchConfig, 'indexPrefix', get(elasticsearchConfig, 'indexPrefix').toLowerCase());
const indexPrefix = get(elasticsearchConfig, 'indexPrefix');
if ( !indexPrefix ) {
errors.pushObject(intl.t('loggingPage.elasticsearch.indexPatterns.errors.required'))
}
if ( indexPrefix.startsWith('-') || indexPrefix.startsWith('_') || indexPrefix.startsWith('+') ) {
errors.pushObject(intl.t('loggingPage.elasticsearch.indexPatterns.errors.startsWith'))
}
INVALID_PREFIX_CHAR.forEach((char) => {
if ( indexPrefix.indexOf(char) > -1 ) {
errors.pushObject(intl.t('loggingPage.elasticsearch.indexPatterns.errors.invalidCharacters', { char }))
}
})
const esErrors = get(this, 'esErrors')
const { endpoint, sslVerify } = config
if (!endpoint) {
errors.pushObject(intl.t('loggingPage.elasticsearch.endpoint.required'))
} else if (esErrors) {
errors.pushObject(intl.t(esErrors))
}
set(elasticsearchConfig, 'endpoint', this.formatUrl(endpoint))
if (endpoint.startsWith('https')) {
if (!sslVerify) {
set(elasticsearchConfig, 'certificate', null)
}
} else {
setProperties(elasticsearchConfig, {
certificate: null,
clientKey: null,
clientCert: null,
clientKeyPass: null,
sslVerify: false,
})
}
return errors
},
});