jenkins as code 與go語言學習

來源:互聯網
上載者:User

標籤:傳參數   deploy   應用   運行   bool   ring   控制   dir   item   

前言

最近看jenkins as code這個概念在很多文章中提起,持續傳遞中八大原則也有把一切都放入版本管理,最近準備把我們公司用的一些jenkins上的job的配置也放到git中,由於https://github.com/jenkinsci/job-dsl-plugin的支援是groovy。我不懂groovy,所以找了一些網上的groovy指令碼改了改,並且通過go template實現這個模板,還能練習使用go。

所有用的到檔案簡介

一共用到3個檔案,只有一個模板,如果有多個情景可以多寫幾個模板

bogon:jenkins-dsl hongzhi.wang$ tree.├── config.yaml   #設定檔├── generate_dsl.go #go 源碼檔案└── springboot.tpl #go template 檔案
設定檔

這次準備通過yaml檔案實現模板的渲染,設定檔如下,通過yaml來設定檔比較清晰。

- department_name: java  cn_name: java組  apps:    - app_name: app-1      nodes:        - node1        - node2        - node3      ansible_playbook_name: deploy-springboot-jar.yml      jvm_size: 2048m      template_name: springboot.tpl    - app_name: app-2      nodes:        - node1        - node2        - node3      ansible_playbook_name: deploy-springboot-jar.yml      jvm_size: 512m      template_name: springboot.tpl- department_name: java2  cn_name: java2組  apps:    - app_name: app-4      nodes:        - node1        - node2        - node3      ansible_playbook_name: deploy-springboot-war.yml      jvm_size: 2048m      template_name: springboot.tpl
GO Template

這裡面主要是用到了自定函數ProcessNodes,其他的都是模板的正常用法,還有就是我們的jenkins主要是傳參數拉代碼,然後通過ansible-playbook實現應用部署。

def app_name = ‘{{ .App.AppName }}‘def gitUrl = "[email protected]:{{ .Name }}/{{ .App.AppName }}.git"job("{{ .Name }}-${app_name}") {description()keepDependencies(false)parameters {choiceParam("Mode", ["release", "deploy"], "")choiceParam("app_name", ["${app_name}"], "")choiceParam("NODES", {{ ProcessNodes .App.Nodes }}, "")gitParam(‘VERSION‘) {sortMode(‘DESCENDING‘)tagFilter(‘*‘)}}scm {git {remote {url(gitUrl)credentials("git")}branch("\$VERSION")}}disabled(false)concurrentBuild(false)steps {maven{configure { node ->node / ‘mavenName‘ (‘maven‘)}goals(‘clean‘)}maven{configure { node ->node / ‘mavenName‘ (‘maven‘)}goals(‘install -Pproduct‘)}shell("""source /opt/py3/bin/activateif [ \$Mode == release ]thenSTART_TASK="copy app code"fiecho \$JOB_NAMEcd /ansible/echo \$WORKSPACEfor host in \$NODESdoansible-playbook --start-at-task="\$START_TASK" {{ .App.AnsiblePlaybookName }} --extra-vars "target_host=\$host workspace=\$WORKSPACE app_name=\$app_name version=\$VERSION  jvm_size={{ .App.JvmSize }}"done""")}}listView("{{ .CnName }}") {jobs {regex(/{{ .Name }}-.+/)}columns {status()weather()name()lastSuccess()lastFailure()lastDuration()buildButton()}}
GO源碼

這個源碼主要按照設定檔,把已經去掉的部門目錄還有應用groovy指令碼給刪了,並且推送到遠程分支,groovy指令碼的名字裡面不能有-,因為groovy的指令碼名字會解析成java的類名,-是不能放在java語言的類名裡面了。所以只能把應用程式名稱字都的-轉成_

