jenkins

1、jenkins pipeline实践

(1)调用salt进行os初始化

依赖后端python脚本和成体系的salt状态管理

properties([
    parameters([
        choice(choices: 'ali\ntengxun\naws', description: '选择数据中心', name: 'idc_name')
    ])
])

node {
    if ( params.idc_name == 'ali' ) {
        env.HOST = '10.0.0.1'
        env.PORT = 56578
        env.IDC_NAME = 'ali'
    } else if ( params.idc_name == 'tengxun' ) {
        env.HOST = '10.0.0.2'
        env.PORT = 56578
        env.IDC_NAME = 'tengxun'
	} else if ( params.idc_name == 'aws' ) {
        env.HOST = '10.0.0.3'
        env.IDC_NAME = 'aws'
        env.PORT = 22
    } else {
        echo "input error !!!!!!"
        sh "exit 1"
    }

	stage("upload") {
        //上传excel文件,记录主机名、ip、登录账号及密码等信息
        def inputFile = input message: 'Upload file', parameters: [file(name: 'salt-minion.xlsx')]
        new hudson.FilePath(new File("/srv/salt/base/salt-minion.xlsx")).copyFrom(inputFile)
        inputFile.delete()
    }
    stage("check_file") {
        echo fileExists('/srv/salt/base/salt-minion.xlsx').toString()
        echo "upload excel success !"
	}

	stage ('cp_excel_to_master') {
		sh "scp -P ${env.PORT} /srv/salt/base/salt-minion.xlsx salt@${env.HOST}:/tmp/ "
	}
	stage ('create_roaster') {
		sh "ssh -p ${env.PORT} salt@${env.HOST} 'sudo /root/.pyenv/shims/python /data/scripts/jenkins/autosysinit/1_check_ssh.py --idc ${env.IDC_NAME}'"
    }
	//stage ('check_certifi') {
    //    sh "salt-ssh ${env.MASTER_NAME} cmd.run '/root/.pyenv/shims/python /data/scripts/jenkins/autosysinit/2_install_certifi.py'"
    //}
    stage ('salt-minion-install') {
        sh "/root/.pyenv/shims/python /data/scripts/jenkins/autosysinit/2_salt-ssh.py --idc ${env.IDC_NAME}"
    }

    stage ('salt-minion-check') {
        sh "/root/.pyenv/shims/python /data/scripts/jenkins/autosysinit/3_check_minion.py --idc ${env.IDC_NAME}"
    }

    stage ('salt-state-sls') {
        sh "/root/.pyenv/shims/python /data/scripts/jenkins/autosysinit/4_check_sls.py --idc ${env.IDC_NAME}"
    }

}

参考:
https://stackoverflow.com/questions/38080876/jenkins-pipeline-job-with-file-parameter

(2)SOA发版jenkins pipeline配置

第一版:

依赖后端python+saltstack发版系统和lua+redis+nginx实现的流量自动切换,实现soa框架精细化发版

properties([
    parameters([
        choice(choices: '01-Commit Package to SVN\n02-Archive Package to Local DataCenter\n03-Group01-Getfile\n04-Group01-Unpack\n05-Group01-Dubbo-Disable\n06-Group01-Stop\n07-Group01-Symlink\n08-Group01-Start\n09-Group01-Dubbo-Enable\n10-Group02-Getfile\n11-Group02-Unpack\n12-Group02-Dobbo-Disable\n13-Group02-Stop\n14-Group02-Symlink\n15-Group02-Start\n16-Group02-Dubbo-Enable', description: '选择开始步骤', name: 'start_step')
    ])
])


