restart.js 2.87 KB
/**
 * 分发部署
 * 
 * @class Restart
 * @author shenzm<zhimin.shen@yoho.cn>
 * @date 2016/10/12
 */

import ssh from 'ssh2';
import path from 'path';

import ws from '../../lib/ws';
import {
    RestartInfo,
    DeployInfo,
    Server
} from '../models';

class Restart {

    constructor(project) {
        this.project = project;
    }

    async restart(info) {
        let server = await Server.findByHost(info.host);

        this.server = server;
        this.info = info;
        this.id = await DeployInfo.insertOrUpdate(this.info);
        this.sshRestart({
            host: server.host,
            username: server.username,
            password: server.password,
            port: server.port
        });
    }

    sshRestart(serverInfo) {
        console.log('ssh connecting', serverInfo);
        let conn = new ssh.Client();
        let self = this;
        conn.on('ready', async() => {
            console.log(`connected ${serverInfo.host}`);
            try {
                await self._restart(conn);
                conn.end();
            } catch (e) {
                self._state('fail');
                self._log(e);
            }
        }).on('error', (err) => {
            self._state('fail');
            self._log(err);
        }).connect(serverInfo);
    }

    _restart(conn) {
        let self = this;
        let startup = this.project.scripts.start;
        return new Promise((resolve, reject) => {
            self._state('restarting');
            self._log(`>>>> ${startup}`);
            conn.exec(`cd ${self.remoteRunningDir} && ${startup}`, (err, stream) => {
                if (err) {
                    reject(err);
                } else {
                    stream.stdout.on('data', (data) => {
                        self._log(data.toString());
                    });
                    stream.stderr.on('data', (data) => {
                        self._log(data.toString());
                    });
                    stream.on('exit', (code) => {
                        if (code === 0) {
                            self._state('running');
                            resolve();
                        } else {
                            reject('restart fail');
                        }
                    });
                }
            });
        });
    }

    async _state(state) {
        ws.broadcast(`/restart/${this.project._id}`, {
            host: this.info.host,
            state: state
        });
        await RestartInfo.updateState(this.info._id, state);
        await DeployInfo.updateState(this.id, state);
    }

    _log(msg) {
        console.log(msg);
        ws.broadcast(`/restart/${this.project._id}/log`, {
            host: this.info.host,
            msg: msg
        });
    }

    get remoteRunningDir() {
        return path.join(this.server.deployDir, this.project.name, 'current', this.project.name);
    }
}

export default Restart;