package jenkins import ( "encoding/json" "github.com/PuerkitoBio/goquery" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/simple/client/devops" "net/http" "net/url" "strings" "time" ) type Pipeline struct { HttpParameters *devops.HttpParameters Jenkins *Jenkins Path string } const ( GetPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/" ListPipelinesUrl = "/blue/rest/search/?" GetPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/" ListPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/?" StopPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/stop/?" ReplayPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/replay/" RunPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/" GetArtifactsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/artifacts/?" GetRunLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/log/?" GetStepLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/%s/log/?" GetPipelineRunNodesUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/?" SubmitInputStepUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/%s/" GetNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/?" GetBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/" GetBranchPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/" StopBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/stop/?" ReplayBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/replay/" RunBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/" GetBranchArtifactsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/artifacts/?" GetBranchRunLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/log/?" GetBranchStepLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/%s/log/?" GetBranchNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/?" GetBranchPipeRunNodesUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/?" CheckBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/%s/" GetPipeBranchUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/?" ScanBranchUrl = "/job/%s/job/%s/build?" GetConsoleLogUrl = "/job/%s/job/%s/indexing/consoleText" GetCrumbUrl = "/crumbIssuer/api/json/" GetSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/" GetSCMOrgUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/?" GetOrgRepoUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/%s/repositories/?" CreateSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/" ValidateUrl = "/blue/rest/organizations/jenkins/scm/%s/validate" GetNotifyCommitUrl = "/git/notifyCommit/?" GithubWebhookUrl = "/github-webhook/" CheckScriptCompileUrl = "/job/%s/job/%s/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile" CheckPipelienCronUrl = "/job/%s/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=%s" CheckCronUrl = "/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=%s" ToJenkinsfileUrl = "/pipeline-model-converter/toJenkinsfile" ToJsonUrl = "/pipeline-model-converter/toJson" cronJobLayout = "Monday, January 2, 2006 15:04:05 PM" ) func (p *Pipeline) GetPipeline() (*devops.Pipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var pipeline devops.Pipeline err = json.Unmarshal(res, &pipeline) if err != nil { klog.Error(err) return nil, err } return &pipeline, err } func (p *Pipeline) ListPipelines() (*devops.PipelineList, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } count, err := p.searchPipelineCount() if err != nil { klog.Error(err) return nil, err } pipelienList := devops.PipelineList{Total: count} err = json.Unmarshal(res, &pipelienList.Items) if err != nil { klog.Error(err) return nil, err } return &pipelienList, err } func (p *Pipeline) searchPipelineCount() (int, error) { query, _ := parseJenkinsQuery(p.HttpParameters.Url.RawQuery) query.Set("start", "0") query.Set("limit", "1000") query.Set("depth", "-1") formatUrl := ListPipelinesUrl + query.Encode() res, err := p.Jenkins.SendPureRequest(formatUrl, p.HttpParameters) if err != nil { klog.Error(err) return 0, err } var pipelines []devops.Pipeline err = json.Unmarshal(res, &pipelines) if err != nil { klog.Error(err) return 0, err } return len(pipelines), nil } func (p *Pipeline) GetPipelineRun() (*devops.PipelineRun, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var pipelineRun devops.PipelineRun err = json.Unmarshal(res, &pipelineRun) if err != nil { klog.Error(err) return nil, err } return &pipelineRun, err } func (p *Pipeline) ListPipelineRuns() (*devops.PipelineRunList, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var pipelineRunList devops.PipelineRunList err = json.Unmarshal(res, &pipelineRunList.Items) if err != nil { klog.Error(err) return nil, err } total, err := p.searchPipelineRunsCount() if err != nil { klog.Error(err) return nil, err } pipelineRunList.Total = total return &pipelineRunList, err } func (p *Pipeline) searchPipelineRunsCount() (int, error) { query, _ := parseJenkinsQuery(p.HttpParameters.Url.RawQuery) query.Set("start", "0") query.Set("limit", "1000") query.Set("depth", "-1") p.HttpParameters.Url.RawQuery = query.Encode() u, err := url.Parse(p.Path) if err != nil { return 0, err } res, err := p.Jenkins.SendPureRequest(u.Path, p.HttpParameters) if err != nil { klog.Error(err) return 0, err } var runs []devops.PipelineRun err = json.Unmarshal(res, &runs) if err != nil { klog.Error(err) return 0, err } return len(runs), nil } func (p *Pipeline) StopPipeline() (*devops.StopPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var stopPipeline devops.StopPipeline err = json.Unmarshal(res, &stopPipeline) if err != nil { klog.Error(err) return nil, err } return &stopPipeline, err } func (p *Pipeline) ReplayPipeline() (*devops.ReplayPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var replayPipeline devops.ReplayPipeline err = json.Unmarshal(res, &replayPipeline) if err != nil { klog.Error(err) return nil, err } return &replayPipeline, err } func (p *Pipeline) RunPipeline() (*devops.RunPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var runPipeline devops.RunPipeline err = json.Unmarshal(res, &runPipeline) if err != nil { klog.Error(err) return nil, err } return &runPipeline, err } func (p *Pipeline) GetArtifacts() ([]devops.Artifacts, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var artifacts []devops.Artifacts err = json.Unmarshal(res, &artifacts) if err != nil { klog.Error(err) return nil, err } return artifacts, err } func (p *Pipeline) GetRunLog() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetStepLog() ([]byte, http.Header, error) { res, header, err := p.Jenkins.SendPureRequestWithHeaderResp(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, header, err } func (p *Pipeline) GetNodeSteps() ([]devops.NodeSteps, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } var nodeSteps []devops.NodeSteps err = json.Unmarshal(res, &nodeSteps) if err != nil { klog.Error(err) return nil, err } return nodeSteps, err } func (p *Pipeline) GetPipelineRunNodes() ([]devops.PipelineRunNodes, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var pipelineRunNodes []devops.PipelineRunNodes err = json.Unmarshal(res, &pipelineRunNodes) if err != nil { klog.Error(err) return nil, err } return pipelineRunNodes, err } func (p *Pipeline) SubmitInputStep() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetBranchPipeline() (*devops.BranchPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchPipeline devops.BranchPipeline err = json.Unmarshal(res, &branchPipeline) if err != nil { klog.Error(err) return nil, err } return &branchPipeline, err } func (p *Pipeline) GetBranchPipelineRun() (*devops.PipelineRun, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchPipelineRun devops.PipelineRun err = json.Unmarshal(res, &branchPipelineRun) if err != nil { klog.Error(err) return nil, err } return &branchPipelineRun, err } func (p *Pipeline) StopBranchPipeline() (*devops.StopPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchStopPipeline devops.StopPipeline err = json.Unmarshal(res, &branchStopPipeline) if err != nil { klog.Error(err) return nil, err } return &branchStopPipeline, err } func (p *Pipeline) ReplayBranchPipeline() (*devops.ReplayPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchReplayPipeline devops.ReplayPipeline err = json.Unmarshal(res, &branchReplayPipeline) if err != nil { klog.Error(err) return nil, err } return &branchReplayPipeline, err } func (p *Pipeline) RunBranchPipeline() (*devops.RunPipeline, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchRunPipeline devops.RunPipeline err = json.Unmarshal(res, &branchRunPipeline) if err != nil { klog.Error(err) return nil, err } return &branchRunPipeline, err } func (p *Pipeline) GetBranchArtifacts() ([]devops.Artifacts, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var artifacts []devops.Artifacts err = json.Unmarshal(res, &artifacts) if err != nil { klog.Error(err) return nil, err } return artifacts, err } func (p *Pipeline) GetBranchRunLog() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetBranchStepLog() ([]byte, http.Header, error) { res, header, err := p.Jenkins.SendPureRequestWithHeaderResp(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, header, err } func (p *Pipeline) GetBranchNodeSteps() ([]devops.NodeSteps, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchNodeSteps []devops.NodeSteps err = json.Unmarshal(res, &branchNodeSteps) if err != nil { klog.Error(err) return nil, err } return branchNodeSteps, err } func (p *Pipeline) GetBranchPipelineRunNodes() ([]devops.BranchPipelineRunNodes, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var branchPipelineRunNodes []devops.BranchPipelineRunNodes err = json.Unmarshal(res, &branchPipelineRunNodes) if err != nil { klog.Error(err) return nil, err } return branchPipelineRunNodes, err } func (p *Pipeline) SubmitBranchInputStep() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetPipelineBranch() (*devops.PipelineBranch, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var pipelineBranch devops.PipelineBranch err = json.Unmarshal(res, &pipelineBranch) if err != nil { klog.Error(err) return nil, err } return &pipelineBranch, err } func (p *Pipeline) ScanBranch() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetConsoleLog() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GetCrumb() (*devops.Crumb, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var crumb devops.Crumb err = json.Unmarshal(res, &crumb) if err != nil { klog.Error(err) return nil, err } return &crumb, err } func (p *Pipeline) GetSCMServers() ([]devops.SCMServer, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var SCMServer []devops.SCMServer err = json.Unmarshal(res, &SCMServer) if err != nil { klog.Error(err) return nil, err } return SCMServer, err } func (p *Pipeline) GetSCMOrg() ([]devops.SCMOrg, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var SCMOrg []devops.SCMOrg err = json.Unmarshal(res, &SCMOrg) if err != nil { klog.Error(err) return nil, err } return SCMOrg, err } func (p *Pipeline) GetOrgRepo() (devops.OrgRepo, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return devops.OrgRepo{}, err } var OrgRepo devops.OrgRepo err = json.Unmarshal(res, &OrgRepo) if err != nil { klog.Error(err) return devops.OrgRepo{}, err } return OrgRepo, err } func (p *Pipeline) CreateSCMServers() (*devops.SCMServer, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var SCMServer devops.SCMServer err = json.Unmarshal(res, &SCMServer) if err != nil { klog.Error(err) return nil, err } return &SCMServer, err } func (p *Pipeline) GetNotifyCommit() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) GithubWebhook() ([]byte, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) } return res, err } func (p *Pipeline) Validate() (*devops.Validates, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var validates devops.Validates err = json.Unmarshal(res, &validates) if err != nil { klog.Error(err) return nil, err } return &validates, err } func (p *Pipeline) CheckScriptCompile() (*devops.CheckScript, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } // Jenkins will return different struct according to different results. var checkScript devops.CheckScript ok := json.Unmarshal(res, &checkScript) if ok != nil { var resJson []*devops.CheckScript err := json.Unmarshal(res, &resJson) if err != nil { klog.Error(err) return nil, err } return resJson[0], nil } return &checkScript, err } func (p *Pipeline) CheckCron() (*devops.CheckCronRes, error) { var res = new(devops.CheckCronRes) Url, err := url.Parse(p.Jenkins.Server + p.Path) reqJenkins := &http.Request{ Method: http.MethodGet, URL: Url, Header: p.HttpParameters.Header, } client := &http.Client{Timeout: 30 * time.Second} resp, err := client.Do(reqJenkins) if resp != nil && resp.StatusCode != http.StatusOK { resBody, _ := getRespBody(resp) return &devops.CheckCronRes{ Result: "error", Message: string(resBody), }, err } if err != nil { klog.Error(err) return nil, err } defer resp.Body.Close() doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { klog.Error(err) return nil, err } doc.Find("div").Each(func(i int, selection *goquery.Selection) { res.Message = selection.Text() res.Result, _ = selection.Attr("class") }) if res.Result == "ok" { res.LastTime, res.NextTime, err = parseCronJobTime(res.Message) if err != nil { klog.Error(err) return nil, err } } return res, err } func parseCronJobTime(msg string) (string, string, error) { times := strings.Split(msg, ";") lastTmp := strings.Split(times[0], " ") lastCount := len(lastTmp) lastTmp = lastTmp[lastCount-7 : lastCount-1] lastTime := strings.Join(lastTmp, " ") lastUinx, err := time.Parse(cronJobLayout, lastTime) if err != nil { klog.Error(err) return "", "", err } last := lastUinx.Format(time.RFC3339) nextTmp := strings.Split(times[1], " ") nextCount := len(nextTmp) nextTmp = nextTmp[nextCount-7 : nextCount-1] nextTime := strings.Join(nextTmp, " ") nextUinx, err := time.Parse(cronJobLayout, nextTime) if err != nil { klog.Error(err) return "", "", err } next := nextUinx.Format(time.RFC3339) return last, next, nil } func (p *Pipeline) ToJenkinsfile() (*devops.ResJenkinsfile, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var jenkinsfile devops.ResJenkinsfile err = json.Unmarshal(res, &jenkinsfile) if err != nil { klog.Error(err) return nil, err } return &jenkinsfile, err } func (p *Pipeline) ToJson() (*devops.ResJson, error) { res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters) if err != nil { klog.Error(err) return nil, err } var toJson devops.ResJson err = json.Unmarshal(res, &toJson) if err != nil { klog.Error(err) return nil, err } return &toJson, err }