node
{
  if (1 >= params.start_step.substring(0,2).toInteger()) {
    //提交开发上传的工程包至发布SVN库
    stage ('1-Commit Package to SVN') {
        wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
            sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python commit.py --app=soa" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
        }
        input '继续还是退出?'
    }
  }

  if (2 >= params.start_step.substring(0,2).toInteger()) {
    //从发布SVN库更新至本地数据中心
    stage ('2-Archive Package to Local DataCenter') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python archive.py --app=soa" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (3 >= params.start_step.substring(0,2).toInteger()) {
    //分发第一组应用到对应的机器上
    stage ('3-Group01-Getfile') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=getfile" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
	}
  }


  if (4 >= params.start_step.substring(0,2).toInteger()) {
    //解压第一组应用
    stage ('4-Group01-Unpack') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=unpack" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (5 >= params.start_step.substring(0,2).toInteger()) {
    //在dubbo-admin中禁用第一组应用
    stage ('5-Group01-Dubbo-Disable') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=dubbo --action=disable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
	}
  }

  if (6 >= params.start_step.substring(0,2).toInteger()) {
    //停止、打连接、启动第一组应用
    stage ('6-Group01-Stop') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=stop" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (7 >= params.start_step.substring(0,2).toInteger()) {
    //打连接第一组应用
    stage ('7-Group01-Symlink') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=symlink" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (8 >= params.start_step.substring(0,2).toInteger()) {
    //启动第一组应用
    stage ('8-Group01-Start') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=start" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
	}
  }

  if (9 >= params.start_step.substring(0,2).toInteger()) {
    //在dubbo-admin中开启第一组应用
    stage ('9-Group01-Dubbo-Enable') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=1 --type=dubbo --action=enable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
	}
  }


  if (10 >= params.start_step.substring(0,2).toInteger()) {
    //分发第二组应用包到对应对的机器上
    stage ('10-Group02-Getfile') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=getfile" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
    }
  }

  if (11 >= params.start_step.substring(0,2).toInteger()) {
    //解压第二组应用
    stage ('11-Group02-Unpack') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=unpack" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (12 >= params.start_step.substring(0,2).toInteger()) {
    //在dubbo-admin中禁用第二组应用
    stage ('12-Group02-Dobbo-Disable') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=dubbo --action=disable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
    }
  }

  if (13 >= params.start_step.substring(0,2).toInteger()) {
    //停止第二组应用
    stage ('13-Group02-Stop') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=stop" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (14 >= params.start_step.substring(0,2).toInteger()) {
    //打连接第二组应用
    stage ('14-Group02-Symlink') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=symlink" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }

  if (15 >= params.start_step.substring(0,2).toInteger()) {
    //启动第二组应用
    stage ('15-Group02-Start') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=start" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
			input '继续还是退出?'
		}
    }
  }

    if (16 >= params.start_step.substring(0,2).toInteger()) {
	//在dubbo-admin中开启第二组应用
    stage ('16-Group02-Dubbo-Enable') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
			sh 'salt-ssh --force-color "xxxxxxx.ali" cmd.run "python release.py --app=soa --group=2 --type=dubbo --action=enable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
		}
	}
  }
}

说明:

当执行到7步的时候,由于网络或者其他原因,导致在第七步失败了。
人工干预:
    先确定第七步是否执行?
        如果第七步已经执行了,只是突然断网导致pipeline退出,第二次手动执行pipeline的时候从选择第7+1步开始
        如果第七步并没有执行就断网了,第二次手动执行pipeline的时候还是从第七步开始执行

第二版:

再去做一套蓝绿没有必要,又懒得做到后端的python中去,就用jenkins的并行任务来修改nginx并重启

pipeline {
    agent any
    parameters {
        choice(choices: '01-提交更新\n02-生成程序包\n03-G1-分发程序包\n04-G1-解压程序包\n05-G1-下线应用\n06-G1-关闭应用\n07-G1-升级应用\n08-G1-启动应用\n09-G1-上线应用\n10-G2-分发程序包\n11-G2-解压程序包\n12-G2-下线应用\n13-G2-关闭应用\n14-G2-升级应用\n15-G2-启动应用\n16-G2-上线应用', description: '选择开始步骤', name: 'start_step')
        choice(name: 'has_pay_notify_web', choices: 'no\nyes', description: '是否有pay-notify-web要发?')

    }
    stages {
        stage('01-提交更新') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 1}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python commit.py --app=soa" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('02-生成程序包') {
            input {
                message "是否继续生成、分发程序包"
                ok "是的"
            }
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 2}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python archive.py --app=soa" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('03-G1-分发程序包') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 3}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=getfile" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('04-G1-解压程序包') {
            input {
                 message "是否继续解压、禁dubbo?"
                 ok "是的"
            }
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 4}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=unpack" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }


        stage('05-G1-下线应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 5}
            }

            parallel {
                stage('05-G1-common') {
                    steps {
                        sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=dubbo --action=disable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
                    }
                }
                stage('05-G1-notify') {
                    when {
                        expression {params.has_pay_notify_web == 'yes'}
                    }
                    steps {
                        echo "..."
                    }
                }
            }
        }


        stage('06-G1-关闭应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 6}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=stop" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
            input {
                 message "是否继续升级、启动应用?"
                 ok "是的"
            }
        }

        stage('07-G1-升级应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 7}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=symlink" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('08-G1-启动应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 8}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=start" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage("是否继续enable G1 dubbo?") {
            input {
                 message "是否继续enable G1 dubbo?"
                 ok "是的"
            }
            steps {
                echo "单独出来一个stage,解决pipeline parallel 与input冲突"
            }
        }

        stage('09-G1-上线应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <=9}
            }
            parallel {
                stage('09-G1-common') {
                    steps {
                        sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=1 --type=dubbo --action=enable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
                    }
                }
                stage('09-G1-notify') {
                    when {
                        expression {params.has_pay_notify_web == 'yes'}
                    }
                    steps {
                        echo "..."
                    }
                }
            }
        }

        stage('10-G2-分发程序包') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 10}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=getfile" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('11-G2-解压程序包') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 11}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=unpack" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
            input {
                 message "是否继续解压、禁dubbo?"
                 ok "是的"
            }
        }

        stage('12-G2-下线应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 12}
            }
            parallel {
                stage('12-G1-common') {
                    steps {
                        sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=dubbo --action=disable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
                    }
                }
                stage('12-G1-notify') {
                    when {
                        expression {params.has_pay_notify_web == 'yes'}
                    }
                    steps {
                        echo "..."
                    }
                }
            }

        }

        stage('13-G2-关闭应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 13}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=stop" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
            input {
                 message "是否继续升级、启动应用?"
                 ok "是的"
            }
        }

        stage('14-G2-升级应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 14}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=symlink" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage('15-G2-启动应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 15}
            }
            steps {
                sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=start" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
            }
        }

        stage("是否继续enable G2 dubbo?") {
            input {
                 message "是否继续enable G2 dubbo?"
                 ok "是的"
            }
            steps {
                echo "单独出来一个stage,解决pipeline parallel 与input冲突"
            }
        }

        stage('16-G2-上线应用') {
            when {
                expression {params.start_step.substring(0,2).toInteger() <= 16}
            }
            parallel {
                stage('16-G2-common') {
                    steps {
                        sh 'salt-ssh --force-color "esearch.prod.component-010177210122.sl" cmd.run "python release.py --app=soa --group=2 --type=dubbo --action=enable" cwd="/data/deploy/apps/sbin" runas=root --out=txt |awk -F\': \' \'{$1="";print}\''
                    }
                }
                stage('16-G2-notify') {
                    when {
                        expression {params.has_pay_notify_web == 'yes'}
                    }
                    steps {
                        echo "..."
                    }
                }
            }

        }

    }
}

