diff --git a/app/cmd/center.go b/app/cmd/center.go index 379f21a8a0222047ceef6358ccc2fdf2a4e06364..c5c009eb8f8b8d94723c8f45fb4915ffdb6aae4f 100644 --- a/app/cmd/center.go +++ b/app/cmd/center.go @@ -48,6 +48,8 @@ func printUpdateCenter(jenkins *JenkinsServer) { jclient.URL = jenkins.URL jclient.UserName = jenkins.UserName jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth var centerStatus string if status, err := jclient.Status(); err == nil { @@ -77,6 +79,8 @@ func printJenkinsStatus(jenkins *JenkinsServer) { jclient.URL = jenkins.URL jclient.UserName = jenkins.UserName jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth if status, err := jclient.Get(); err == nil { fmt.Println("Jenkins Version:", status.Version) diff --git a/app/cmd/config.go b/app/cmd/config.go index c4098c480343df1308f28e12128d9fb0bb85c2a8..df3b38939e4a332fd1423b4d15e39478a4ca9cc1 100644 --- a/app/cmd/config.go +++ b/app/cmd/config.go @@ -65,7 +65,7 @@ var configCmd = &cobra.Command{ if configOptions.Generate { if data, err := generateSampleConfig(); err == nil { fmt.Print(string(data)) - fmt.Printf("# Goto 'http://localhost:8080/jenkins/me/configure', then you can generate your token.") + fmt.Println("# Goto 'http://localhost:8080/jenkins/me/configure', then you can generate your token.") } else { log.Fatal(err) } diff --git a/app/cmd/plugin.go b/app/cmd/plugin.go index c0700ede5d9d0cbf3aaf7600562654a83fe7ca53..dd0a5f2a8ea4b9b322e187c4fba5c11c03b738a1 100644 --- a/app/cmd/plugin.go +++ b/app/cmd/plugin.go @@ -1,19 +1,13 @@ package cmd import ( - "bytes" - "crypto/tls" "fmt" - "io" "io/ioutil" "log" - "mime/multipart" "net/http" "os" - "path/filepath" "strings" - "github.com/gosuri/uiprogress" "github.com/linuxsuren/jenkins-cli/client" "github.com/linuxsuren/jenkins-cli/util" "github.com/spf13/cobra" @@ -53,51 +47,18 @@ var pluginCmd = &cobra.Command{ Short: "Manage the plugins of Jenkins", Long: `Manage the plugins of Jenkins`, Run: func(cmd *cobra.Command, args []string) { - if pluginOpt.Upload { - crumb, config := getCrumb() - - api := fmt.Sprintf("%s/pluginManager/uploadPlugin", config.URL) - - path, _ := os.Getwd() - dirName := filepath.Base(path) - dirName = strings.Replace(dirName, "-plugin", "", -1) - path += fmt.Sprintf("/target/%s.hpi", dirName) - extraParams := map[string]string{} - request, err := newfileUploadRequest(api, extraParams, "@name", path) - if err != nil { - log.Fatal(err) - } - request.SetBasicAuth(config.UserName, config.Token) - request.Header.Add("Accept", "*/*") - request.Header.Add(crumb.CrumbRequestField, crumb.Crumb) - if err == nil { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - var response *http.Response - response, err = client.Do(request) - if err != nil { - fmt.Println(err) - } else if response.StatusCode != 200 { - var data []byte - if data, err = ioutil.ReadAll(response.Body); err == nil { - fmt.Println(string(data)) - } else { - log.Fatal(err) - } - } - } else { - log.Fatal(err) - } - } - - config := getCurrentJenkins() jenkins := getCurrentJenkins() jclient := &client.PluginManager{} jclient.URL = jenkins.URL - jclient.UserName = config.UserName - jclient.Token = config.Token + jclient.UserName = jenkins.UserName + jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth + + if pluginOpt.Upload { + jclient.Upload() + } + if pluginOpt.CheckUpdate { jclient.CheckUpdate(func(response *http.Response) { code := response.StatusCode @@ -218,71 +179,3 @@ func (o *PluginOptions) Output(obj interface{}) (data []byte, err error) { } return } - -func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { - file, err := os.Open(path) - if err != nil { - return nil, err - } - - var total float64 - if stat, err := file.Stat(); err != nil { - panic(err) - } else { - total = float64(stat.Size()) - } - defer file.Close() - - // body := &bytes.Buffer{} - body := &ProgressIndicator{ - Total: total, - } - body.Init() - writer := multipart.NewWriter(body) - part, err := writer.CreateFormFile(paramName, filepath.Base(path)) - if err != nil { - return nil, err - } - - _, err = io.Copy(part, file) - - for key, val := range params { - _ = writer.WriteField(key, val) - } - err = writer.Close() - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", uri, body) - req.Header.Set("Content-Type", writer.FormDataContentType()) - return req, err -} - -type ProgressIndicator struct { - bytes.Buffer - Total float64 - count float64 - bar *uiprogress.Bar -} - -func (i *ProgressIndicator) Init() { - uiprogress.Start() // start rendering - i.bar = uiprogress.AddBar(100) // Add a new bar - - // optionally, append and prepend completion and elapsed time - i.bar.AppendCompleted() - // i.bar.PrependElapsed() -} - -func (i *ProgressIndicator) Write(p []byte) (n int, err error) { - n, err = i.Buffer.Write(p) - return -} - -func (i *ProgressIndicator) Read(p []byte) (n int, err error) { - n, err = i.Buffer.Read(p) - i.count += float64(n) - i.bar.Set((int)(i.count * 100 / i.Total)) - return -} diff --git a/app/cmd/restart.go b/app/cmd/restart.go index 937b8e2ef5d0405b4d667b7d810fb26b3eb80fd1..85f7915773303a15961a868ebc99ed3e3a9ca6fc 100644 --- a/app/cmd/restart.go +++ b/app/cmd/restart.go @@ -1,13 +1,10 @@ package cmd import ( - "crypto/tls" "fmt" - "io/ioutil" - "log" - "net/http" "github.com/AlecAivazis/survey" + "github.com/linuxsuren/jenkins-cli/client" "github.com/spf13/cobra" ) @@ -28,12 +25,11 @@ var restartCmd = &cobra.Command{ Short: "Restart your Jenkins", Long: `Restart your Jenkins`, Run: func(cmd *cobra.Command, args []string) { - crumb, config := getCrumb() - + jenkins := getCurrentJenkins() if !restartOption.Batch { confirm := false prompt := &survey.Confirm{ - Message: fmt.Sprintf("Are you sure to restart Jenkins %s?", config.URL), + Message: fmt.Sprintf("Are you sure to restart Jenkins %s?", jenkins.URL), } survey.AskOne(prompt, &confirm) if !confirm { @@ -41,30 +37,13 @@ var restartCmd = &cobra.Command{ } } - api := fmt.Sprintf("%s/safeRestart", config.URL) - - req, err := http.NewRequest("POST", api, nil) - if err != nil { - log.Fatal(err) - } - req.Header.Add("Accept", "*/*") - req.SetBasicAuth(config.UserName, config.Token) - req.Header.Add(crumb.CrumbRequestField, crumb.Crumb) + jclient := &client.CoreClient{} + jclient.URL = jenkins.URL + jclient.UserName = jenkins.UserName + jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - if response, err := client.Do(req); err == nil { - if response.StatusCode != 200 { - if data, err := ioutil.ReadAll(response.Body); err == nil { - fmt.Println(string(data)) - } else { - log.Fatal(err) - } - } - } else { - log.Fatal(err) - } + jclient.Restart() }, } diff --git a/client/common.go b/client/common.go new file mode 100644 index 0000000000000000000000000000000000000000..ae6f2a106041831d65755adbaee2913b2857c60a --- /dev/null +++ b/client/common.go @@ -0,0 +1,107 @@ +package client + +import ( + "crypto/tls" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" +) + +type JenkinsCore struct { + JenkinsCrumb + URL string + UserName string + Token string + Proxy string + ProxyAuth string +} + +type JenkinsCrumb struct { + CrumbRequestField string + Crumb string +} + +func (j *JenkinsCore) GetClient() (client *http.Client) { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + if j.Proxy != "" { + if proxyURL, err := url.Parse(j.Proxy); err == nil { + tr.Proxy = http.ProxyURL(proxyURL) + } else { + log.Fatal(err) + } + + if j.ProxyAuth != "" { + basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(j.ProxyAuth)) + tr.ProxyConnectHeader = http.Header{} + tr.ProxyConnectHeader.Add("Proxy-Authorization", basicAuth) + } + } + client = &http.Client{Transport: tr} + return +} + +func (j *JenkinsCore) ProxyHandle(request *http.Request) { + if j.ProxyAuth != "" { + basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(j.ProxyAuth)) + request.Header.Add("Proxy-Authorization", basicAuth) + } +} + +func (j *JenkinsCore) AuthHandle(request *http.Request) (err error) { + request.SetBasicAuth(j.UserName, j.Token) + j.ProxyHandle(request) + + if request.Method == "POST" { + err = j.CrumbHandle(request) + } + return +} + +func (j *JenkinsCore) CrumbHandle(request *http.Request) error { + if c, err := j.GetCrumb(); err == nil && c != nil { + // cannot get the crumb could be a noraml situation + j.CrumbRequestField = c.CrumbRequestField + j.Crumb = c.Crumb + request.Header.Add(j.CrumbRequestField, j.Crumb) + } else { + return err + } + + return nil +} + +func (j *JenkinsCore) GetCrumb() (*JenkinsCrumb, error) { + api := fmt.Sprintf("%s/crumbIssuer/api/json", j.URL) + + req, err := http.NewRequest("GET", api, nil) + if err != nil { + return nil, err + } + j.AuthHandle(req) + + var crumbIssuer JenkinsCrumb + client := j.GetClient() + if response, err := client.Do(req); err == nil { + if data, err := ioutil.ReadAll(response.Body); err == nil { + if response.StatusCode == 200 { + json.Unmarshal(data, &crumbIssuer) + } else if response.StatusCode == 404 { + return nil, err + } else { + log.Printf("Unexpected status code: %d.", response.StatusCode) + return nil, err + } + } else { + return nil, err + } + } else { + return nil, err + } + return &crumbIssuer, nil +} diff --git a/client/core.go b/client/core.go index 24e0df23d844f3a9b1ea91e0a31958d4f6e69b0d..1debb6b1ec5af32cad7cab461123c729c1a090f7 100644 --- a/client/core.go +++ b/client/core.go @@ -1,97 +1,43 @@ package client import ( - "crypto/tls" - "encoding/base64" - "encoding/json" "fmt" "io/ioutil" "log" "net/http" - "net/url" ) -type JenkinsCore struct { - JenkinsCrumb - URL string - UserName string - Token string - Proxy string - ProxyAuth string +type CoreClient struct { + JenkinsCore } -type JenkinsCrumb struct { - CrumbRequestField string - Crumb string -} - -func (j *JenkinsCore) GetClient() (client *http.Client) { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - if j.Proxy != "" { - if proxyURL, err := url.Parse(j.Proxy); err == nil { - tr.Proxy = http.ProxyURL(proxyURL) - } else { - log.Fatal(err) - } - - if j.ProxyAuth != "" { - basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(j.ProxyAuth)) - tr.ProxyConnectHeader = http.Header{} - tr.ProxyConnectHeader.Add("Proxy-Authorization", basicAuth) - } - } - client = &http.Client{Transport: tr} - return -} - -func (j *JenkinsCore) AuthHandle(request *http.Request) { - request.SetBasicAuth(j.UserName, j.Token) -} - -func (j *JenkinsCore) CrumbHandle(request *http.Request) error { - if c, err := j.GetCrumb(); err == nil && c != nil { - // cannot get the crumb could be a noraml situation - j.CrumbRequestField = c.CrumbRequestField - j.Crumb = c.Crumb - request.Header.Add(j.CrumbRequestField, j.Crumb) +// Search find a set of jobs by name +func (q *CoreClient) Restart() (err error) { + api := fmt.Sprintf("%s/safeRestart", q.URL) + var ( + req *http.Request + response *http.Response + ) + + req, err = http.NewRequest("POST", api, nil) + if err == nil { + q.AuthHandle(req) } else { - return err - } - - return nil -} - -func (j *JenkinsCore) GetCrumb() (*JenkinsCrumb, error) { - api := fmt.Sprintf("%s/crumbIssuer/api/json", j.URL) - - req, err := http.NewRequest("GET", api, nil) - if err != nil { - return nil, err + return } - j.AuthHandle(req) - var crumbIssuer JenkinsCrumb - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - if response, err := client.Do(req); err == nil { - if data, err := ioutil.ReadAll(response.Body); err == nil { - if response.StatusCode == 200 { - json.Unmarshal(data, &crumbIssuer) - } else if response.StatusCode == 404 { - return nil, err - } else { - log.Printf("Unexpected status code: %d.", response.StatusCode) - return nil, err - } + client := q.GetClient() + if response, err = client.Do(req); err == nil { + code := response.StatusCode + var data []byte + data, err = ioutil.ReadAll(response.Body) + if code != 200 || err != nil { + log.Fatalf("Error code: %d, response: %s, errror: %v", code, string(data), err) } else { - return nil, err + fmt.Println("restart successfully") } } else { - return nil, err + log.Fatal(err) } - return &crumbIssuer, nil + return } diff --git a/client/pluginManger.go b/client/pluginManger.go index 001659b73ac5e155f72a08452f4c570d6693761b..a04a09f218ad13a368b08a20989fa6829e6aa1cb 100644 --- a/client/pluginManger.go +++ b/client/pluginManger.go @@ -1,12 +1,19 @@ package client import ( + "bytes" "encoding/json" "fmt" + "io" "io/ioutil" "log" + "mime/multipart" "net/http" + "os" + "path/filepath" "strings" + + "github.com/gosuri/uiprogress" ) type PluginManager struct { @@ -159,15 +166,13 @@ func (p *PluginManager) InstallPlugin(names []string) (err error) { req, err = http.NewRequest("POST", api, nil) if err == nil { - p.AuthHandle(req) + if err = p.AuthHandle(req); err != nil { + log.Fatal(err) + } } else { return } - if err = p.CrumbHandle(req); err != nil { - return - } - client := p.GetClient() if response, err = client.Do(req); err == nil { code := response.StatusCode @@ -199,10 +204,6 @@ func (p *PluginManager) UninstallPlugin(name string) (err error) { return } - if err = p.CrumbHandle(req); err != nil { - return - } - client := p.GetClient() if response, err = client.Do(req); err == nil { code := response.StatusCode @@ -219,9 +220,111 @@ func (p *PluginManager) UninstallPlugin(name string) (err error) { return } +func (p *PluginManager) Upload() { + api := fmt.Sprintf("%s/pluginManager/uploadPlugin", p.URL) + + path, _ := os.Getwd() + dirName := filepath.Base(path) + dirName = strings.Replace(dirName, "-plugin", "", -1) + path += fmt.Sprintf("/target/%s.hpi", dirName) + extraParams := map[string]string{} + request, err := newfileUploadRequest(api, extraParams, "@name", path) + if err != nil { + log.Fatal(err) + } + + if err == nil { + p.AuthHandle(request) + } else { + return + } + + client := p.GetClient() + var response *http.Response + response, err = client.Do(request) + if err != nil { + log.Fatal(err) + } else if response.StatusCode != 200 { + var data []byte + if data, err = ioutil.ReadAll(response.Body); err == nil { + fmt.Println(string(data)) + } else { + log.Fatal(err) + } + } +} + func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Response) { if handle == nil { handle = func(*http.Response) {} } return handle } + +type ProgressIndicator struct { + bytes.Buffer + Total float64 + count float64 + bar *uiprogress.Bar +} + +func (i *ProgressIndicator) Init() { + uiprogress.Start() // start rendering + i.bar = uiprogress.AddBar(100) // Add a new bar + + // optionally, append and prepend completion and elapsed time + i.bar.AppendCompleted() + // i.bar.PrependElapsed() +} + +func (i *ProgressIndicator) Write(p []byte) (n int, err error) { + n, err = i.Buffer.Write(p) + return +} + +func (i *ProgressIndicator) Read(p []byte) (n int, err error) { + n, err = i.Buffer.Read(p) + i.count += float64(n) + i.bar.Set((int)(i.count * 100 / i.Total)) + return +} + +func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + + var total float64 + if stat, err := file.Stat(); err != nil { + panic(err) + } else { + total = float64(stat.Size()) + } + defer file.Close() + + // body := &bytes.Buffer{} + body := &ProgressIndicator{ + Total: total, + } + body.Init() + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile(paramName, filepath.Base(path)) + if err != nil { + return nil, err + } + + _, err = io.Copy(part, file) + + for key, val := range params { + _ = writer.WriteField(key, val) + } + err = writer.Close() + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", uri, body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + return req, err +}