未验证 提交 8c3695b7 编写于 作者: LinuxSuRen's avatar LinuxSuRen 提交者: GitHub

Add support to list Jenkins agents (#259)

* Add support to list Jenkins agents

* Add i18n translation
上级 2e13d6bd
package cmd
import (
"github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(computerCmd)
}
var computerCmd = &cobra.Command{
Use: "computer",
Aliases: []string{"cpu", "agent"},
Short: i18n.T("Manage the computers of your Jenkins"),
Long: i18n.T(`Manage the computers of your Jenkins`),
}
package cmd
import (
"bytes"
"fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"net/http"
"github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/jenkins-zh/jenkins-cli/util"
"github.com/spf13/cobra"
)
// ComputerListOption option for config list command
type ComputerListOption struct {
OutputOption
RoundTripper http.RoundTripper
}
var computerListOption ComputerListOption
func init() {
computerCmd.AddCommand(computerListCmd)
computerListOption.SetFlag(computerListCmd)
}
var computerListCmd = &cobra.Command{
Use: "list",
Short: i18n.T("List all Jenkins agents"),
Long: i18n.T("List all Jenkins agents"),
RunE: func(cmd *cobra.Command, _ []string) (err error) {
jClient := &client.ComputerClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: computerListOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jClient.JenkinsCore))
var computers client.ComputerList
if computers, err = jClient.List(); err == nil {
var data []byte
data, err = computerListOption.Output(computers.Computer)
if err == nil && len(data) > 0 {
cmd.Print(string(data))
}
}
return
},
}
// Output render data into byte array as a table format
func (o *ComputerListOption) Output(obj interface{}) (data []byte, err error) {
if data, err = o.OutputOption.Output(obj); err != nil && o.Format == TableOutputFormat {
computers := obj.([]client.Computer)
buf := new(bytes.Buffer)
table := util.CreateTableWithHeader(buf, o.WithoutHeaders)
table.AddHeader("number", "name", "executors", "description", "offline")
for i, computer := range computers {
table.AddRow(fmt.Sprintf("%d", i), computer.DisplayName,
fmt.Sprintf("%d", computer.NumExecutors), computer.Description,
fmt.Sprintf("%v", computer.Offline))
}
table.Render()
err = nil
data = buf.Bytes()
}
return
}
package cmd
import (
"bytes"
"io"
"io/ioutil"
"os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("computer list command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
buf io.Writer
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
rootCmd.SetArgs([]string{})
buf = new(bytes.Buffer)
rootCmd.SetOutput(buf)
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
computerListOption.RoundTripper = roundTripper
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
var (
err error
)
BeforeEach(func() {
var data []byte
data, err = generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
})
It("should success", func() {
client.PrepareForComputerListRequest(roundTripper, "http://localhost:8080/jenkins", "admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"computer", "list"})
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
})
})
})
...@@ -115,6 +115,10 @@ msgstr "为所有的 jcli 命令生成文档" ...@@ -115,6 +115,10 @@ msgstr "为所有的 jcli 命令生成文档"
msgid "jcli is a tool which could help you with your multiple Jenkins" msgid "jcli is a tool which could help you with your multiple Jenkins"
msgstr "jcli 是帮助你管理多个 Jenkins 的工具" msgstr "jcli 是帮助你管理多个 Jenkins 的工具"
#: app/cmd/computer.go:15 app/cmd/computer.go:16
msgid "管理 Jenkins 节点"
msgstr ""
#: app/cmd/root.go:55 #: app/cmd/root.go:55
msgid "Jenkins CLI (jcli) manage your Jenkins" msgid "Jenkins CLI (jcli) manage your Jenkins"
msgstr "Jenkins CLI (jcli) 管理你的 Jenkins" msgstr "Jenkins CLI (jcli) 管理你的 Jenkins"
...@@ -127,6 +131,10 @@ msgstr "是否跳过前置命令钩子" ...@@ -127,6 +131,10 @@ msgstr "是否跳过前置命令钩子"
msgid "Create a sub shell so that changes to a specific Jenkins remain local to the shell." msgid "Create a sub shell so that changes to a specific Jenkins remain local to the shell."
msgstr "创建一个子 shell 使得对配置的修改保持在一个上下文中" msgstr "创建一个子 shell 使得对配置的修改保持在一个上下文中"
#: app/cmd/computer_list.go:31 app/cmd/computer_list.go:32
msgid "列出所有的 Jenkins 节点"
msgstr ""
#: app/cmd/plugin.go:21 app/cmd/plugin.go:22 #: app/cmd/plugin.go:21 app/cmd/plugin.go:22
msgid "Manage the plugins of Jenkins" msgid "Manage the plugins of Jenkins"
msgstr "管理 Jenkins 的插件" msgstr "管理 Jenkins 的插件"
......
package client
// ComputerClient is client for operate computers
type ComputerClient struct {
JenkinsCore
}
// List get the computer list
func (c *ComputerClient) List() (computers ComputerList, err error) {
err = c.RequestWithData("GET", "/computer/api/json",
nil, nil, 200, &computers)
return
}
// Computer is the agent of Jenkins
type Computer struct {
AssignedLabels []ComputerLabel
Description string
DisplayName string
Idle bool
JnlpAgent bool
LaunchSupported bool
ManualLaunchAllowed bool
NumExecutors int
Offline bool
OfflineCause string
OfflineCauseReason string
TemporarilyOffline bool
}
// ComputerList represents the list of computer from API
type ComputerList struct {
busyExecutors int
Computer []Computer
TotalExecutors int
}
// ComputerLabel represents the label of a computer
type ComputerLabel struct {
Name string
}
package client_test
import (
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("computer test", func() {
var (
ctrl *gomock.Controller
computerClient client.ComputerClient
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
computerClient = client.ComputerClient{}
computerClient.RoundTripper = roundTripper
computerClient.URL = "http://localhost"
})
AfterEach(func() {
ctrl.Finish()
})
It("List", func() {
client.PrepareForComputerListRequest(roundTripper, computerClient.URL, "", "")
//request, _ := http.NewRequest("GET", fmt.Sprintf("%s/computer/api/json", computerClient.URL), nil)
//response := &http.Response{
// StatusCode: 200,
// Request: request,
// Body: ioutil.NopCloser(bytes.NewBufferString()),
//}
//roundTripper.EXPECT().
// RoundTrip(request).Return(response, nil)
computers, err := computerClient.List()
Expect(err).NotTo(HaveOccurred())
Expect(computers).NotTo(BeNil())
Expect(len(computers.Computer)).To(Equal(1))
})
})
package client
import (
"bytes"
"fmt"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
"io/ioutil"
"net/http"
)
// PrepareForComputerListRequest only for test
func PrepareForComputerListRequest(roundTripper *mhttp.MockRoundTripper, rootURL, user, password string) {
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/computer/api/json", rootURL), nil)
response := &http.Response{
StatusCode: 200,
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(PrepareForComputerList())),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
if user != "" && password != "" {
request.SetBasicAuth(user, password)
}
}
// PrepareForComputerList only for test
func PrepareForComputerList() string {
return `
{
"_class" : "hudson.model.ComputerSet",
"busyExecutors" : 1,
"computer" : [
{
"_class" : "hudson.model.Hudson$MasterComputer",
"actions" : [
{
},
{
}
],
"assignedLabels" : [
{
"name" : "master"
}
],
"description" : "Jenkins的master节点",
"displayName" : "master",
"executors" : [
{
},
{
}
],
"icon" : "computer.png",
"iconClassName" : "icon-computer",
"idle" : false,
"jnlpAgent" : false,
"launchSupported" : true,
"loadStatistics" : {
"_class" : "hudson.model.Label$1"
},
"manualLaunchAllowed" : true,
"monitorData" : {
"hudson.node_monitors.SwapSpaceMonitor" : {
"_class" : "hudson.node_monitors.SwapSpaceMonitor$MemoryUsage2",
"availablePhysicalMemory" : 533508096,
"availableSwapSpace" : 0,
"totalPhysicalMemory" : 16656797696,
"totalSwapSpace" : 0
},
"hudson.node_monitors.TemporarySpaceMonitor" : {
"_class" : "hudson.node_monitors.DiskSpaceMonitorDescriptor$DiskSpace",
"timestamp" : 1574952137138,
"path" : "/tmp",
"size" : 31745785856
},
"hudson.node_monitors.DiskSpaceMonitor" : {
"_class" : "hudson.node_monitors.DiskSpaceMonitorDescriptor$DiskSpace",
"timestamp" : 1574952136930,
"path" : "/var/jenkins_home",
"size" : 31745785856
},
"hudson.node_monitors.ArchitectureMonitor" : "Linux (amd64)",
"hudson.node_monitors.ResponseTimeMonitor" : {
"_class" : "hudson.node_monitors.ResponseTimeMonitor$Data",
"timestamp" : 1574952136931,
"average" : 0
},
"hudson.node_monitors.ClockMonitor" : {
"_class" : "hudson.util.ClockDifference",
"diff" : 0
}
},
"numExecutors" : 2,
"offline" : false,
"offlineCause" : null,
"offlineCauseReason" : "",
"oneOffExecutors" : [
{
}
],
"temporarilyOffline" : false
}
],
"displayName" : "节点列表",
"totalExecutors" : 2
}`
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册