-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathportainer.go
171 lines (129 loc) · 3.83 KB
/
portainer.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
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
)
// HTTP request timeout
const Timeout = 5 * time.Second
type Portainer struct {
Endpoint string
Token string
}
// AuthRequest is authorization form struct for Portainer API
type AuthRequest struct {
Username string
Password string
}
// AuthResponse is response format for authorization in Portainer API
type AuthResponse struct {
JWT string
Err string
}
// SwarmEndpoint is response format for GET /endpoints call in Portainer API
type SwarmEndpoint struct {
ID int
Name string
PublicURL string
Containers []DockerContainer
}
// DockerContainer is response format for GET /endpoints/{endpointId}/docker/containers call in Portainer API
type DockerContainer struct {
ID string
Image string
State string
}
// NewPortainer initializes connection to Portainer API and obtain JWT access token
func NewPortainer(username string, password string, endpoint string) *Portainer {
url := endpoint + "/api/auth"
login := AuthRequest{Username: username, Password: password}
data, err := json.Marshal(login)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: Timeout}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
token := &AuthResponse{}
err = json.Unmarshal(body, token)
if err != nil {
log.Println(err)
}
if token.Err != "" {
log.Fatal(token.Err)
}
if token.JWT == "" {
log.Fatal("Portainer server didn't return JWT token")
}
log.Printf("Successfully logged in as %s\n", username)
return &Portainer{Token: token.JWT, Endpoint: endpoint}
}
// GetSwarmEndpoints makes request to Portainer API and returns []SwarmEndpoint
func (p *Portainer) GetSwarmEndpoints() ([]SwarmEndpoint, error) {
var endpoints []SwarmEndpoint
resp, err := p.makeRequest("GET", "/api/endpoints", nil)
if err != nil {
return nil, err
}
err = json.Unmarshal(resp, &endpoints)
if err != nil {
return nil, err
}
return endpoints, nil
}
// GetDockerContainers makes request to Portainer API and returns []DockerContainer with label "name=factomd" for requested endpointId
func (p *Portainer) GetDockerContainers(endpointID int) ([]DockerContainer, error) {
var containers []DockerContainer
resp, err := p.makeRequest("GET", "/api/endpoints/"+strconv.Itoa(endpointID)+"/docker/containers/json?all=1&filters={\"label\":[\"name=factomd\"]}", nil)
if err != nil {
return nil, err
}
if len(resp) == 0 {
return nil, fmt.Errorf("Empty response received from Portainer API")
}
err = json.Unmarshal(resp, &containers)
if err != nil {
return nil, err
}
if len(containers) == 0 {
return nil, fmt.Errorf("No containers with label 'name=factomd'")
}
return containers, nil
}
// RestartDockerContainer makes restart request to Portainer API for requested endpointId and containerId
func (p *Portainer) RestartDockerContainer(endpointID int, containerID string) error {
// nothing returned = success
_, err := p.makeRequest("POST", "/api/endpoints/"+strconv.Itoa(endpointID)+"/docker/containers/"+containerID+"/restart?t=5", nil)
if err != nil {
return err
}
return nil
}
// Low level function making requests to Portainer API
func (p *Portainer) makeRequest(method string, path string, data []byte) ([]byte, error) {
url := p.Endpoint + path
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+p.Token)
client := &http.Client{Timeout: Timeout}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}