LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
docker_image.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2012-2026, QORE Lab, Imperial College London
3
* All rights reserved.
4
*/
5
#ifndef LINE_IO_DOCKER_IMAGE_H
6
#define LINE_IO_DOCKER_IMAGE_H
7
8
/**
9
* @file
10
* @ingroup line_io
11
* Docker primitives for the backends that legitimately ship an image.
12
*
13
* Port of jar/src/main/java/jline/io/DockerImage.java. In the JAR these are
14
* shared by the JMT backend (imperialqore/jmt-rest) and the Sage symbolic
15
* engine (imperialqore/line-sage-rest); this port has only the second so far.
16
* Each backend owns its image name; this file only answers whether the daemon
17
* is up, whether an image is present, whether there is room to pull it, and
18
* performs the pull.
19
*
20
* LQNS, lqsim and qnsolver are deliberately absent, here as in the JAR: their
21
* licence is an evaluation agreement that forbids redistribution, so LINE runs
22
* them only from a binary the user installed.
23
*
24
* THE STORAGE GUARD IS NOT DECORATION. A pull that fills the filesystem backing
25
* the Docker root breaks every container on the machine, not just LINE's, so a
26
* pull is refused unless the free space clears the larger of 2 GiB and three
27
* times the compressed manifest size. When the free space cannot be determined
28
* the pull is ALLOWED: an unknown is not evidence of a full disk, and refusing
29
* would strand users whose daemon does not report a root dir.
30
*/
31
32
#include <cstddef>
33
#include <cstdlib>
34
#include <string>
35
#include <vector>
36
37
#include <sys/stat.h>
38
#include <sys/statvfs.h>
39
40
#include "
line/util/subprocess.h
"
41
42
namespace
line
{
43
namespace
io
{
44
45
/** Conservative free-space floor required before a pull (2 GiB). */
46
static
const
long
long
DOCKER_DEFAULT_MIN_FREE_BYTES
= 2LL * 1024 * 1024 * 1024;
47
48
/** True if the Docker daemon is reachable. */
49
inline
bool
docker_daemon_available
() {
50
const
util::ProcResult
r =
util::capture
({
"docker"
,
"info"
}, 15);
51
return
r.
exitCode
== 0;
52
}
53
54
/**
55
* @param image the image tag
56
* @return true if it is already present in the local Docker store
57
*/
58
inline
bool
docker_has_local_image
(
const
std::string& image) {
59
if
(image.empty())
return
false
;
60
const
util::ProcResult
r =
util::capture
({
"docker"
,
"images"
,
"-q"
, image}, 15);
61
return
r.
exitCode
== 0 && !
util::trim
(r.
out
).empty();
62
}
63
64
/**
65
* Pulls an image, streaming Docker's progress to stdout and stderr. No timeout.
66
*
67
* @param image the image tag
68
* @return true on success
69
*/
70
inline
bool
docker_pull
(
const
std::string& image) {
71
if
(image.empty())
return
false
;
72
return
util::run_inherit
({
"docker"
,
"pull"
, image}) == 0;
73
}
74
75
namespace
detail {
76
77
/** Usable bytes on the filesystem backing the Docker root dir; -1 if unknown. */
78
inline
long
long
docker_free_bytes() {
79
const
util::ProcResult
r =
80
util::capture
({
"docker"
,
"info"
,
"--format"
,
"{{.DockerRootDir}}"
}, 15);
81
std::string root = r.
exitCode
== 0 ?
util::trim
(r.
out
) : std::string();
82
if
(root.empty()) root =
"/var/lib/docker"
;
83
84
// The root dir may not exist for, or be readable by, this user: walk up to
85
// an existing ancestor so the statvfs reports a real filesystem.
86
struct
stat st;
87
while (!root.empty() && ::stat(root.c_str(), &st) != 0) {
88
const std::size_t slash = root.find_last_of(
'/'
);
89
if (slash == std::string::npos) break;
90
root = slash == 0 ? std::string(
"/"
) : root.substr(0, slash);
91
if (root ==
"/"
) break;
92
}
93
if (root.empty()) root =
"/"
;
94
95
struct
statvfs vfs;
96
if (::statvfs(root.c_str(), &vfs) != 0)
return
-1;
97
const
long
long
usable =
98
static_cast<
long
long
>
(vfs.f_bavail) *
static_cast<
long
long
>
(vfs.f_frsize);
99
return
usable > 0 ? usable : -1;
100
}
101
102
/** On-disk estimate (compressed layer sizes x3), or 0 if it cannot be determined. */
103
inline
long
long
docker_estimate_image_bytes(
const
std::string& image) {
104
const
util::ProcResult r =
util::capture
({
"docker"
,
"manifest"
,
"inspect"
, image}, 30);
105
if
(r.exitCode != 0 || r.out.empty())
return
0;
106
long
long
sum = 0;
107
const
std::string& json = r.
out
;
108
const
std::string key =
"\"size\""
;
109
std::size_t at = 0;
110
while
((at = json.find(key, at)) != std::string::npos) {
111
std::size_t i = at + key.size();
112
while
(i < json.size() && (json[i] ==
' '
|| json[i] ==
':'
|| json[i] ==
'\t'
)) ++i;
113
if
(i < json.size() && json[i] >=
'0'
&& json[i] <=
'9'
)
114
sum += std::atoll(json.c_str() + i);
115
at = i;
116
}
117
return
sum > 0 ? sum * 3 : 0;
118
}
119
120
/** LINE_DOCKER_MIN_FREE_BYTES, or -1 when unset or unparsable. */
121
inline
long
long
docker_override_min_free_bytes() {
122
const
char
* v = std::getenv(
"LINE_DOCKER_MIN_FREE_BYTES"
);
123
if
(v ==
nullptr
|| *v ==
'\0'
)
return
-1;
124
const
long
long
parsed = std::atoll(v);
125
return
parsed > 0 ? parsed : -1;
126
}
127
128
}
// namespace detail
129
130
/**
131
* @param image the image tag
132
* @return true if the Docker storage location has room for it
133
*/
134
inline
bool
docker_has_storage_for
(
const
std::string& image) {
135
const
long
long
free = detail::docker_free_bytes();
136
if
(free < 0)
return
true
;
// could not determine; do not block the pull
137
const
long
long
override
= detail::docker_override_min_free_bytes();
138
if
(
override
> 0)
return
free >=
override
;
139
const
long
long
est = detail::docker_estimate_image_bytes(image);
140
const
long
long
required = est >
DOCKER_DEFAULT_MIN_FREE_BYTES
? est
141
:
DOCKER_DEFAULT_MIN_FREE_BYTES
;
142
return
free >= required;
143
}
144
145
}
// namespace io
146
}
// namespace line
147
148
#endif
// LINE_IO_DOCKER_IMAGE_H
line::io
Definition
docker_image.h:43
line::io::DOCKER_DEFAULT_MIN_FREE_BYTES
static const long long DOCKER_DEFAULT_MIN_FREE_BYTES
Conservative free-space floor required before a pull (2 GiB).
Definition
docker_image.h:46
line::io::docker_has_storage_for
bool docker_has_storage_for(const std::string &image)
Definition
docker_image.h:134
line::io::docker_daemon_available
bool docker_daemon_available()
True if the Docker daemon is reachable.
Definition
docker_image.h:49
line::io::docker_has_local_image
bool docker_has_local_image(const std::string &image)
Definition
docker_image.h:58
line::io::docker_pull
bool docker_pull(const std::string &image)
Pulls an image, streaming Docker's progress to stdout and stderr.
Definition
docker_image.h:70
line::util::run_inherit
int run_inherit(const std::vector< std::string > &argv)
Runs a command with the parent's stdout and stderr, e.g.
Definition
subprocess.h:170
line::util::capture
ProcResult capture(const std::vector< std::string > &argv, int timeoutSeconds, bool mergeStderr=false)
Runs a command, capturing stdout and discarding stderr.
Definition
subprocess.h:82
line::util::trim
std::string trim(const std::string &s)
Trims ASCII whitespace from both ends, as Java's String.trim() does.
Definition
subprocess.h:181
line
Definition
aoi_dist2ph.h:52
line::util::ProcResult
Outcome of a captured command.
Definition
subprocess.h:42
line::util::ProcResult::exitCode
int exitCode
Exit status, or -1 when the command could not run.
Definition
subprocess.h:43
line::util::ProcResult::out
std::string out
Everything the command wrote to stdout.
Definition
subprocess.h:44
subprocess.h
Running an external command and capturing its output, with a deadline.
include
line
io
docker_image.h
Generated by
1.18.0