(3)生产上有几个服务要经常重启,因此做了一个如下的东西,让开发自己去弄!

注意:

    借助python+saltstack+jenkins可以让很多动作实现半自动化,包括发版、系统初始化、扩容、服务启停等等,这些动作完全可以交给开发自己去操作,从而将我们运维的时间解放。
    如果要实现k8s的那种完全自动化扩容,在saltstack的基础上,写一个Daemon来收集性能数据,并根据一定的算法,也可以实现一个简单的定制的自动化扩容方案。
    本篇博文中pipeline是否专业的groovy编写,复杂用法有很多,可以参考groovy语法。

#!/usr/bin/env groovy
#coding:utf-8

properties([
    parameters([
        choice(choices: 'ali\ntengxun', description: '选择数据中心', name: 'idc_name'),
		choice(choices: '10.0.0.1\n10.0.0.2\n10.0.0.3\n10.0.0.4\n10.0.0.5\n10.0.0.6', description: '选择目标主机', name: 'target_host'),
		choice(choices: 'biz\ncanal\nhadoop\nindex\nsearch\nadmin\nrestapi', description: '选择要操作的服务名', name: 'target_service'),
		choice(choices: 'start\nstop\nrestart\nstatus', description: '选择操作类型', name: 'type_name')
	])
])

node {
    if ( params.idc_name == 'ali' ) {
        env.HOST = 'xxxxxxx.ali'
    } else if ( params.idc_name == 'tengxun' ) {
		env.HOST = 'yyyyyyy.tengxun'
    } else {
        echo "input error !!!!!!"
        sh "exit 1"
    }

	if ( params.target_host == '10.0.0.1' ) {
		env.TARGET_HOST = 'xxxxxxx.ali'
	} else if ( params.target_host == '10.0.0.2' ){
		env.TARGET_HOST = 'yyyyyyy.ali'
	} else if ( params.target_host == '10.0.0.3' ) {
		env.TARGET_HOST = 'zzzzzzz.ali'
	} else if ( params.target_host == '10.0.0.4' ) {
		env.TARGET_HOST = 'aaaaaaa.ali'
	} else if ( params.target_host == '10.0.0.5' ) {
		env.TARGET_HOST = 'bbbbbbb.tengxun'
	} else if ( params.target_host == '10.0.0.6' ) {
		env.TARGET_HOST = 'ccccccc.tengxun'
	} else {
        echo "input error !!!!!!"
        sh "exit 1"
    }

    //下面的转换其实不需要
	if ( params.target_service == "biz" ) {
		env.TARGET_SERVICE = "biz"
	} else if ( params.target_service == "canal" ) {
		env.TARGET_SERVICE = "canal"
	} else if ( params.target_service == "hadoop" ) {
		env.TARGET_SERVICE = "hadoop"
	} else if ( params.target_service == "index" ) {
		env.TARGET_SERVICE = "index"
	} else if ( params.target_service == "search" ) {
		env.TARGET_SERVICE = "search"
	} else if ( params.target_service == "admin" ) {
		env.TARGET_SERVICE = "admin"
	} else if ( params.target_service == "restapi" ) {
		env.TARGET_SERVICE = "restapi"
	} else {
        echo "input error !!!!!!"
        sh "exit 1"
    }


	if ( params.type_name == "start" ) {
		env.TYPE_NAME = "start"
	} else if ( params.type_name == "restart" ) {
		env.TYPE_NAME = "restart"
	} else if ( params.type_name == "stop" ) {
		env.TYPE_NAME = "stop"
	} else if ( params.type_name == "status" ) {
        env.TYPE_NAME = "status"
    } else {
        echo "input error !!!!!!"
        sh "exit 1"
    }

	stage ('tool') {
		wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
            #echo "${env.HOST}"
            #echo "${env.TARGET_HOST}"
            #echo "${env.TARGET_SERVICE}"
            #echo "${env.TYPE_NAME}"
            def type_cmd = "systemctl " + "${env.TYPE_NAME}" + " " + "${env.TARGET_SERVICE}"
            def remote_cmd = '"' + "salt" + " " + "${env.TARGET_HOST}" + " cmd.run " + "'${type_cmd}'" + '"'
            #echo "${type_cmd}"
            #echo "${remote_cmd}"
            sh "salt-ssh ${env.HOST} cmd.run ${remote_cmd}"
		}
	}

}

