/
computer.go
178 lines (159 loc) · 4.59 KB
/
computer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package computer
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"runtime"
"strings"
"github.com/jenkins-zh/jenkins-client/pkg/core"
httpdownloader "github.com/linuxsuren/http-downloader/pkg"
)
// Client is client for operate computers
type Client struct {
core.JenkinsCore
}
// List get the computer list
func (c *Client) List() (computers List, err error) {
err = c.RequestWithData(http.MethodGet, "/computer/api/json",
nil, nil, 200, &computers)
return
}
// Launch starts up a agent
func (c *Client) Launch(name string) (err error) {
api := fmt.Sprintf("/computer/%s/launchSlaveAgent", name)
_, err = c.RequestWithoutData(http.MethodPost, api, nil, nil, 200)
return
}
// Delete removes a agent from Jenkins
func (c *Client) Delete(name string) (err error) {
api := fmt.Sprintf("/computer/%s/doDelete", name)
_, err = c.RequestWithoutData(http.MethodPost, api, nil, nil, 200)
return
}
type agentJNLP struct {
XMLName xml.Name `xml:"jnlp"`
AppArguments []string `xml:"application-desc>argument"`
}
// GetSecret returns the secret of an agent
func (c *Client) GetSecret(name string) (secret string, err error) {
api := fmt.Sprintf("/computer/%s/slave-agent.jnlp", name)
var response *http.Response
if response, err = c.RequestWithResponse(http.MethodGet, api, nil, nil); err == nil {
if response.StatusCode == http.StatusOK {
var data []byte
if data, err = ioutil.ReadAll(response.Body); err == nil {
jnlp := &agentJNLP{}
if err = xml.Unmarshal(data, jnlp); err == nil {
secret = jnlp.AppArguments[0]
} else {
err = fmt.Errorf("invalid jnlp xml, error: %v", err)
}
}
} else {
err = fmt.Errorf("unexpected status code: %d", response.StatusCode)
}
}
return
}
// GetLog fetch the log a computer
func (c *Client) GetLog(name string) (log string, err error) {
var response *http.Response
api := fmt.Sprintf("/computer/%s/logText/progressiveText", name)
if response, err = c.RequestWithResponse(http.MethodGet, api, nil, nil); err == nil {
statusCode := response.StatusCode
if statusCode != 200 {
err = fmt.Errorf("unexpected status code %d", statusCode)
return
}
var data []byte
if data, err = ioutil.ReadAll(response.Body); err == nil {
log = string(data)
}
}
return
}
// Create creates a computer by name
func (c *Client) Create(name string) (err error) {
formData := url.Values{
"name": {name},
"mode": {"hudson.slaves.DumbSlave"},
}
payload := strings.NewReader(formData.Encode())
if _, err = c.RequestWithoutData(http.MethodPost, "/computer/createItem",
map[string]string{httpdownloader.ContentType: httpdownloader.ApplicationForm}, payload, 200); err == nil {
payload = GetPayloadForCreateAgent(name)
_, err = c.RequestWithoutData(http.MethodPost, "/computer/doCreateItem",
map[string]string{httpdownloader.ContentType: httpdownloader.ApplicationForm}, payload, 200)
}
return
}
func getDefaultAgentLabels() string {
return fmt.Sprintf("%s %s", runtime.GOOS, runtime.GOARCH)
}
// GetDefaultAgentWorkDir returns the Jenkins agent work dir
func GetDefaultAgentWorkDir() string {
// TODO return different directory base on the OS
return "/var/tmp/jenkins"
}
// GetPayloadForCreateAgent returns a payload for creating an agent
func GetPayloadForCreateAgent(name string) *strings.Reader {
palyLoad := fmt.Sprintf(`{
"name": "%s",
"nodeDescription": "",
"numExecutors": "1",
"remoteFS": "%s",
"labelString": "%s",
"mode": "NORMAL",
"launcher": {
"$class": "hudson.slaves.JNLPLauncher",
"workDirSettings": {
"disabled": false,
"workDirPath": "",
"internalDir": "remoting",
"failIfWorkDirIsMissing": false
},
"tunnel": "",
"vmargs": ""
},
"type": "hudson.slaves.DumbSlave"
}`, name, GetDefaultAgentWorkDir(), getDefaultAgentLabels())
formData := url.Values{
"name": {name},
"type": {"hudson.slaves.DumbSlave"},
"json": {palyLoad},
}
return strings.NewReader(formData.Encode())
}
// Computer is the agent of Jenkins
type Computer struct {
AssignedLabels []Label
Description string
DisplayName string
Idle bool
JnlpAgent bool
LaunchSupported bool
ManualLaunchAllowed bool
NumExecutors int
Offline bool
OfflineCause OfflineCause
OfflineCauseReason string
TemporarilyOffline bool
}
// OfflineCause is the cause of computer offline
type OfflineCause struct {
Timestamp int64
Description string
}
// List represents the list of computer from API
type List struct {
// nolint
busyExecutors int
Computer []Computer
TotalExecutors int
}
// Label represents the label of a computer
type Label struct {
Name string
}