package mainimport (    "io/ioutil"    "github.com/ghodss/yaml"    "fmt"    "text/template"    "os"    "log"    "strings"    "os/exec"    "bytes")type Department struct {    Name string `json:"department_name"`    CnName string `json:"cn_name"`    Apps []App `json:"apps"`}type App struct {    AppName string `json:"app_name"`    Nodes []string `json:"nodes"`    PythonVersion string `json:"python_version"`    JvmSize string `json:"jvm_size"`    TemplateName string `json:"template_name"`    AnsiblePlaybookName string `json:"ansible_playbook_name"`    DestPath string `json:"dest_path"`    TomcatGitUrl string `json:"tomcat_git_url"`    TomcatPort string `json:"tomcat_port"`    TomcatAdminPort string `json:"tomcat_admin_port"`    TomcatName string `json:"tomcat_name"`    TomcatWebApp string `json:"tomcat_web_app"`}func In(i string,l []string) bool{    for _, item:= range l{        if item == i{            return true        }    }    return false}func checkErr(err error)  {    if err != nil{        log.Fatal(err)    }}func ProcessNodes(l []string) string {    if len(l) == 1{        return fmt.Sprintf(`["%s"]`,strings.Join(l," "))    }    return fmt.Sprintf(`["%s","%s"]`,l[0],strings.Join(l," "))}func AppNameToFileName(appname string) string {    appname = strings.Replace(appname,"-","_",-1)    return fmt.Sprintf("%s.groovy",appname)}func SysCommand(command string){    commandList := strings.Fields(command)    var out bytes.Buffer    cmd := exec.Command(commandList[0],commandList[1:]...)    cmd.Stdout = &out    cmd.Stderr = &out    err := cmd.Run()    if err != nil{        log.Printf("commd error: %v",command)    }    log.Println(out.String())}func main()  {    content,err := ioutil.ReadFile("config.yaml")    checkErr(err)    var d []Department    err = yaml.Unmarshal(content, &d)    checkErr(err)    DepartmentNames := []string{}    funcMap := template.FuncMap{        "ProcessNodes": ProcessNodes,    }    for _, department := range d{        err := os.MkdirAll(department.Name,0755)        checkErr(err)        DepartmentNames = append(DepartmentNames, department.Name)        if AppFileNames := []string{}; department.Apps != nil{            for _, app := range department.Apps{                FileName :=  AppNameToFileName(app.AppName)                AppFileNames = append(AppFileNames,FileName)                data := map[string]interface{}{                    "Name":department.Name,                    "CnName":department.CnName,                    "App":app,                }                templ,err := template.New(app.TemplateName).Funcs(funcMap).ParseFiles(app.TemplateName)                checkErr(err)                f, err := os.Create(fmt.Sprintf("%s/%s",department.Name, FileName))                defer f.Close()                checkErr(err)                err = templ.Execute(f, data)                checkErr(err)            }            ExistFiles,err := ioutil.ReadDir(department.Name)            checkErr(err)            for _,v := range ExistFiles{                if ! In(v.Name(),AppFileNames){                    log.Println("going to delete file: ",v.Name())                    SysCommand(fmt.Sprintf("git rm %s/%s",department.Name,v.Name()))                }            }        }    }    ExistDirs,err := ioutil.ReadDir("./")    checkErr(err)    for _,dir := range ExistDirs{        if dir.IsDir()&& dir.Name()!=".idea" && dir.Name()!=".git" &&  ! In(dir.Name(),DepartmentNames){            log.Println("going to delete dir: ",dir.Name())            log.Printf("git rm -r %s\n",dir.Name())            SysCommand(fmt.Sprintf("git rm -r %s",dir.Name()))            checkErr(err)        }    }    SysCommand("git add * ")    SysCommand("git commit -m ‘update‘ ")    //SysCommand("git push ")    log.Println("finished")}

templ,err := template.New(app.TemplateName).Funcs(funcMap).ParseFiles(app.TemplateName)這個之所以這樣是因為要傳入自定的函數,parsefile的傳回值是兩個不能直接用Funcs。這個就要詳見Stack Overflow上的答案了。

指令碼啟動並執行結果
bogon:jenkins-dsl hongzhi.wang$ go run generate_dsl.go bogon:jenkins-dsl hongzhi.wang$ tree.├── config.yaml├── generate_dsl.go├── java│   ├── app_1.groovy│   └── app_2.groovy├── java2│   └── app_4.groovy└── springboot.tpl
剩餘的工作

這個指令碼把程式碼推送到gitlab之後,gitlab通過webhook觸發一個jenkins-seed-job,這個job再運行groovy指令碼,這個groovy指令碼裡面記得把已經存在的刪了,我們是一個部門對應一個jenkins-seed-job,一個webhook。如果config.yaml太大了,可以把一些部門的配置放到另一個源碼庫裡。

steps {        dsl {            ignoreExisting(false)            removeAction("DELETE")            removeViewAction("IGNORE")            lookupStrategy("JENKINS_ROOT")        }    }
總結

這次主要是把jenkins的job管理納入版本控制,並且練習一下go。這裡主要是做個筆記o( ̄︶ ̄)o。

jenkins as code 與go語言學習

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.