api.js 6.54 KB
'use strict';

const Router = require('koa-router');
const _ = require('lodash');
const Operation = require('../../logger/operation');
const Build = require('../../ci/build');
const Deploy = require('../../ci/deploy');
const DeployPool = require('../../ci/deploy_pool');
const {
    Building,
    Project,
    Server,
    DeployInfo,
    RestartInfo,
    DeleteRestartInfo
} = require('../../models');

let r = new Router();

r.get('/params', async(ctx) => {
    ctx.body = {
        env: {
            production: '线上环境',
            preview: '灰度环境'
        },
        cloud: {
            aws: '亚马逊',
            qcloud: '腾讯云'
        }
    };
});

r.get('/projects', async(ctx) => {
    let q = ctx.request.query;
    let cloud = _.trim(q.cloud);
    let query = {};

    if (cloud) {
        query.cloud = cloud;
    }

    let projects = await Project.find(query);

    ctx.body = _.map(projects, p => {
        return {
            id: p._id,
            name: p.name,
            subname: p.subname
        };
    });
});

r.get('/publish', async (ctx) => {
    let q = ctx.request.query;
    let id = q.id;
    let env = q.env;
    let branch = q.branch;

    let p = await Project.findById(id);
    let build = new Build(p);

    let {
        buildTime,
        distFile
    } = build.build(branch);
    let buildingDoc = await Building.insert({
        buildTime: buildTime,
        project: p.name,
        projectId: id,
        branch: branch,
        env: env,
        distFile: distFile,
        state: 'waiting',
        md5: '',
        createdAt: new Date(),
        updatedAt: new Date()
    });
    let building = buildingDoc[0];

    let bid = building._id;

    build.run(bid, async () => {
        let targets = p.deploy[env].target;

        if (typeof targets === 'string') {
            targets = [targets];
        }

        targets.forEach(async(host) => {
            let deploy = new Deploy(p, building, host);

            DeployPool.deploy(deploy);
        });

        await Operation.action('app', 'PROJECT_DEPLOY', '项目分发部署', {
            _id: bid,
            project: p.name,
            branch: building.branch,
            env: building.env
        });
    });

    await Operation.action('app', 'NEW_PROJECT_BUILDING', '新增项目构建', {
        _id: id,
        project: p.name,
        branch: branch,
        env: env
    });

    ctx.body = {
        code: 200,
        bid: bid
    };
});

r.get('/builds', async (ctx) => {
    let q = ctx.request.query;
    let buildings = await Building.cfind({
        env: q.env,
        projectId: q.id,
        state: 'success'
    }).sort({
        buildTime: -1
    }).limit(30).exec();

    ctx.body = _.map(buildings, b => {
        return {id: b._id, createdAt: b.createdAt, buildNo: b.buildTime};
    });
});

r.get('/rollback', async (ctx) => {
    let q = ctx.request.query;
    let buildingId = q.id;
    let building = await Building.findById(q.id);
    if (!building) {
        ctx.body = {
            code: 201,
            msg: '该版本不存在'
        };
    } else if (building.state == 'success') {
        let project = await Project.findById(building.projectId);
        let targets = project.deploy[building.env].target;

        if (typeof targets === 'string') {
            targets = [targets];
        }

        targets.forEach(async(host) => {

            let doc = await DeployInfo.findOne({
                projectId: project._id,
                host: host,
                env: building.env
            });

            if (!doc || doc.state !== 'running' || doc.building !== building.buildTime) {
                let deploy = new Deploy(project, building, host);

                // if (project.type === 'php') {
                //     deploy = new DeployPhp(project, building, host);
                // } else {
                //     deploy = new Deploy(project, building, host);
                // }
                DeployPool.deploy(deploy);
            }
        });

        await Operation.action(ctx.session.user, 'PROJECT_DEPLOY', '项目分发部署', {
            _id: buildingId,
            project: project.name,
            branch: building.branch,
            env: building.env
        });

        ctx.body = {
            code: 200,
            targets: targets
        };
    } else {
        ctx.body = {
            code: 201,
            msg: '该版本未构建成功,暂不能分发'
        };
    }
});

r.get('/deploy', async (ctx) => {
    let q = ctx.request.query;
    let buildingId = q.bid;
    let building = await Building.findById(buildingId);
    if (!building) {
        ctx.body = {
            code: 201,
            msg: '该版本不存在'
        };
    } else if (building.state == 'success') {
        let project = await Project.findById(building.projectId);
        let targets = project.deploy[building.env].target;

        if (typeof targets === 'string') {
            targets = [targets];
        }

        targets.forEach(async(host) => {

            let doc = await DeployInfo.findOne({
                projectId: project._id,
                host: host,
                env: building.env
            });

            if (!doc || doc.state !== 'running' || doc.building !== building.buildTime) {
                let deploy = new Deploy(project, building, host);
                DeployPool.deploy(deploy);
            }
        });

        await Operation.action(ctx.session.user, 'PROJECT_DEPLOY', '项目分发部署', {
            _id: buildingId,
            project: project.name,
            branch: building.branch,
            env: building.env
        });

        ctx.body = {
            code: 200,
            building: building
        };
    } else {
        ctx.body = {
            code: 201,
            msg: '该版本未构建成功,暂不能分发'
        };
    }
});

r.get('/state', async (ctx) => {
    let q = ctx.request.query;

    let building = await Building.findById(q.bid);
    let doc = await DeployInfo.find({
        projectId: building.projectId,
        env: building.env,
        building: building.buildTime
    });

    let finish = true;
    let redeploy = false;

    let deploys = _.map(doc, d => {
        if (d.state !== 'running' && d.state !== 'fail') {
            finish = false;
        }

        if (d.state === 'fail') {
            redeploy = true;
        } 

        return {
            host: d.host,
            state: d.state
        };
    });

    ctx.body = {
        build: building.state,
        deploy: deploys,
        finish: finish,
        redeploy: redeploy && finish
    };
});


module.exports = r;