testing
This commit is contained in:
252
nodejs/lib/deploy.js
Normal file
252
nodejs/lib/deploy.js
Normal file
@ -0,0 +1,252 @@
|
||||
'user strict';
|
||||
const extend = require('extend');
|
||||
const axios = require('axios')
|
||||
const {Repo, Environment, Deployment, Target} = require('../models/repo');
|
||||
const deployTargets = require('./lxc');
|
||||
const conf = require('../conf/conf')
|
||||
|
||||
async function doDeploy(action, repo, branch, repoSshurl, commit){
|
||||
var deployment;
|
||||
try{
|
||||
|
||||
console.log(action, repo, branch, repoSshurl, commit)
|
||||
repo = await Repo.get(repo);
|
||||
|
||||
let deployments = await repo.getDeploymentsbyBranch(branch, true)
|
||||
|
||||
console.log('deployments', deployments)
|
||||
|
||||
if(deployments.length && action === 'delete'){
|
||||
deployment = deployments[0]
|
||||
}if(deployments.length){
|
||||
deployment = deployments[0]
|
||||
action = 'update';
|
||||
}else{
|
||||
var environment = await repo.getEnvironmentsbyBranch(branch)
|
||||
deployment = await environment.addDeployment()
|
||||
}
|
||||
|
||||
deployment.environment.settings.repoSshurl = repoSshurl
|
||||
deployment.environment.settings.branch = branch
|
||||
|
||||
|
||||
}catch(error){
|
||||
console.error('create start', error)
|
||||
throw new Error('Failed to make new Deployment')
|
||||
}
|
||||
|
||||
try{
|
||||
deployment = new Depoy(deployment);
|
||||
setImmediate(async function(deployment, action) {
|
||||
try{
|
||||
await deployment[action]()
|
||||
}catch(error){
|
||||
console.log('set error', error)
|
||||
}
|
||||
}, deployment, action)
|
||||
|
||||
return {id: deployment.id};
|
||||
}catch(error){
|
||||
console.error('create remote', error)
|
||||
}
|
||||
}
|
||||
|
||||
function event(deployment, message){
|
||||
console.info('event:', message)
|
||||
}
|
||||
|
||||
class Depoy{
|
||||
constructor(deployment){
|
||||
this.deployment = deployment
|
||||
this.environment = deployment.environment;
|
||||
this.settings = pasrseSetings(deployment);
|
||||
this.secrets = pasrseSecrets(deployment);
|
||||
this.id = deployment.repo_env_id
|
||||
|
||||
this.target = new deployTargets[deployment.target.type](this.settings)
|
||||
}
|
||||
|
||||
async exec(code, info){
|
||||
await this.event(`exec-start`, {info})
|
||||
code = `
|
||||
sudo su
|
||||
${exportBashVars(this.secrets)}
|
||||
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
${code}
|
||||
`
|
||||
let res = await this.target.exec(code);
|
||||
|
||||
await this.event(`exec-finish`, {info, ...res})
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async event(name, data){
|
||||
console.log(`EVENT: ${name}`, data)
|
||||
}
|
||||
|
||||
async log(type, message){
|
||||
console.log('LOG:', type, message)
|
||||
}
|
||||
|
||||
async setinfo(){
|
||||
let info = await this.target.info();
|
||||
if(!info.ip){
|
||||
return await this.setinfo();
|
||||
}
|
||||
let id = info.ip.slice(-2);
|
||||
let settings = {
|
||||
sshURL: `${this.settings.host}:22${id}`,
|
||||
httpURL: `${this.settings.host}:80${id}`,
|
||||
}
|
||||
|
||||
this.settings = {...this.settings, ...settings};
|
||||
|
||||
await this.deployment.update('settings', {settings: this.settings, state:'deployed'})
|
||||
}
|
||||
|
||||
async create(){
|
||||
|
||||
this.event('deployment-started', {info: `Creating deployment ${this.settings.appName}`})
|
||||
await this.target.create('bionic-base')
|
||||
await this.target.start()
|
||||
await this.setinfo();
|
||||
|
||||
console.log(this.settings)
|
||||
|
||||
try{
|
||||
await this.exec(`
|
||||
while [ ! -f /opt/datacom/firstboot ]; do sleep 1; done
|
||||
sleep 2
|
||||
`, 'Wait for target to be ready')
|
||||
}catch(error){}
|
||||
await this.init();
|
||||
await this.updateProxy();
|
||||
}
|
||||
|
||||
async init(){
|
||||
await this.exec(deployInitScript(this.settings), 'Initializing deployment')
|
||||
|
||||
await this.exec(`
|
||||
cd ${this.settings.workingPath};
|
||||
./${this.settings.scriptsPath}/${this.environment.environment}/deploy.sh
|
||||
`, 'Running repo deploy script')
|
||||
}
|
||||
|
||||
async update(){
|
||||
await this.exec(`
|
||||
cd ${this.settings.workingPath};
|
||||
export GIT_SSH_COMMAND="/usr/bin/ssh -o StrictHostKeyChecking=no -i $HOME/.ssh/id_rsa_deploy_key"
|
||||
git pull origin master;
|
||||
./${this.settings.scriptsPath}/${this.environment.environment}/update.sh
|
||||
`, 'Running repo update script')
|
||||
}
|
||||
|
||||
async updateProxy(){
|
||||
let target = this.settings.httpURL.split(':');
|
||||
|
||||
let res = await axios.post(`${conf.httpProxyAPI.host}/api/host/`, {
|
||||
forcessl: true,
|
||||
host: this.settings.domain.replace('*', this.settings.branch),
|
||||
ip: target[0],
|
||||
targetPort: Number(target[1] || 80),
|
||||
targetssl: false
|
||||
}, {
|
||||
headers: { "auth-token": conf.httpProxyAPI.key }
|
||||
})
|
||||
}
|
||||
|
||||
async delete(){
|
||||
await this.target.destroy()
|
||||
await this.deployment.update({state: 'deleted', isActive: false})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function deployUpdateScript(argument) {
|
||||
// body...
|
||||
}
|
||||
|
||||
function deployInitScript(args){
|
||||
return `
|
||||
mkdir -p "${args.workingPath}";
|
||||
mkdir "$HOME/.ssh";
|
||||
chmod 700 "$HOME/.ssh"
|
||||
echo "${args.privateKey}" > $HOME/.ssh/id_rsa_deploy_key
|
||||
chmod 600 $HOME/.ssh/id_rsa_deploy_key
|
||||
wget https://raw.githubusercontent.com/tests-always-included/mo/master/mo -O /usr/local/bin/mo
|
||||
chmod +x /usr/local/bin/mo
|
||||
export GIT_SSH_COMMAND="/usr/bin/ssh -o StrictHostKeyChecking=no -i $HOME/.ssh/id_rsa_deploy_key"
|
||||
git clone ${args.repoSshurl} ${args.workingPath};
|
||||
`
|
||||
}
|
||||
|
||||
function exportBashVars(map){
|
||||
let out = '';
|
||||
for (const [key, value] of Object.entries(map)){
|
||||
out += `export ${key}="${value}";`
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
function pasrseBase(deployment){
|
||||
let appName = deployment.repo_env_id.replace('/', '_')
|
||||
|
||||
return {
|
||||
appName: appName,
|
||||
scriptsPath: deployment.environment.repo.scriptsPath,
|
||||
privateKey: deployment.environment.repo.privateKey,
|
||||
environment: deployment.environment.environment,
|
||||
workingPath: `${deployment.environment.workingPath}/${appName}`,
|
||||
domain: deployment.environment.domain,
|
||||
name: appName,
|
||||
}
|
||||
}
|
||||
|
||||
function pasrseSecrets(deployment){
|
||||
return {
|
||||
...deployment.environment.repo.secrets,
|
||||
...deployment.environment.secrets,
|
||||
...pasrseBase(deployment),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function pasrseSetings(deployment){
|
||||
return {
|
||||
...deployment.target.settings,
|
||||
...deployment.environment.repo.settings,
|
||||
...deployment.environment.settings,
|
||||
...pasrseBase(deployment),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {doDeploy};
|
||||
|
||||
(async function(){try{
|
||||
// console.log(await doDeploy('create', 'wmantly/static-test', 'master', 'ssh://gitea@git.theta42.com:2222/wmantly/static-test.git'))
|
||||
|
||||
// let repo = await Repo.get('wmantly/static-test');
|
||||
// let deployments = await repo.getDeploymentsbyBranch('master')
|
||||
|
||||
// for(let d of deployments){
|
||||
// try{
|
||||
// let lxc = new deployTargets.LXC({...{name: d.repo_env_id.replace('/', '_')}, ...d.target.settings})
|
||||
// await lxc.destroy();
|
||||
// await d.remove()
|
||||
|
||||
// }catch(error){
|
||||
// console.log('err', error)
|
||||
// }finally{
|
||||
// await d.remove()
|
||||
// }
|
||||
// }
|
||||
|
||||
}catch(error){
|
||||
console.error('IIFE error:', error)
|
||||
}})()
|
174
nodejs/lib/lxc.js
Normal file
174
nodejs/lib/lxc.js
Normal file
@ -0,0 +1,174 @@
|
||||
'use strict';
|
||||
const util = require('util');
|
||||
const exec = util.promisify(require('child_process').exec)
|
||||
|
||||
|
||||
class Local{
|
||||
async sysExec(command){
|
||||
try{
|
||||
return await exec(command)
|
||||
}catch(error){
|
||||
throw(error);
|
||||
}
|
||||
}
|
||||
|
||||
async exec(...args){
|
||||
await this.sysExec()
|
||||
}
|
||||
}
|
||||
|
||||
class SSH extends Local{
|
||||
constructor(args){
|
||||
super()
|
||||
this.user = args.user;
|
||||
this.host = args.host;
|
||||
this.keyPath = args.keyPath;
|
||||
}
|
||||
|
||||
async sysExec(command){try{
|
||||
// console.log('command', command)
|
||||
command = new Buffer.from(command).toString('base64');
|
||||
command = `ssh -i "${this.keyPath}" -o StrictHostKeyChecking=no ${this.user}@${this.host} "echo ${command} | base64 --decode | bash"`;
|
||||
return await super.sysExec(command);
|
||||
}catch(error){
|
||||
throw error;
|
||||
}}
|
||||
}
|
||||
|
||||
class LXC{
|
||||
constructor(args){
|
||||
// console.log('lxc args', args)
|
||||
this.name = args.name
|
||||
if(args.host){
|
||||
this.sysExec = (new SSH(args)).sysExec.bind(args)
|
||||
}else{
|
||||
this.sysExec = (new Local()).sysExec
|
||||
}
|
||||
}
|
||||
|
||||
static async list(){
|
||||
try{
|
||||
let res = await this.prototype.sysExec(`lxc-ls --fancy`);
|
||||
let output = res.stdout.split("\n").slice(0).slice(0,-1);
|
||||
let keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1).map(function(v){return v.toLowerCase()});
|
||||
let info = [];
|
||||
|
||||
for(let line of output){
|
||||
if(line.match(/^-/)) continue;
|
||||
|
||||
line = line.split(/\s+/).slice(0,-1);
|
||||
|
||||
let mapOut = {};
|
||||
line.map(function(value,idx){
|
||||
mapOut[keys[idx]] = value;
|
||||
});
|
||||
info.push(mapOut);
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async create(from){
|
||||
try{
|
||||
return await this.sysExec(`lxc-copy --name "${from}" --newname "${this.name}" --daemon`);
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async start(){
|
||||
try{
|
||||
return await this.sysExec(`lxc-start --name "${this.name}" --daemon`);
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async destroy(){
|
||||
try{
|
||||
let res = await this.sysExec(`lxc-destroy --force --name ${this.name}`)
|
||||
|
||||
return !!res.stdout.match(/Destroyed container/);
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async stop(){
|
||||
try{
|
||||
return await this.sysExec(`lxc-stop --name "${this.name}"`);
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async exec(code){
|
||||
try{
|
||||
code = new Buffer.from(code).toString('base64')
|
||||
return await this.sysExec(`lxc-attach -n "${this.name}" --clear-env -- bash -c 'echo "${code}" | base64 --decode | bash'`)
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async info(){
|
||||
try{
|
||||
let info = {};
|
||||
|
||||
let res = await this.sysExec(`lxc-info --name "${this.name}"`);
|
||||
res = res.stdout;
|
||||
|
||||
if(res.match("doesn't exist")){
|
||||
throw new Error('ContainerDoesntExist')
|
||||
}
|
||||
|
||||
res = res.replace(/\suse/ig, '').replace(/\sbytes/ig, '').split("\n").slice(0,-1);
|
||||
for(var i in res){
|
||||
var temp = res[i].split(/\:\s+/);
|
||||
info[temp[0].toLowerCase().trim()] = temp[1].trim();
|
||||
}
|
||||
var args = [info].concat(Array.prototype.slice.call(arguments, 1));
|
||||
|
||||
return info;
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async setAutoStart(name){
|
||||
await this.sysExec(`echo "lxc.start.auto = 1" >> "$HOME/.local/share/lxc/${this.name}/config"`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {Local, SSH, LXC};
|
||||
|
||||
(async function(){try{
|
||||
|
||||
// let lxc = new LXC();
|
||||
|
||||
// // console.log(await lxc.copy('hass', 'hass2'))
|
||||
|
||||
// console.log(await lxc.destroy('hass2'))
|
||||
// console.log(await LXC.list())
|
||||
|
||||
// let lxc = new LXC({name:'hass'})
|
||||
// console.log(await hass.start())
|
||||
|
||||
|
||||
|
||||
// let lxc = new LXC({user:'virt-service', host:'142.93.30.52', keyPath:'/home/william/.ssh/id_rsa_virt-service', name: 'test2'})
|
||||
// console.log(await lxc.exec('hostname'))
|
||||
// // console.log(await lxc.exec('test2', 'sleep 50'))
|
||||
// console.log(await lxc.info())
|
||||
//
|
||||
|
||||
|
||||
}catch(error){
|
||||
console.error('IIFE error', error);
|
||||
}})()
|
Reference in New Issue
Block a user