Loading src/apps.cpp +15 −0 Changes for src/apps.cpp: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -110,6 +110,9 @@ Result listApps(size_t from) { json_object *tags = member(a, "tags"); for (size_t t = 0; tags && t < json_object_array_length(tags); ++t) one.add("tag", json_object_get_string(json_object_array_get_idx(tags, t))); json_object *volumes = member(a, "volumes"); for (size_t v = 0; volumes && v < json_object_array_length(volumes); ++v) one.add("volume", json_object_get_string(json_object_array_get_idx(volumes, v))); if (!text(a, "icon").empty()) one.add("icon", text(a, "icon")); size_t bytes = 0; for (auto &f : one.fields) bytes += f.first.size() + f.second.size() + 8; Loading Loading @@ -160,6 +163,18 @@ Result refreshApps() { json_object_object_add(a, "description", json_object_new_string(text(r, "description").c_str())); json_object_object_add(a, "owner", json_object_new_string(text(r, "owner").c_str())); json_object_object_add(a, "tags", tags); // the bind mounts the install dialog proposes; an app without stays one Reference image = ref; image.repo = name; image.tag = json_object_get_string(json_object_array_get_idx(tags, 0)); std::vector<std::string> volumes; err = remoteVolumes(image, volumes); if (!err.empty()) std::cerr << "containerd: apps: " << name << ": " << err << std::endl; if (!volumes.empty()) { json_object *v = json_object_new_array(); for (auto &p : volumes) json_object_array_add(v, json_object_new_string(p.c_str())); json_object_object_add(a, "volumes", v); } std::string icon; if (json_object_get_boolean(member(r, "image")) && reg.api("/api/image" + query + "&w=96", icon, err) && !icon.empty() && icon.size() <= MaxIcon) Loading src/images.cpp +55 −23 Changes for src/images.cpp: 55 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -139,6 +139,37 @@ void collectLayers() { close(lock); } // the manifest of ref for this machine, the entry of a multi-platform image // when it is one; "" or why not (code: the HTTP status) std::string platformManifest(Registry ®, const Reference &ref, json_object *&m, std::string &mediaType, std::string &digest, int &code) { std::string body, err; if (!reg.manifest(ref.digest.empty() ? ref.tag : ref.digest, body, mediaType, digest, err)) return err; m = json_tokener_parse(body.c_str()); if (!m) return tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"); json_object *list = nullptr; if (json_object_object_get_ex(m, "manifests", &list) && json_object_is_type(list, json_type_array)) { std::string arch = goArch(), pick; for (size_t i = 0; i < json_object_array_length(list) && pick.empty(); ++i) { json_object *e = json_object_array_get_idx(list, i), *plat = nullptr; if (!json_object_object_get_ex(e, "platform", &plat)) continue; if (str(plat, "os") == "linux" && str(plat, "architecture") == arch && (arch != "arm" || str(plat, "variant") == "v7" || str(plat, "variant").empty())) pick = str(e, "digest"); } json_object_put(m); m = nullptr; if (pick.empty()) { code = 404; return tr("%1 has no image for linux/%2", "%1 hat kein Image für linux/%2", {ref.str(), arch}); } if (!reg.manifest(pick, body, mediaType, digest, err)) return err; m = json_tokener_parse(body.c_str()); if (!m) return tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"); } return ""; } } // namespace std::string normalizeRef(const std::string &ref) { Loading Loading @@ -191,6 +222,25 @@ std::vector<Image> allImages() { return out; } std::string remoteVolumes(const Reference &ref, std::vector<std::string> &volumes) { Registry reg(ref); std::string mediaType, digest, cfgText, err; json_object *m = nullptr; int code = 500; err = platformManifest(reg, ref, m, mediaType, digest, code); if (!err.empty()) return err; json_object *cfgRef = nullptr; std::string configDigest = json_object_object_get_ex(m, "config", &cfgRef) ? str(cfgRef, "digest") : ""; json_object_put(m); if (configDigest.empty()) return tr("the manifest names no image config", "das Manifest nennt keine Image-Konfiguration"); if (!reg.blob(configDigest, cfgText, err)) return err; json_object *cfg = json_tokener_parse(cfgText.c_str()), *conf = nullptr; if (!cfg) return tr("the registry sent no valid image config", "die Registry schickte keine gültige Image-Konfiguration"); if (json_object_object_get_ex(cfg, "config", &conf)) volumes = keys(conf, "Volumes"); json_object_put(cfg); return ""; } Result pullImage(const std::string &text) { Reference ref; std::string err = parseReference(text, ref); Loading @@ -208,29 +258,11 @@ Result pullImage(const std::string &text) { Registry reg(ref); jobs::progress(tr("reading the manifest", "Manifest wird gelesen")); std::string body, mediaType, digest; if (!reg.manifest(ref.digest.empty() ? ref.tag : ref.digest, body, mediaType, digest, err)) return fail(err, 500); json_object *m = json_tokener_parse(body.c_str()); if (!m) return fail(tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"), 500); // a multi-platform image: the manifest for this machine json_object *list = nullptr; if (json_object_object_get_ex(m, "manifests", &list) && json_object_is_type(list, json_type_array)) { std::string arch = goArch(), pick; for (size_t i = 0; i < json_object_array_length(list) && pick.empty(); ++i) { json_object *e = json_object_array_get_idx(list, i), *plat = nullptr; if (!json_object_object_get_ex(e, "platform", &plat)) continue; if (str(plat, "os") == "linux" && str(plat, "architecture") == arch && (arch != "arm" || str(plat, "variant") == "v7" || str(plat, "variant").empty())) pick = str(e, "digest"); } json_object_put(m); if (pick.empty()) return fail(tr("%1 has no image for linux/%2", "%1 hat kein Image für linux/%2", {ref.str(), arch}), 404); if (!reg.manifest(pick, body, mediaType, digest, err)) return fail(err, 500); m = json_tokener_parse(body.c_str()); if (!m) return fail(tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"), 500); } std::string mediaType, digest; json_object *m = nullptr; int code = 500; err = platformManifest(reg, ref, m, mediaType, digest, code); if (!err.empty()) return fail(err, code); json_object *cfgRef = nullptr, *layers = nullptr; if (!json_object_object_get_ex(m, "config", &cfgRef) || !json_object_object_get_ex(m, "layers", &layers) || !json_object_is_type(layers, json_type_array)) { Loading src/images.h +4 −0 Changes for src/images.h: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace containerd { struct Reference; struct Image { std::string ref; // normalized: docker.io/library/nginx:latest std::string digest, id; // manifest digest, config digest Loading @@ -65,6 +67,8 @@ std::string layerDir(const std::string &diffIdHex); // the work of PullImage (in a job); "image" and "id" on success Result pullImage(const std::string &ref); // the VOLUMEs of an image in its registry, without pulling it; "" or why not std::string remoteVolumes(const Reference &ref, std::vector<std::string> &volumes); // RemoveImage; usedBy: the containers on it (refused if any) Result removeImage(const std::string &ref, const std::vector<std::string> &usedBy); Loading Loading
src/apps.cpp +15 −0 Changes for src/apps.cpp: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -110,6 +110,9 @@ Result listApps(size_t from) { json_object *tags = member(a, "tags"); for (size_t t = 0; tags && t < json_object_array_length(tags); ++t) one.add("tag", json_object_get_string(json_object_array_get_idx(tags, t))); json_object *volumes = member(a, "volumes"); for (size_t v = 0; volumes && v < json_object_array_length(volumes); ++v) one.add("volume", json_object_get_string(json_object_array_get_idx(volumes, v))); if (!text(a, "icon").empty()) one.add("icon", text(a, "icon")); size_t bytes = 0; for (auto &f : one.fields) bytes += f.first.size() + f.second.size() + 8; Loading Loading @@ -160,6 +163,18 @@ Result refreshApps() { json_object_object_add(a, "description", json_object_new_string(text(r, "description").c_str())); json_object_object_add(a, "owner", json_object_new_string(text(r, "owner").c_str())); json_object_object_add(a, "tags", tags); // the bind mounts the install dialog proposes; an app without stays one Reference image = ref; image.repo = name; image.tag = json_object_get_string(json_object_array_get_idx(tags, 0)); std::vector<std::string> volumes; err = remoteVolumes(image, volumes); if (!err.empty()) std::cerr << "containerd: apps: " << name << ": " << err << std::endl; if (!volumes.empty()) { json_object *v = json_object_new_array(); for (auto &p : volumes) json_object_array_add(v, json_object_new_string(p.c_str())); json_object_object_add(a, "volumes", v); } std::string icon; if (json_object_get_boolean(member(r, "image")) && reg.api("/api/image" + query + "&w=96", icon, err) && !icon.empty() && icon.size() <= MaxIcon) Loading
src/images.cpp +55 −23 Changes for src/images.cpp: 55 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -139,6 +139,37 @@ void collectLayers() { close(lock); } // the manifest of ref for this machine, the entry of a multi-platform image // when it is one; "" or why not (code: the HTTP status) std::string platformManifest(Registry ®, const Reference &ref, json_object *&m, std::string &mediaType, std::string &digest, int &code) { std::string body, err; if (!reg.manifest(ref.digest.empty() ? ref.tag : ref.digest, body, mediaType, digest, err)) return err; m = json_tokener_parse(body.c_str()); if (!m) return tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"); json_object *list = nullptr; if (json_object_object_get_ex(m, "manifests", &list) && json_object_is_type(list, json_type_array)) { std::string arch = goArch(), pick; for (size_t i = 0; i < json_object_array_length(list) && pick.empty(); ++i) { json_object *e = json_object_array_get_idx(list, i), *plat = nullptr; if (!json_object_object_get_ex(e, "platform", &plat)) continue; if (str(plat, "os") == "linux" && str(plat, "architecture") == arch && (arch != "arm" || str(plat, "variant") == "v7" || str(plat, "variant").empty())) pick = str(e, "digest"); } json_object_put(m); m = nullptr; if (pick.empty()) { code = 404; return tr("%1 has no image for linux/%2", "%1 hat kein Image für linux/%2", {ref.str(), arch}); } if (!reg.manifest(pick, body, mediaType, digest, err)) return err; m = json_tokener_parse(body.c_str()); if (!m) return tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"); } return ""; } } // namespace std::string normalizeRef(const std::string &ref) { Loading Loading @@ -191,6 +222,25 @@ std::vector<Image> allImages() { return out; } std::string remoteVolumes(const Reference &ref, std::vector<std::string> &volumes) { Registry reg(ref); std::string mediaType, digest, cfgText, err; json_object *m = nullptr; int code = 500; err = platformManifest(reg, ref, m, mediaType, digest, code); if (!err.empty()) return err; json_object *cfgRef = nullptr; std::string configDigest = json_object_object_get_ex(m, "config", &cfgRef) ? str(cfgRef, "digest") : ""; json_object_put(m); if (configDigest.empty()) return tr("the manifest names no image config", "das Manifest nennt keine Image-Konfiguration"); if (!reg.blob(configDigest, cfgText, err)) return err; json_object *cfg = json_tokener_parse(cfgText.c_str()), *conf = nullptr; if (!cfg) return tr("the registry sent no valid image config", "die Registry schickte keine gültige Image-Konfiguration"); if (json_object_object_get_ex(cfg, "config", &conf)) volumes = keys(conf, "Volumes"); json_object_put(cfg); return ""; } Result pullImage(const std::string &text) { Reference ref; std::string err = parseReference(text, ref); Loading @@ -208,29 +258,11 @@ Result pullImage(const std::string &text) { Registry reg(ref); jobs::progress(tr("reading the manifest", "Manifest wird gelesen")); std::string body, mediaType, digest; if (!reg.manifest(ref.digest.empty() ? ref.tag : ref.digest, body, mediaType, digest, err)) return fail(err, 500); json_object *m = json_tokener_parse(body.c_str()); if (!m) return fail(tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"), 500); // a multi-platform image: the manifest for this machine json_object *list = nullptr; if (json_object_object_get_ex(m, "manifests", &list) && json_object_is_type(list, json_type_array)) { std::string arch = goArch(), pick; for (size_t i = 0; i < json_object_array_length(list) && pick.empty(); ++i) { json_object *e = json_object_array_get_idx(list, i), *plat = nullptr; if (!json_object_object_get_ex(e, "platform", &plat)) continue; if (str(plat, "os") == "linux" && str(plat, "architecture") == arch && (arch != "arm" || str(plat, "variant") == "v7" || str(plat, "variant").empty())) pick = str(e, "digest"); } json_object_put(m); if (pick.empty()) return fail(tr("%1 has no image for linux/%2", "%1 hat kein Image für linux/%2", {ref.str(), arch}), 404); if (!reg.manifest(pick, body, mediaType, digest, err)) return fail(err, 500); m = json_tokener_parse(body.c_str()); if (!m) return fail(tr("the registry sent no valid manifest", "die Registry schickte kein gültiges Manifest"), 500); } std::string mediaType, digest; json_object *m = nullptr; int code = 500; err = platformManifest(reg, ref, m, mediaType, digest, code); if (!err.empty()) return fail(err, code); json_object *cfgRef = nullptr, *layers = nullptr; if (!json_object_object_get_ex(m, "config", &cfgRef) || !json_object_object_get_ex(m, "layers", &layers) || !json_object_is_type(layers, json_type_array)) { Loading
src/images.h +4 −0 Changes for src/images.h: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace containerd { struct Reference; struct Image { std::string ref; // normalized: docker.io/library/nginx:latest std::string digest, id; // manifest digest, config digest Loading @@ -65,6 +67,8 @@ std::string layerDir(const std::string &diffIdHex); // the work of PullImage (in a job); "image" and "id" on success Result pullImage(const std::string &ref); // the VOLUMEs of an image in its registry, without pulling it; "" or why not std::string remoteVolumes(const Reference &ref, std::vector<std::string> &volumes); // RemoveImage; usedBy: the containers on it (refused if any) Result removeImage(const std::string &ref, const std::vector<std::string> &usedBy); Loading