由于命令中层层嵌套,同时每层中都有变量,因此用字符串拼接的方式

salt-ssh yyyyyyy.tengxun cmd.run 'xxxxxxx.ali cmd.run '\''systemctl status canal'\'''

(4)search发版:

如下代码,当要进行流量切换时,想做成子流程,有待完善;另外下面的处理也比较粗糙。

#!/usr/bin/env groovy
#coding:utf-8

properties([
    parameters([
        choice(choices: 'yes\nno', description: '选择是否要进行流量切换?', name: 'net_flow'),
        choice(choices: 'ali\ntengxu', description: '选择要操作的机房?', name: 'idc_name'),
        choice(choices: '01-Group01-Close-Net_flow\n02-Commit Package to SVN\n03-Archive Package to Local DataCenter\n04-Group01-Getfile\n05-Group01-Unpack-Tarfile\n06-Group01-Stop_services\n07-Group01-Symlink\n08-Group01-Config\n09-Group01-Start_services\n10-Group01-Open-Net_flow\n11-Group02-Close-Net_flow\n12-Group02-Getfile\n13-Group02-Unpack-Tarfile\n14-Group02-Stop_services\n15-GroGroup02-Symlink\n16-Group02-Config\n17-Group02-Start_services\n18-Group02-Open-Net_flow', description: '选择开始步骤', name: 'start_step')
	])
])

