Commit 7967072f authored by jan.koester's avatar jan.koester
Browse files

test

parent 3f2303ea
Loading
Loading
Loading
Loading
+15 −0
Changes for src/apps.cpp: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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;
@@ -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)
+55 −23
Changes for src/images.cpp: 55 added lines, 23 removed lines.
Original line number Diff line number Diff line
@@ -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 &reg, 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) {
@@ -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);
@@ -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)) {
+4 −0
Changes for src/images.h: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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
@@ -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);