Esempio n. 1
0
 def start(self, run_path):
     # 启动新的服务.
     cmd = 'cd %s; cd program;  sh __start_all.sh'  % (run_path)
     ret = pyshell.remote_shell(cmd, warn_only=True)
     if ret.return_code != 0:
         raise Exception('start failed')
Esempio n. 2
0
 def stop(self, run_path):
     cmd = 'cd %s; if [ -d program ] ;then cd program;  sh __stop_all.sh; fi'  % (
             run_path)
     ret = pyshell.remote_shell(cmd, warn_only=True)
Esempio n. 3
0
    def deploy(self, program_path, deploy_env):
        """
        @program_path: 程序在本地的地址.
        @env: 要部署环境
        pre-condition:当前工作目录处在要部署的模块下.
        从octopus.prj文件中读取依赖哪些库.
        从METAINFO/deploy.inf中读取依赖的版本,如果没有该文件,则都用最新版本(build号最大的).
        从deploy.conf文件中读取部署到哪里
        拷贝模块自身到目标位置
        拷贝依赖模块到目标位置(这个不好弄,依赖模块的路径怎么设定定?)
        在远程机器上运行setup 脚本
        在本机运行冒烟测试脚本(smoketest)
        """
        print 'start deploy ' + program_path + ', env=' + deploy_env
        REMOTE_PROGRAM_BASE = '~/program'
        REMOTE_RUN_BASE =  '~/service'
        program_info = ProgramInfo(program_path)
        depends = program_info.get_depends()
        build_no = program_info.get_buildmeta().build_number
        scripts = program_info.get_scripts()
        # 读取部署位置文件,将文件拷贝过去.    
        deploy_conf_file = program_path + '/config/%s/deploy.conf' % (deploy_env)
        deploy_conf  = pyetc.load(deploy_conf_file, deploy_schema.ENV)
        instances = deploy_conf.CONFIG['instance']
        for instance in instances:
            instance_name = instance['user'] + '@' + instance['host'] + ':'
            instance_name = instance_name + instance['name']
            fabric_env.host_string = instance['host']
            print '=================start deploy %s =========' % (instance_name)
            fabric_env.user = instance['user']
            # 生成模版文件,打包成tar.gz.
            homedir = CITool.get_homedir(pyshell.remote_shell)
            run_path = REMOTE_RUN_BASE + '/' + instance['name']
            run_path = CITool.normalize_path(run_path, homedir)
            print run_path
            remote_program_path = REMOTE_PROGRAM_BASE + '/' + instance['name']
            if build_no > 0:
                remote_program_path = '%s-%d' % (remote_program_path, build_no)
            else:
                # 如果取不到build号,则取当前时间.
                cur_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                remote_program_path = '%s-%s' % (remote_program_path, cur_time)

            shell_ret = pyshell.remote_shell('if [ -d %s ] ;then exit 1;fi' % (
                            remote_program_path), warn_only=True)
            
            if shell_ret.return_code == 0: 
                # 目录不存在,则重新打包拷贝.
                pkg_file_full_path = self.make_package(instance, program_info,
                    program_path, deploy_env, run_path, remote_program_path)
                run('mkdir -p %s' % (remote_program_path))
                put(pkg_file_full_path, remote_program_path)
                local('rm -f ' + pkg_file_full_path)
                run('cd %s && tar -zxf %s' % (
                    remote_program_path, os.path.basename(pkg_file_full_path)))
            # 安装依赖的模块.
            print '===================<<%s>> start install depends========' % (
                    instance_name)
            self.install_depends(depends, 'runtime', {'host':instance['host'],
                'user':instance['user']})
            # 按顺序执行脚本 install, stop,  switch,  start,check
            # install - 
            print '===================<<%s>> start scripts:install========' % (
                    instance_name)
            try:
                self.run_script(instance, 'install', scripts,
                        remote_program_path, pyshell.remote_shell)
            except Exception, e:
                print 'step=install host=%s program=%s e=%s' % (
                        instance['host'], remote_program_path, e)
                raise e
            print '===================<<%s>> stop ========' % ( instance_name )
            self.stop(run_path)
            # switch - unlink link, ln -s install_path link
            print '===================<<%s>> switch link========' % (
                instance_name)
            run('[ -d %s ] || mkdir -p %s' % (run_path, run_path))
            run(('cd %s ;  if [ -h program_old ]; then mv program_old program_old2;fi;'
                +'  if [ -h program ] ;then  mv program program_old; fi ;'
                +' ln -s %s program') % (
                run_path, remote_program_path))
            # 启动新的
            print '===================<<%s>> start ========' % (
                    instance_name)
            try:
                self.start(run_path)
                # 进行线上检查
                print '===================<<%s>> check ========' % (
                        instance_name)
                self.run_script(instance, 'check', scripts, remote_program_path,
                        run_path)
                # 删除program_old2
                print '===================<<%s>> delete old version ========' % (
                        instance_name)
                ret = pyshell.remote_shell(('cd %s;'
                        +' if [ -h program_old2 ] ;then '
                        +'old2=`readlink program_old2`;'
                        +'old=`readlink program_old`;'
                        +'pp=`readlink program`;'
                        + ' if [ "$old2" = "$old" -o "$old2" = "$pp" ];then rm -f program_old2;'
                        +'else rm -rf $old2 program_old2; fi;fi') % (run_path))
            except Exception,e:
                # 如果失败,回滚.回滚怎么重启老版本的服务?octopus.prj文件中的脚本可能发生了变化.
                # 解决方案1:
                # 1) 脚本不在octopus中配置,必须写死,但是解决不了多role问题
                # 2) 或者重新读远程目录的octopus.prj文件, 仍然解决不了多role问题。
                # 3) 必须生成一个部署meta文件,放在METAINFO/deploy.inf中,将role信息写入
                # 另外依赖库怎么办?需要重新安装一遍吗?
                # 看来最好的办法还是将所有的依赖库都放在自己的目录下.
                # 1.一些第三方库整个维持一个版本(即depend_third每个程序只能有一个版本)
                # 2. 模块下有个lib目录,放依赖的库和程序.
                # 这样回滚的时候只需要修改链接就行.
                print e
                print '===================<<%s>> rollback ========' % (
                        instance_name)
                # stop 正在部署的服务
                self.stop(run_path)
                run(('cd %s ;  if [ -h program_fail ];then old_fail=`readlink program_fail`;pp=`readlink program`;'
                    +' if [ "$old_fail" = "$pp" ];then unlink program_fail; else rm -rf $old_fail program_fail;fi;'
                    +'fi; mv program program_fail; '
                   +'if [ -h program_old ] ; then  mv program_old program; fi;'
                   +'if [ -h program_old2 ];then mv program_old2 program_old; fi') % (run_path))
                # 切换目录,启动老版本的服务
                try:
                    self.start(run_path)
                except Exception, e:
                    print 'rollback faied ,reson=%s' % (e)