node {
    //根据用户选择参数,判断salt-master主机名
    if ( params.idc_name == 'ali' ) {
        env.HOST = 'xxxxxxx.ali'
        env.REMOTE_PATH = '/root/tools/deploy/apps/sbin/apps'
    } else if ( params.idc_name == tengxun' ) {
		env.HOST = 'yyyyyyy.tengxun'
        env.REMOTE_PATH = '/data/deploy/apps/sbin/apps'
    } else {
        echo "input error !!!!!!"
        sh "exit 1"
    }

    if (1 >= params.start_step.substring(0,2).toInteger()) {
        //如果需要关闭第一组流量,这里关闭,否则此步不会进行实质性操作
        stage ('01-Group01-Close-Net_flow') {
            if (params.net_flow == "no") {
                echo "不用进行流量切换,此步将被忽略..."
            } else {
                //...待补充
                input '继续还是退出?'
            }
        }
    }


    if (2 >= params.start_step.substring(0,2).toInteger()) {
        //提交开发上传的工程包至发布SVN库,eg: python commit.py search sl
        stage ('02-Commit Package to SVN') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python commit.py search ${params.idc_name}" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (3 >= params.start_step.substring(0,2).toInteger()) {
        //从发布SVN库更新至本地数据中心,eg: python archive.py --app=search --idc=sl
        stage ('03-Archive Package to Local DataCenter') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python archive.py --app=search --idc=${params.idc_name}" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (4 >= params.start_step.substring(0,2).toInteger()) {
        //第一组拉取包到本地,eg: python release.py --app=search --idc=sl --group=1 --type=getfile
        stage ('04-Group01-Getfile') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=1 --type=getfile" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (5 >= params.start_step.substring(0,2).toInteger()) {
        //第一组解压拉取到本地的包,eg: python release.py --app=search --idc=sl --group=1 --type=unpack
        stage ('05-Group01-Unpack-Tarfile') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=1 --type=unpack" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (6 >= params.start_step.substring(0,2).toInteger()) {
        //第一组停止本地服务,eg:salt -N 'search-group1' state.sls release.search.stop saltenv=prod
        stage ('06-Group01-Stop_services') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group1' state.sls release.search.stop saltenv=prod" + '"'
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (7 >= params.start_step.substring(0,2).toInteger()) {
        //第一组打软链,eg:python release.py --app=search --idc=sl --group=1 --type=symlink
        stage ('07-Group01-Symlink') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=1 --type=symlink" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (8 >= params.start_step.substring(0,2).toInteger()) {
        //第一组修改配置,eg:salt -N 'search-group1' state.sls release.search.config saltenv=prod
        stage ('08-Group01-Config') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group1' state.sls release.search.config saltenv=prod" + '"'
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (9 >= params.start_step.substring(0,2).toInteger()) {
        //第一组服务启动,eg:salt -N 'search-group1' state.sls release.search.start saltenv=prod
        stage ('09-Group01-Start_services') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group1' state.sls release.search.start saltenv=prod" + '""'
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (10 >= params.start_step.substring(0,2).toInteger()) {
        //如果第一组流量关闭,此时打开
        stage ('10-Group01-Open-Net_flow') {
            if (params.net_flow == "no") {
                echo "不用进行流量切换,此步将被忽略..."
            } else {
                //...待补充
                input '继续还是退出?'
            }
        }
    }

    if (11 >= params.start_step.substring(0,2).toInteger()) {
        //如果需要切流量,此时关闭第二组流量
        stage ('11-Group02-Close-Net_flow') {
            if (params.net_flow == "no") {
                echo "不用进行流量切换,此步将被忽略..."
            } else {
                //...待补充
                input '继续还是退出?'
            }
        }
    }

    if (12 >= params.start_step.substring(0,2).toInteger()) {
        //第二组拉取包到本地,eg: python release.py --app=search --idc=sl --group=2 --type=getfile
        stage ('12-Group02-Getfile') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=2 --type=getfile" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (13 >= params.start_step.substring(0,2).toInteger()) {
        //第二组解压拉取到本地的包,eg: python release.py --app=search --idc=sl --group=2 --type=unpack
        stage ('13-Group02-Unpack-Tarfile') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=2 --type=unpack" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (14 >= params.start_step.substring(0,2).toInteger()) {
        //第二组停止本地服务,eg:salt -N 'search-group2' state.sls release.search.stop saltenv=prod
        stage ('14-Group02-Stop_services') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group2' state.sls release.search.stop saltenv=prod" + '"'
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (15 >= params.start_step.substring(0,2).toInteger()) {
        //第二组打软链,eg:python release.py --app=search --idc=sl --group=2 --type=symlink
        stage ('15-GroGroup02-Symlink') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = "'" + "python release.py --app=search --idc=${params.idc_name} --group=2 --type=symlink" + "'"
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (16 >= params.start_step.substring(0,2).toInteger()) {
        //第二组修改配置,eg:salt -N 'search-group2' state.sls release.search.config saltenv=prod
        stage ('16-Group02-Config') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group2' state.sls release.search.config saltenv=prod" + '"'
                sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (17 >= params.start_step.substring(0,2).toInteger()) {
        //第二组服务启动,eg:salt -N 'search-group2' state.sls release.search.start saltenv=prod
        stage ('17-Group02-Start_services') {
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
                def remote_cmd = '"' + "salt -N 'search-group2' state.sls release.search.start saltenv=prod" + '"'
                echo "${remote_cmd}"
                //sh "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                echo "salt-ssh ${env.HOST} --force-color cmd.run ${remote_cmd} cwd=${env.REMOTE_PATH} runas=root --out=txt"
                input '继续还是退出?'
            }
        }
    }

    if (18 >= params.start_step.substring(0,2).toInteger()) {
        //如果第二组流量关闭,打开
        stage ('18-Group02-Open-Net_flow') {
            if (params.net_flow == "no") {
                echo "不用进行流量切换,此步将被忽略..."
            } else {
                //待补充,暂时不进行自动流量切换
                input '继续还是退出?'
            }
        }
    }

}

(5)别人复杂的例子

另外附上github中的例子url:https://github.com/jenkinsci/pipeline-examples
官方基础steps的文档url:https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#catcherror-catch-error-and-set-build-result

例1——declarative方式:

pipeline {
    agent none

    parameters {
        string(name: 'BRANCH_TO_BUILD', defaultValue: "develop", description: 'GIT branch to build')
    }

    environment {
        GIT_URL = 'ssh://user@git/repo.git'
        BRANCH_TO_BUILD_DEFAULT = 'develop'
        BRANCH_TO_BUILD_REQUESTED = "${params.BRANCH_TO_BUILD}"
    }


    stage('Configure the build') {
        agent none
        steps {
            echo "Prompt user for a branch to build (default: ${BRANCH_TO_BUILD_DEFAULT})"
            script {
                try {
                    timeout(time:30, unit:'SECONDS') {
                    BRANCH_TO_BUILD_REQUESTED = input(
                        message: 'Input branch to build',
                        parameters: [
                                [$class: 'TextParameterDefinition',
                                 defaultValue: BRANCH_TO_BUILD_DEFAULT,
                                 description: 'Branch name', name: 'Enter branch name (or leave default) and press [Proceed]:']
                            ])
                        echo ("User has entered the branch name: " + BRANCH_TO_BUILD_REQUESTED)
                    }
                } catch(err) { // timeout reached or input Aborted
                    def user = err.getCauses()[0].getUser()
                        if('SYSTEM' == user.toString()) { // SYSTEM means timeout
                            echo ("Input timeout expired, default branch will be used: " + BRANCH_TO_BUILD_DEFAULT)
                            BRANCH_TO_BUILD_REQUESTED = BRANCH_TO_BUILD_DEFAULT
                        } else {
                            echo "Input aborted by: [${user}]"
                            error("Pipeline aborted by: [${user}]")
                        }
                }
            }
        }
    }

    stage('Checkout') {
        agent{node {label 'worker-1'}}

        steps {
            echo "Checkout will be done for Git branch: ${BRANCH_TO_BUILD_REQUESTED}"
            checkout([$class: 'GitSCM', branches: [[name: "*/${BRANCH_TO_BUILD_REQUESTED}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: ${GIT_URL]}]])
            }
    }

}

例2——scripted方式:

  • 这个例子在第一次看的时候,扫了一遍,感觉有点绕,就没有深究。后面耐下心来看了一遍,还真可以用来做scripted方式的并发,当然,比较复杂的并发,还是有点麻烦的。
// While you can't use Groovy's .collect or similar methods currently, you can
// still transform a list into a set of actual build steps to be executed in
// parallel.

// Our initial list of strings we want to echo in parallel
def stringsToEcho = ["a", "b", "c", "d"]

// The map we'll store the parallel steps in before executing them.
// collectEntries是groovy中列表的生成map的一个方法
def stepsForParallel = stringsToEcho.collectEntries {
    ["echoing ${it}" : transformIntoStep(it)]
}
// 这个map的key其实就是并发的step的名称
// value其实就是并发要执行的命令,如果要某个step中要执行多个步骤,比如:
// 修改nginx、测试nginx、重启nginx,那这个还是要费一番手脚的


// Actually run the steps in parallel - parallel takes a map as an argument,
// hence the above.
parallel stepsForParallel  // 执行并发

// Take the string and echo it.
def transformIntoStep(inputString) {
    // We need to wrap what we return in a Groovy closure, or else it's invoked
    // when this method is called, not when we pass it to parallel.
    // To do this, you need to wrap the code below in { }, and either return
    // that explicitly, or use { -> } syntax.
    return {
        node {
            echo inputString
        }
    }
}

再看看别人的例子就明了了:
参考:stackoverflow.com

def buildJob(jobName){
    echo "${jobName} will be built."
}

node {

    map = [:]
    projects = ['project1-dev', 'project2-dev', 'project1-qa', 'project2-qa', 'project1-pp', 'project2-pp']

    stage ('Build') {
        for (project in projects) {
            map[project] = { buildJob("'${project}'") }
        }

        parallel map
    }
}

2、使用注意事项

(1)jenkins编译打包java时,要在jenkins中配置jdk

另外jenkins和sonar集成时也要依赖这个配置

(2)颜色相关

由于结果有一些是有颜色的,这时可以使用jenkins的AnsiColor插件
参考:
https://wiki.jenkins.io/display/JENKINS/AnsiColor+Plugin
https://github.com/jenkinsci/ansicolor-plugin

pipeline中:   #将输出结果的命令放入wrap命令块中
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
    sh 'salt-ssh "xxxxxxx.ali" cmd.run "python commit.py --app=soa" cwd="/data/deploy/apps/sbin" runas=root'
    //这里我们当时用的是febric的颜色控制,返回的不是标准的格式??还是怎么回事呢???
    //标准的格式是echo -e "\033[31m ERROR: 当前已是最新版,请确认是否上传工程包! \033[0m"因此也就这样了
    //或者echo -e "\e[31m ERROR: 当前已是最新版,请确认是否上传工程包! \e[0m"
}
或者
ansiColor('xterm') {
    echo 'something that outputs ansi colored stuff'
}

当时设置经过:

加上salt-ssh命令加上--force-color参数,可以显示salt-ssh执行后的颜色,但是无法正常显示远程终端的颜色
# salt-ssh "xxxxxxx.ali" cmd.run "echo -e \"\033[31mERROR: 当前已是最新版,请确认是否上传工程包!\033[0m\"" runas=root
xxxxxxx.ali:
    ?[31mERROR: 当前已是最新版,请确认是否上传工程包!?[0m
结果是salt-ssh执行成功的绿色,而不是命令的结果红色

salt-ssh 加一个参数--out=txt这样可以jenkins pipeline中可以显示颜色,但是格式又不是很好,blue ocean还是没有颜色。
最后结合shell脚本的管道,过滤掉第一列数据,就好很多了。

(3)有一次jenkins构建pipeline任务时,清空了workspace导致构建任务失败:

jenkins启动相关属性,必须在-jar之前,才能生效,否则会被忽略
https://wiki.jenkins.io/display/JENKINS/Features+controlled+by+system+properties

hudson.model.WorkspaceCleanupThread.disabled
hudson.model.WorkspaceCleanupThread.recurrencePeriodHours
hudson.model.WorkspaceCleanupThread.retainForDays
看/etc/sysconfig/jenkins中配置:
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true -Dhudson.DNSMultiCast.disabled=true -Dhudson.model.WorkspaceCleanupThread.recurrencePeriodHours=168"

jenkins启动参数查看
java -jar jenkins.jar --help

注意:
如果是关闭了workspace清空线程,那么如何清空工作目录呢
pipeline {
    agent any
    stages {
        stage('No-op') {
            steps {
                sh 'ls'
            }
        }
    }
    post {
        always {
            echo 'One way or another, I have finished'
            deleteDir() /* clean up our workspace */
        }
    }
}

另外有一个workspace清空插件可以用

(4)jenkins的input用法:

https://stackoverflow.com/questions/37831386/jenkins-pipeline-input-step-blocks-executor

node() {
  stage 'Build to Stage' {
    sh '# ...'
  }

  stage 'Promotion' {
    timeout(time: 1, unit: 'HOURS') {
      input 'Deploy to Production?'
    }
  }

  stage 'Deploy to Production' {
    sh '# ...'
  }
}

(5)lock方法:

You have to use the input step outside any node block, so it does not hold any executor:

stage 'Build'
node('build-node') {
  sh 'call you build tool'
  stash includes: 'target/my-output-artifact.whatever', name: 'built'
}

input 'Continue to deploy stage?'

stage 'Deploy'
node('deploy-node') {
  unstash 'built'
  sh 'scp target/my-output-artifact.whatever user@deploy-server:/deploy'
}
And you can lock the deploy stage if you want only one deploy at time:

lock ('deploy-server') {
  stage 'Deploy'
  node('deploy-node') {
    unstash 'built'
    sh 'scp target/my-output-artifact.whatever user@deploy-server:/deploy'
  }
}

(6)常用的其他插件

  • Build Timestamp (每次运行添加时间标签)
  • execute python script
  • Progress Bar Column( jenkins界面优化)
  • Schedule Build
  • Build View Column ( jenkins界面优化)
  • Parameter Separator
  • 注意:
    • 一般解决CICD碰到一些问题或者没有灵感时去插件中整个撸一遍,一般都能有所收获

3、自动化开发相关的东西

(1)jenkins job builder可以将job创建变得模板化和脚本化,给你不一样的job规模化job管理

待补充

(2)自动化相关

a、获取构建结果(SUCCESS/FAIL)

获取某一个构建版本号为6的构建结果:
curl http://192.168.165.214:8081/job/pro-ljj_mir-ljj/6/api/xml --user admin:123456
获取最后一次构建的构建结果:
curl http://192.168.165.214:8081/job/pro-ljj_mir-ljj/lastBuild/api/xml --user admin:123456
获取最后一次构建的版本号:
curl  http://192.168.165.214:8081/job/laijinjie-pro_laijinjie-mir/lastBuild/buildNumber --user admin:123456
获取某个项目所以构建版本号的结果;
curl  http://192.168.165.214:8081/job/pro-ljj_mir-ljj/api/xml --user admin:123456
以上pro-ljj_mir-ljj为项目名称,最后的是账号密码。

b、jenkins的cli客户端

参考:https://www.w3cschool.cn/jenkins/jenkins-zh3e28mj.html

wget https://JENKINS_URL/jnlpJars/jenkins-cli.jar   #jenkins服务器自己就提供了
使用:java -jar jenkins-cli.jar [-s JENKINS_URL] [global options...] command [command options...] [arguments...]
客户端连接模式
有三种基本模式,其中可以使用本2.54+ / 2.46.2+客户端,通过全局选项可选择的: -http; -ssh; 和-remoting。

http模式:
java -jar jenkins-cli.jar [-s JENKINS_URL] -auth kohsuke:abc1234ffe4a command ...
获取单个job的输出:
java -jar ./jenkins-cli.jar -s http://10.4.4.67:8080/ -auth admin:xKHIBxHkrTE console java-ejob 28

# java -jar ./jenkins-cli.jar -s http://10.4.4.67:8080/ -auth admin:xKHIBxHkrTE console --help
ERROR: "--help" is not a valid option
java -jar jenkins-cli.jar console JOB [BUILD] [-f] [-n N] [--username VAL] [--password VAL] [--password-file VAL]
Produces the console output of a specific build to stdout, as if you are doing 'cat build.log'
 JOB                 : Name of the job
 BUILD               : Build number or permalink to point to the build.
                       Defaults to the last build
 -f                  : If the build is in progress, stay around and append     //正在执行的job
                       console output as it comes, like 'tail -f'
 -n N                : Display the last N lines
 --username VAL      : User name to authenticate yourself to Jenkins
 --password VAL      : Password for authentication. Note that passing a
                       password in arguments is insecure.
 --password-file VAL : File that contains the password
当日志中有颜色时,可以用sed进行处理:
# cat 76.log |sed 's/ha.*==//g'|sed 's/ha.*=//g'
eg:
# java -jar ./jenkins-cli.jar -s http://10.4.4.67:8080/ -auth admin:xKHIBxHkrTE console SOA-Deploy-Level01 |sed 's/ha.*==//g'|sed 's/ha.*=//g'|sed 's/ha.*AAAA//g'

更多详细用法:

# java -jar ./jenkins-cli.jar -s http://10.4.4.67:8080/ -auth admin:xKHIBxHkrTE help
  add-job-to-view
    Adds jobs to view.
  build
    Builds a job, and optionally waits until its completion.
  cancel-quiet-down
    Cancel the effect of the "quiet-down" command.
  clear-queue
    Clears the build queue.
  connect-node
    Reconnect to a node(s)
  console
    Retrieves console output of a build.
  copy-job
    Copies a job.
  create-credentials-by-xml
    Create Credential by XML
  create-credentials-domain-by-xml
    Create Credentials Domain by XML
  create-job
    Creates a new job by reading stdin as a configuration XML file.
  create-node
    Creates a new node by reading stdin as a XML configuration.
  create-view
    Creates a new view by reading stdin as a XML configuration.
  declarative-linter
    Validate a Jenkinsfile containing a Declarative Pipeline
  delete-builds
    Deletes build record(s).
  delete-credentials
    Delete a Credential
  delete-credentials-domain
    Delete a Credentials Domain
  delete-job
    Deletes job(s).
  delete-node
    Deletes node(s)
  delete-view
    Deletes view(s).
  disable-job
    Disables a job.
  disconnect-node
    Disconnects from a node.
  enable-job
    Enables a job.
  get-credentials-as-xml
    Get a Credentials as XML (secrets redacted)
  get-credentials-domain-as-xml
    Get a Credentials Domain as XML
  get-job
    Dumps the job definition XML to stdout.
  get-node
    Dumps the node definition XML to stdout.
  get-view
    Dumps the view definition XML to stdout.
  groovy
    Executes the specified Groovy script.
  groovysh
    Runs an interactive groovy shell.
  help
    Lists all the available commands or a detailed description of single command.
  install-plugin
    Installs a plugin either from a file, an URL, or from update center.
  install-tool
    Performs automatic tool installation, and print its location to stdout. Can be only called from inside a build. [deprecated]
  keep-build
    Mark the build to keep the build forever.
  list-changes
    Dumps the changelog for the specified build(s).
  list-credentials
    Lists the Credentials in a specific Store
  list-credentials-context-resolvers
    List Credentials Context Resolvers
  list-credentials-providers
    List Credentials Providers
  list-jobs
    Lists all jobs in a specific view or item group.
  list-plugins
    Outputs a list of installed plugins.
  login
    Saves the current credentials to allow future commands to run without explicit credential information. [deprecated]
  logout
    Deletes the credentials stored with the login command. [deprecated]
  mail
    Reads stdin and sends that out as an e-mail.
  offline-node
    Stop using a node for performing builds temporarily, until the next "online-node" command.
  online-node
    Resume using a node for performing builds, to cancel out the earlier "offline-node" command.
  quiet-down
    Quiet down Jenkins, in preparation for a restart. Don’t start any builds.
  reload-configuration
    Discard all the loaded data in memory and reload everything from file system. Useful when you modified config files directly on disk.
  reload-job
    Reload job(s)
  remove-job-from-view
    Removes jobs from view.
  replay-pipeline
    Replay a Pipeline build with edited script taken from standard input
  restart
    Restart Jenkins.
  safe-restart
    Safely restart Jenkins.
  safe-shutdown
    Puts Jenkins into the quiet mode, wait for existing builds to be completed, and then shut down Jenkins.
  session-id
    Outputs the session ID, which changes every time Jenkins restarts.
  set-build-description
    Sets the description of a build.
  set-build-display-name
    Sets the displayName of a build.
  set-build-parameter
    Update/set the build parameter of the current build in progress. [deprecated]
  set-build-result
    Sets the result of the current build. Works only if invoked from within a build. [deprecated]
  set-external-build-result
    Set external monitor job result.
  shutdown
    Immediately shuts down Jenkins server.
  update-credentials-by-xml
    Update Credentials by XML
  update-credentials-domain-by-xml
    Update Credentials Domain by XML
  update-job
    Updates the job definition XML from stdin. The opposite of the get-job command.
  update-node
    Updates the node definition XML from stdin. The opposite of the get-node command.
  update-view
    Updates the view definition XML from stdin. The opposite of the get-view command.
  version
    Outputs the current version.
  wait-node-offline
    Wait for a node to become offline.
  wait-node-online
    Wait for a node to become online.
  who-am-i
    Reports your credential and permissions.

另外jenkins本身提供xml api,json api,python api
参考:https://www.cnblogs.com/zjsupermanblog/archive/2017/07/26/7238422.html

http://10.0.0.7:8080/api/
某个job的api借口:http://10.0.0.7:8080/job/ejob/api/
eg:curl 'http://10.0.0.7:8080/job/ejob/lastBuild/api/json?pretty=true&tree=result' --user admin:12345678
tree是用来过滤结果的
或者直接使用第三方模块https://pypi.python.org/pypi/python-jenkins/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值