import path from 'path' import fs from 'fs' import lodash from 'lodash' import { Telnet } from 'telnet-client' import { getPgTableData } from './postgres' // 在目标服务器上,获取 node 可用的端口 export async function getAvailableNodePort (ip: string, startPort = 30000) { const tryPortAvailable = async function (port: number): Promise<number> { let telnet = new Telnet() const params = { host: ip, port: port, negotiationMandatory: false, timeout: 1500 } try { await telnet.connect(params) telnet.end() return tryPortAvailable(port + 1) } catch (err) { return port } } return tryPortAvailable(startPort) } export async function checkSshExists (username: string) { let gitEmail = username + '@greaconsulting.com' let docker = createDockerFactory(username) // 创建 node 容器 let container = await docker.checkContainer(username + '.node') if (!container) { throw new Error('没有创建容器,请先初始化容器') } await docker.startContainer({ container }) let sshKey = '' try { sshKey = await docker.getFile({ container, path: '/root/.ssh/id_rsa.pub' }) } catch (err) { await docker.execContainerCommand({ container, cmd: 'rm -rf /root/.ssh' }) await docker.execContainerCommand({ container, cmd: `ssh-keygen -f /root/.ssh/id_rsa -t ed25519 -C "${gitEmail}"` }) sshKey = await docker.getFile({ container, path: '/root/.ssh/id_rsa.pub' }) } return sshKey } export async function copyAndCreateServerPropertiesV2InDocker (username: string) { let docker = createDockerFactory(username) let container = await docker.checkContainer( username + '.node') if (!container) { throw new Error('没有创建容器,请先初始化容器') } let backendText = fs.readFileSync(path.resolve('./public/files/v2/application-server.properties'), { encoding: 'utf-8' }) const userDefaultSettingStr = fs.readFileSync(path.resolve('./public/files/default-user-setting.json'), { encoding: 'utf-8'}) const userConfigs = await getPgTableData('v2', username) const userDefaultSetting = JSON.parse(userDefaultSettingStr) const fn = (f: (obj: Record<string, any>) => string) => f(userConfigs!) || f(userDefaultSetting) // postgres config backendText = backendText.replace(/spring.datasource.url=(.*?)\r?\n/, `spring.datasource.url=jdbc:postgresql://${PgHost}:${PgPort}/${username}\n`) backendText = backendText.replace(/spring.datasource.username=(.*?)\r?\n/, `spring.datasource.username=${useRuntimeConfig().pgUser}\n`) backendText = backendText.replace(/spring.datasource.password=(.*?)\r?\n/, `spring.datasource.password=${useRuntimeConfig().pgPassword}\n`) // redis config backendText = backendText.replace(/spring.redis.host=(.*?)\r?\n/, `spring.redis.host=${HOST}\n`) // zookeeper config backendText = backendText.replace(/logwire.register-center-server-list=(.*?)\r?\n/, `logwire.register-center-server-list=${HOST}:2181\n`) // rocketmq config backendText = backendText.replace(/logwire.mq.name-srv-address=(.*?)\r?\n/, `logwire.mq.name-srv-address=${HOST}:9876\n`) // tenants config backendText = backendText.replace(/logwire.tenants\[0\].id=(.*?)\r?\n/, `logwire.tenants[0].id=${fn(o => o.tenants?.id)}\n`) backendText = backendText.replace(/logwire.tenants\[0\].host=(.*?)\r?\n/, `logwire.tenants[0].host=${fn(o => o.tenants?.host)}\n`) backendText = backendText.replace(/logwire.tenants\[0\].database-schema=(.*?)\r?\n/, `logwire.tenants[0].database-schema=${fn(o => o.tenants?.["database-schema"])}\n`) backendText = backendText.replace(/logwire.tenants\[0\].primary-namespace=(.*?)\r?\n/, `logwire.tenants[0].primary-namespace=${fn(o => o.tenants?.["primary-namespace"])}\n`) // 设计器配置 backendText = backendText.replace(/logwire.tenants\[0\].designer.trust-ip=(.*?)\r?\n/, `logwire.tenants[0].designer.trust-ip=${HOST}\n`) // user personal config const customServerProperties: { key: string, value: string }[] = userConfigs!.serverProperties || [] customServerProperties.forEach(item => { const RegExpKey = item.key.replaceAll('[', '\\[').replaceAll(']', '\\]').replace('.', '\\.') if (backendText.match(new RegExp(`#${RegExpKey}=(.*?)\n`))) { backendText = backendText.replace(new RegExp(`#${RegExpKey}=(.*?)\n`), `${item.key}=${item.value}\n`) } else if (backendText.match(new RegExp(`${RegExpKey}=(.*?)\n`))) { backendText = backendText.replace(new RegExp(`${RegExpKey}=(.*?)\n`), `${item.key}=${item.value}\n`) } else { // 如果完全没有匹配到内容,则直接追加到最后 backendText += `\n${item.key}=${item.value}\n` } }) await docker.writeFile({ container, path: '/var/logwire-backend/build-output/backend/config/application-server.properties', text: '\'' + backendText.replace(/'/g, '"') + '\'' }) } export async function copyAndCreateGatewayPropertiesV2InDocker (username: string) { let docker = createDockerFactory(username) let container = await docker.checkContainer( username + '.node') if (!container) { throw new Error('没有创建容器,请先初始化容器') } let gatewayText = fs.readFileSync(path.resolve('./public/files/v2/application-gateway.properties'), { encoding: 'utf-8' }) // zookeeper config gatewayText = gatewayText.replace(/gateway.register-center-server-list=(.*?)\r?\n/, `gateway.register-center-server-list=${HOST}:2181\n`) // rocketmq config gatewayText = gatewayText.replace(/gateway.mq.name-srv-address=(.*?)\r?\n/, `gateway.mq.name-srv-address=${HOST}:9876`) await docker.writeFile({ container, path: '/var/logwire-backend/build-output/gateway/config/application-gateway.properties', text: '\'' + gatewayText.replace(/'/g, '"') + '\'' }) } export async function copyAndCreateServerPropertiesV1InDocker (username: string) { let docker = createDockerFactory(username) let container = await docker.checkContainer( username + '.node') if (!container) { throw new Error('没有创建容器,请先初始化容器') } let backendText = fs.readFileSync(path.resolve('./public/files/v1/application.properties'), { encoding: 'utf-8' }) const userConfigs = await getPgTableData('v1', username) // postgres config backendText = backendText.replace(/spring.datasource.url=(.*?)\r?\n/, `spring.datasource.url=jdbc:postgresql://${PgHost}:${PgPort}/${username + '_v1'}\n`) backendText = backendText.replace(/spring.datasource.username=(.*?)\r?\n/, `spring.datasource.username=${useRuntimeConfig().pgUser}\n`) backendText = backendText.replace(/spring.datasource.password=(.*?)\r?\n/, `spring.datasource.password=${useRuntimeConfig().pgPassword}\n`) // redis config backendText = backendText.replace(/spring.redis.host=(.*?)\r?\n/, `spring.redis.host=${HOST}\n`) // user personal config const customServerProperties: { key: string, value: string }[] = userConfigs!.serverProperties || [] customServerProperties.forEach(item => { const RegExpKey = item.key.replaceAll('[', '\\[').replaceAll(']', '\\]').replace('.', '\\.') if (backendText.match(new RegExp(`#${RegExpKey}=(.*?)\n`))) { backendText = backendText.replace(new RegExp(`#${RegExpKey}=(.*?)\n`), `${item.key}=${item.value}\n`) } else if (backendText.match(new RegExp(`${RegExpKey}=(.*?)\n`))) { backendText = backendText.replace(new RegExp(`${RegExpKey}=(.*?)\n`), `${item.key}=${item.value}\n`) } else { // 如果完全没有匹配到内容,则直接追加到最后 backendText += `\n${item.key}=${item.value}\n` } }) await docker.writeFile({ container, path: '/var/logwire-platform/dist/config/application.properties', text: '\'' + backendText.replace(/'/g, '"') + '\'' }) } export async function copyAndCreateNginxConfInDocker (username: string) { let docker = createDockerFactory(username) let container = await docker.checkContainer( username + '.node') if (!container) { throw new Error('没有创建容器,请先初始化容器') } const userDefaultSettingStr = fs.readFileSync(path.resolve('./public/files/default-user-setting.json'), { encoding: 'utf-8'}) const userDefaultSetting = JSON.parse(userDefaultSettingStr) const userConfigs = await getPgTableData('v2', username) const nginxConfigStr = fs.readFileSync(path.resolve('./public/files/nginx.conf'), { encoding: 'utf-8' }) // 修改调试端口的 NGINX 配置 const replacedNginxConfig = nginxConfigStr.replace(/192.168.1.94/, userConfigs?.debug?.host || userDefaultSetting.debug.host) await docker.writeFile({ container, path: '/etc/nginx/nginx.conf', text: '\'' + replacedNginxConfig + '\'' }) } export function getPlatformRootFolder (platform: 'v1' | 'v2') { return platform === 'v1' ? '/var/logwire-platform' : '/var/logwire-backend' }