-
Notifications
You must be signed in to change notification settings - Fork 0
/
docker.cpp
221 lines (198 loc) · 7.77 KB
/
docker.cpp
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include "docker.h"
size_t writeFunction(void *ptr, size_t size, size_t nmemb, string *data)
{
/* Simple callback for response of curl */
data->append((char *)ptr, size * nmemb);
return size * nmemb;
}
string convert_http_query(string str)
{
// Process http query to use it with curl
string::size_type pos = 0;
while ((pos = str.find(' ', pos)) != string::npos)
{
str.replace(pos, 1, "%20");
pos += 3;
}
return str;
}
string raw_request(string endpoint, int method, string data, string docker_socket)
{
/* Raw request to docker endpoint
Choose docker socket
Choose http host
Choose http request type (GET, POST)
*/
// Example curl cli command
// curl -X GET --unix-socket /var/run/docker.sock http://localhost/images/json
// cout << "RW " << endpoint << " " << method << " " << data << "\n";
string url = convert_http_query(endpoint);
// cout << url << endl;
string response_string;
string header_string;
long http_code = 0;
curl_global_init(CURL_GLOBAL_DEFAULT);
auto curl = curl_easy_init();
if (curl)
{
// Convert socket path + endpoint from string to *char
int endpoint_length = endpoint.length();
char endpoint_arr[endpoint_length + 1];
strcpy(endpoint_arr, endpoint.c_str());
int socket_length = docker_socket.length();
char socket_arr[socket_length + 1];
strcpy(socket_arr, docker_socket.c_str());
curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, socket_arr);
curl_easy_setopt(curl, CURLOPT_URL, endpoint_arr);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &header_string);
if (method == 1) // POST
{
// cout << "POST\n";
struct curl_slist *hs = NULL;
hs = curl_slist_append(hs, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
// cout << data << "\n";
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
}
else if (method == 2){} // PUT
else if (method == 3){ //DELETE
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
}
curl_easy_perform(curl);
auto res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
// cout << "HTTP code: " << http_code << "\n";
curl_easy_cleanup(curl);
curl_global_cleanup();
curl = NULL;
}
return response_string;
}
json raw_api(string endpoint, int method, string data, bool plain, string docker_socket)
{
string plain_text = raw_request(endpoint, method, data);
if (plain) return {{"data", plain_text}};
// cout << "\n" << plain_text << "\n";
json no_data = {
{"data", false}};
if (plain_text.length() == 0)
return no_data;
else
return json::parse(plain_text);
}
json list_containers(bool all, string host)
{
return raw_api(fmt::v9::format("{}/containers/json?all={}", host, all));
}
json inspect_container(string id, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/json", host, id));
}
json processes_in_container(string id, string ps_args, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/top?ps_args={}", host, id, ps_args));
}
json start_container(string id, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/start", host, id), 1);
}
json stop_container(string id, int t, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/stop?t={}", host, id, t), 1);
}
json restart_container(string id, int t, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/restart?t={}", host, id, t), 1);
}
json kill_container(string id, string signal, string host)
{
return raw_api(fmt::v9::format("{}/containers/{}/kill?signal={}", host, id, signal), 1);
}
json exec_in_container(string id, string bash_command, bool bash, bool AttachStdin, bool AttachStdout, bool AttachStderr, bool tty, string working_dir, string host)
{
// Creating exec instance
string endpoint = fmt::v9::format("{}/containers/{}/exec", host, id);
json payload = {
{"AttachStdin", AttachStdin},
{"AttachStdout", AttachStdout},
{"AttachStderr", AttachStderr},
{"Tty", tty},
{"WorkingDir", working_dir}};
// To execute bash command in docker, you need to use smth, like bash -c COMMAND HERE
// To execute binary in docker, you need to use smth, like /path/to/bin
if (bash)
payload["Cmd"] = {"bash", "-c", bash_command};
else
payload["Cmd"] = {bash_command};
string payload_string = payload.dump();
cout << payload_string << "\n";
json res = raw_api(endpoint, 1, payload_string);
// Start exec instance
payload = {
{"Detach", true},
{"Tty", true}};
payload_string = payload.dump();
return raw_api(fmt::v9::format("{}/exec/{}/start", host, res["Id"]), 1, payload_string);
}
json create_container(string image, int StopTimeout, json volumes, int MemoryLimit, string bash_init_cmd, string WorkingDir, bool AttachStdin, bool AttachStdout, bool AttachStderr, bool NetworkDisabled, string host)
{
json payload = {
{"Image", image},
// {"Entrypoint", {"/bin/bash", },
{"Cmd", {"ls", "/home/code"}},
// {"Volumes", {{"/home/code", {"/home/stephan/Progs/DockerAPI/build/wokspace/tmp"}}}},
//{"StopTimeout", StopTimeout},
{"HostConfig", {{"Memory", MemoryLimit}, {"Mounts", {{{"Target", "/home/code"}, {"Source", "workspace/tmp"}, {"Type", "volume"}, {"ReadOnly", false}}}}}},
{"NetworkDisabled", NetworkDisabled},
{"WorkingDir", WorkingDir},
// {"AttachStdin", AttachStdin},
// {"AttachStdout", AttachStdout},
// {"AttachStderr", AttachStderr}
};
string payload_string = payload.dump();
cout << "\n"
<< payload_string << "\n";
return raw_api(fmt::v9::format("{}/containers/create", host), 1, payload_string);
}
websocket::stream<tcp::socket> attach_to_container_ws(string id, bool stream, bool stdout, bool stdin, bool logs, string host, string port)
{
// Create websocket
net::io_context ioc;
tcp::resolver resolver{ioc};
websocket::stream<tcp::socket> ws{ioc};
auto const results = resolver.resolve(host, port);
net::connect(ws.next_layer(), results.begin(), results.end());
// Decorator for user agent
// ws.set_option(websocket::stream_base::decorator(
// [](websocket::request_type &req)
// {
// req.set(http::field::user_agent,
// std::string(BOOST_BEAST_VERSION_STRING) +
// " shtp-docker-client");
// }));
string connection_uri = fmt::v9::format("/containers/{}/attach/ws?stream={}&stdout={}&stdin={}&logs={}", id, stream, stdout, stdin, logs);
cout << "\n" << connection_uri << "\n";
ws.handshake(host, connection_uri);
return ws;
}
string get_container_logs(string id, bool stream_stdout, bool stream_stderr, string host){
return raw_api(fmt::v9::format("{}/containers/{}/logs?stdout={}&stderr={}", host, id, stream_stdout, stream_stderr), 0, "", true)["data"];
}
json wait_for_container(string id, string host){
// Yeah, we will stack here
json res = raw_api(fmt::v9::format("{}/containers/{}/wait", host, id), 1, "");
return res;
}
json remove_container(string id, string host){
return raw_api(fmt::v9::format("{}/containers/{}", host, id), 3);
}
// json put_archive(string id, string host){
// }
/*class API {
public:
string Host, UnixSocket;
API(string Host="http://localhost/v1.41", string UnixSocket="/var/run/docker.sock"){
cout << "Class constructor";
}
};*/