Refactoring to use Docker sockets directly as well as fork() to call processes instead of opening shells
This commit is contained in:
parent
6635446438
commit
802550f6e7
9 changed files with 720 additions and 1229 deletions
93
src/docker_engine_client.cpp
Normal file
93
src/docker_engine_client.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#include "docker_engine_client.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
DockerEngineClient::DockerEngineClient(std::string socket_path)
|
||||
: socket_path_(std::move(socket_path)) {}
|
||||
|
||||
EngineResponse DockerEngineClient::request(const std::string& method,
|
||||
const std::string& path,
|
||||
const std::string& body) const {
|
||||
EngineResponse response;
|
||||
const int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
response.error = std::strerror(errno);
|
||||
return response;
|
||||
}
|
||||
|
||||
sockaddr_un address{};
|
||||
address.sun_family = AF_UNIX;
|
||||
if (socket_path_.size() >= sizeof(address.sun_path)) {
|
||||
response.error = "Docker socket path is too long.";
|
||||
close(fd);
|
||||
return response;
|
||||
}
|
||||
std::strncpy(address.sun_path, socket_path_.c_str(), sizeof(address.sun_path) - 1);
|
||||
if (connect(fd, reinterpret_cast<sockaddr*>(&address), sizeof(address)) != 0) {
|
||||
response.error = std::strerror(errno);
|
||||
close(fd);
|
||||
return response;
|
||||
}
|
||||
|
||||
timeval timeout{};
|
||||
timeout.tv_sec = 10;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
std::ostringstream request;
|
||||
request << method << " " << path << " HTTP/1.1\r\n"
|
||||
<< "Host: docker\r\n"
|
||||
<< "Connection: close\r\n"
|
||||
<< "Content-Type: application/json\r\n"
|
||||
<< "Content-Length: " << body.size() << "\r\n\r\n"
|
||||
<< body;
|
||||
const std::string wire = request.str();
|
||||
std::size_t sent = 0;
|
||||
while (sent < wire.size()) {
|
||||
const ssize_t count = write(fd, wire.data() + sent, wire.size() - sent);
|
||||
if (count <= 0) {
|
||||
response.error = std::strerror(errno);
|
||||
close(fd);
|
||||
return response;
|
||||
}
|
||||
sent += static_cast<std::size_t>(count);
|
||||
}
|
||||
|
||||
std::string raw;
|
||||
char buffer[8192];
|
||||
ssize_t count = 0;
|
||||
while ((count = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
raw.append(buffer, static_cast<std::size_t>(count));
|
||||
}
|
||||
close(fd);
|
||||
if (count < 0) {
|
||||
response.error = std::strerror(errno);
|
||||
return response;
|
||||
}
|
||||
|
||||
const std::size_t header_end = raw.find("\r\n\r\n");
|
||||
if (header_end == std::string::npos) {
|
||||
response.error = "Invalid response from Docker Engine.";
|
||||
return response;
|
||||
}
|
||||
const std::size_t status_end = raw.find("\r\n");
|
||||
std::istringstream status_line(raw.substr(0, status_end));
|
||||
std::string http_version;
|
||||
status_line >> http_version >> response.status_code;
|
||||
if (response.status_code == 0) {
|
||||
response.error = "Invalid HTTP status from Docker Engine.";
|
||||
return response;
|
||||
}
|
||||
response.body = raw.substr(header_end + 4);
|
||||
if (!response.ok()) {
|
||||
response.error = response.body.empty() ? "Docker Engine request failed." : response.body;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue