5#ifndef LINE_IO_DOCKER_IMAGE_H
6#define LINE_IO_DOCKER_IMAGE_H
39#include <sys/statvfs.h>
60 if (image.empty())
return false;
72 if (image.empty())
return false;
79inline long long docker_free_bytes() {
81 util::capture({
"docker",
"info",
"--format",
"{{.DockerRootDir}}"}, 15);
83 if (root.empty()) root =
"/var/lib/docker";
88 while (!root.empty() && ::stat(root.c_str(), &st) != 0) {
89 const std::size_t slash = root.find_last_of(
'/');
90 if (slash == std::string::npos) break;
91 root = slash == 0 ? std::string(
"/") : root.substr(0, slash);
92 if (root ==
"/") break;
94 if (root.empty()) root =
"/";
97 if (::statvfs(root.c_str(), &vfs) != 0)
return -1;
98 const long long usable =
99 static_cast<long long>(vfs.f_bavail) *
static_cast<long long>(vfs.f_frsize);
100 return usable > 0 ? usable : -1;
104inline long long docker_estimate_image_bytes(
const std::string& image) {
105 const util::ProcResult r =
util::capture({
"docker",
"manifest",
"inspect", image}, 30);
106 if (r.exitCode != 0 || r.out.empty())
return 0;
108 const std::string& json = r.
out;
109 const std::string key =
"\"size\"";
111 while ((at = json.find(key, at)) != std::string::npos) {
112 std::size_t i = at + key.size();
113 while (i < json.size() && (json[i] ==
' ' || json[i] ==
':' || json[i] ==
'\t')) ++i;
114 if (i < json.size() && json[i] >=
'0' && json[i] <=
'9')
115 sum += std::atoll(json.c_str() + i);
118 return sum > 0 ? sum * 3 : 0;
122inline long long docker_override_min_free_bytes() {
123 const char* v = std::getenv(
"LINE_DOCKER_MIN_FREE_BYTES");
124 if (v ==
nullptr || *v ==
'\0')
return -1;
125 const long long parsed = std::atoll(v);
126 return parsed > 0 ? parsed : -1;
136 const long long free = detail::docker_free_bytes();
137 if (free < 0)
return true;
138 const long long override = detail::docker_override_min_free_bytes();
139 if (
override > 0)
return free >=
override;
140 const long long est = detail::docker_estimate_image_bytes(image);
143 return free >= required;
static const long long DOCKER_DEFAULT_MIN_FREE_BYTES
Conservative free-space floor required before a pull (2 GiB).
bool docker_has_storage_for(const std::string &image)
bool docker_daemon_available()
True if the Docker daemon is reachable.
bool docker_has_local_image(const std::string &image)
bool docker_pull(const std::string &image)
Pulls an image, streaming Docker's progress to stdout and stderr.
int run_inherit(const std::vector< std::string > &argv)
Runs a command with the parent's stdout and stderr, e.g.
ProcResult capture(const std::vector< std::string > &argv, int timeoutSeconds, bool mergeStderr=false)
Runs a command, capturing stdout and discarding stderr.
std::string trim(const std::string &s)
Trims ASCII whitespace from both ends, as Java's String.trim() does.
Conservation laws of a layered queueing network, enumerated from its structure.
Outcome of a captured command.
int exitCode
Exit status, or -1 when the command could not run.
std::string out
Everything the command wrote to stdout.
Running an external command and capturing its output, with a deadline.