oci_common_operators.c 14.7 KB
Newer Older
D
dogsheng 已提交
1 2
/******************************************************************************
 * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
3 4 5 6
 * iSulad licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
D
dogsheng 已提交
7 8 9
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
10
 * See the Mulan PSL v2 for more details.
D
dogsheng 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23
 * Author: liuhao
 * Create: 2019-07-23
 * Description: provide image common function definition
 ******************************************************************************/
#include "oci_common_operators.h"
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <sys/utsname.h>
#include <ctype.h>

H
haozi007 已提交
24
#include "isula_libutils/log.h"
D
dogsheng 已提交
25 26 27 28 29
#include "utils.h"
#include "specs_extend.h"
#include "oci_config_merge.h"

#include "filters.h"
30
#include "storage.h"
D
dogsheng 已提交
31 32 33 34 35 36 37

bool oci_detect(const char *image_name)
{
    if (image_name == NULL) {
        return false;
    }

L
LiFeng 已提交
38
    return storage_image_exist(image_name);
D
dogsheng 已提交
39 40 41 42
}

char *oci_resolve_image_name(const char *name)
{
L
LiFeng 已提交
43
    if (util_valid_short_sha256_id(name) && storage_image_exist(name)) {
D
dogsheng 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        return util_strdup_s(name);
    }

    return oci_normalize_image_name(name);
}


static void oci_strip_dockerio(const imagetool_image *image)
{
    char *repo_tag = NULL;
    char *repo_digest = NULL;
    size_t i = 0;

    if (image == NULL) {
        return;
    }

    for (i = 0; i < image->repo_tags_len; i++) {
        repo_tag = image->repo_tags[i];
        image->repo_tags[i] = oci_strip_dockerio_prefix(repo_tag);
        free(repo_tag);
        repo_tag = NULL;
    }

    for (i = 0; i < image->repo_digests_len; i++) {
        repo_digest = image->repo_digests[i];
        image->repo_digests[i] = oci_strip_dockerio_prefix(repo_digest);
        free(repo_digest);
        repo_digest = NULL;
    }

    return;
}

78
int oci_get_user_conf(const char *basefs, host_config *hc, const char *userstr, defs_process_user *puser)
D
dogsheng 已提交
79 80 81 82 83 84 85 86 87 88
{
    if (basefs == NULL || puser == NULL) {
        ERROR("Empty basefs or puser");
        return -1;
    }
    return get_user(basefs, hc, userstr, puser);
}

static int oci_list_all_images(imagetool_images_list *images_list)
{
L
LiFeng 已提交
89
    return storage_get_all_images(images_list);
D
dogsheng 已提交
90 91
}

L
LiFeng 已提交
92

D
dogsheng 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static bool image_meet_dangling_filter(const imagetool_image *src, const struct filters_args *filters)
{
    bool ret = false;
    map_t *field_values_map = NULL;
    const char *field = "dangling";
    map_itor *itor = NULL;
    bool dangling_value = false;

    field_values_map = map_search(filters->fields, (void *)field);
    if (field_values_map == NULL) {
        return true;
    }

    itor = map_itor_new(field_values_map);
    if (itor == NULL) {
        ERROR("Out of memory");
        return false;
    }

    for (; map_itor_valid(itor); map_itor_next(itor)) {
        if (strcmp(map_itor_key(itor), "true") == 0) {
            dangling_value = true;
            break;
        }
    }

    if (dangling_value) {
        ret = src->repo_tags_len == 0;
    } else {
        ret = src->repo_tags_len != 0;
    }

    map_itor_free(itor);
    return ret;
}

static int do_image_time_filter(map_itor *itor, bool is_before_filter, int64_t *cmp_nanos)
{
    int ret = 0;
    int64_t tmp_nanos = 0;
L
LiFeng 已提交
133 134
    imagetool_image *image_info = NULL;

D
dogsheng 已提交
135 136 137 138 139 140
    char *tmp = oci_resolve_image_name(map_itor_key(itor));
    if (tmp == NULL) {
        ERROR("Failed to resolve image name");
        goto out;
    }

141
    image_info = storage_img_get(tmp);
D
dogsheng 已提交
142 143 144 145 146
    if (image_info == NULL) {
        ret = -1;
        goto out;
    }

L
LiFeng 已提交
147
    if (to_unix_nanos_from_str(image_info->created, &tmp_nanos) != 0) {
D
dogsheng 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        ERROR("Failed to get unix nano from string");
        ret = -1;
        goto out;
    }

    if (is_before_filter) {
        if (*cmp_nanos > tmp_nanos) {
            *cmp_nanos = tmp_nanos;
        }
    } else {
        if (*cmp_nanos < tmp_nanos) {
            *cmp_nanos = tmp_nanos;
        }
    }

out:
L
LiFeng 已提交
164
    free_imagetool_image(image_info);
D
dogsheng 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    free(tmp);
    return ret;
}

static bool image_time_filter(const imagetool_image *src, const struct filters_args *filters,
                              const char *field)
{
    bool ret = false;
    map_t *field_values_map = NULL;
    map_itor *itor = NULL;
    bool is_before_filter = true;
    int64_t cmp_nanos;
    int64_t tmp_nanos = 0;

    is_before_filter = (strcmp(field, "before") == 0);
    cmp_nanos = is_before_filter ? INT64_MAX : 0;

    field_values_map = map_search(filters->fields, (void *)field);
    if (field_values_map == NULL) {
        return true;
    }

    itor = map_itor_new(field_values_map);
    if (itor == NULL) {
        ERROR("Out of memory");
        return false;
    }

    for (; map_itor_valid(itor); map_itor_next(itor)) {
        if (do_image_time_filter(itor, is_before_filter, &cmp_nanos) != 0) {
            goto out;
        }
    }

    if (to_unix_nanos_from_str(src->created, &tmp_nanos) != 0) {
        ERROR("Failed to get unix nano from string");
        goto out;
    }

    if (is_before_filter) {
        if (tmp_nanos < cmp_nanos) {
            ret = true;
        }
    } else {
        if (tmp_nanos > cmp_nanos) {
            ret = true;
        }
    }

out:
    map_itor_free(itor);
    return ret;
}

static bool image_meet_before_filter(const imagetool_image *src, const struct filters_args *filters)
{
    return image_time_filter(src, filters, "before");
}

static bool image_meet_since_filter(const imagetool_image *src, const struct filters_args *filters)
{
    return image_time_filter(src, filters, "since");
}

static bool image_meet_label_filter(const imagetool_image *src, const struct filters_args *filters)
{
    bool ret = false;
    map_t *field_values_map = NULL;
    const char *field = "label";
    map_itor *itor = NULL;
    size_t i;

    field_values_map = map_search(filters->fields, (void *)field);
    if (field_values_map == NULL) {
        return true;
    }

    if (src->spec->config == NULL || src->spec->config->labels == NULL) {
        return false;
    }

    itor = map_itor_new(field_values_map);
    if (itor == NULL) {
        ERROR("Out of memory");
        return false;
    }

    for (; map_itor_valid(itor); map_itor_next(itor)) {
        char *tmp_key = map_itor_key(itor);
        if (tmp_key == NULL) {
            ERROR("Invalid labels");
            ret = false;
            goto out;
        }
        for (i = 0; i < src->spec->config->labels->len; i++) {
            if (strcmp(tmp_key, src->spec->config->labels->keys[i]) == 0) {
                ret = true;
                goto out;
            }
        }
    }

out:
    map_itor_free(itor);
    return ret;
}

static bool image_meet_reference_filter(const imagetool_image *src, const struct filters_args *filters)
{
    size_t i;
    size_t len = src->repo_tags_len;

    map_t *field_values_map = map_search(filters->fields, (void *)"reference");
    if (field_values_map == NULL) {
        return true;
    }

    for (i = 0; i < len; i++) {
        if (filters_args_match(filters, "reference", src->repo_tags[i])) {
            return true;
        }
    }

    return false;
}

static bool image_meet_filters(const imagetool_image *src, const struct filters_args *filters)
{
    return image_meet_dangling_filter(src, filters) &&
           image_meet_before_filter(src, filters) &&
           image_meet_since_filter(src, filters) &&
           image_meet_label_filter(src, filters) &&
           image_meet_reference_filter(src, filters);
}

L
LiFeng 已提交
300
static int dup_oci_image_info_by_filters(const imagetool_image *src, const struct filters_args *filters,
D
dogsheng 已提交
301 302 303 304 305 306 307 308 309
                                         imagetool_images_list *images_list)
{
    int ret = 0;
    char *json = NULL;
    parser_error err = NULL;
    imagetool_image **tmp_images = NULL;
    imagetool_image *tmp_image = NULL;
    size_t new_size, old_size;

L
LiFeng 已提交
310
    if (src == NULL) {
D
dogsheng 已提交
311 312 313
        goto out;
    }

L
LiFeng 已提交
314
    if (!image_meet_filters(src, filters)) {
D
dogsheng 已提交
315 316 317
        goto out;
    }

L
LiFeng 已提交
318
    json = imagetool_image_generate_json(src, NULL, &err);
D
dogsheng 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    if (json == NULL) {
        ERROR("Failed to generate json: %s", err);
        ret = -1;
        goto out;
    }

    tmp_image = imagetool_image_parse_data(json, NULL, &err);
    if (tmp_image == NULL) {
        ERROR("Failed to parse json: %s", err);
        ret = -1;
        goto out;
    }

    if (images_list->images_len > SIZE_MAX / sizeof(imagetool_image *) - 1) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    new_size = (images_list->images_len + 1) * sizeof(imagetool_image *);
    old_size = images_list->images_len * sizeof(imagetool_image *);

    ret = mem_realloc((void **)(&tmp_images), new_size, images_list->images, old_size);
    if (ret != 0) {
        ERROR("Failed to realloc memory for append images");
        ret = -1;
        goto out;
    }
    images_list->images = tmp_images;
    images_list->images[images_list->images_len] = tmp_image;
    tmp_image = NULL;
    images_list->images_len++;

    ret = 0;

out:
    free(err);
    free(json);
    free_imagetool_image(tmp_image);
    return ret;
}

static int oci_list_images_by_filters(struct filters_args *filters, imagetool_images_list *images_list)
{
    int ret = 0;
    int nret;
    size_t i = 0;
L
LiFeng 已提交
366
    imagetool_images_list *all_images = NULL;
D
dogsheng 已提交
367

L
LiFeng 已提交
368 369 370 371 372
    all_images = util_common_calloc_s(sizeof(imagetool_images_list));
    if (all_images == NULL) {
        ERROR("Memory out");
        ret = -1;
        goto out;
D
dogsheng 已提交
373 374
    }

L
LiFeng 已提交
375 376 377
    if (storage_get_all_images(all_images) != 0) {
        ERROR("Failed to get all images info");
        ret = -1;
D
dogsheng 已提交
378 379 380
        goto out;
    }

L
LiFeng 已提交
381 382
    for (i = 0; i < all_images->images_len; i++) {
        nret = dup_oci_image_info_by_filters(all_images->images[i], filters, images_list);
D
dogsheng 已提交
383 384 385 386 387 388
        if (nret != 0) {
            WARN("Failed to dup oci image info");
        }
    }

out:
L
LiFeng 已提交
389
    free_imagetool_images_list(all_images);
D
dogsheng 已提交
390 391
    return ret;
}
L
LiFeng 已提交
392

D
dogsheng 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
static void oci_strip_all_dockerios(const imagetool_images_list *images)
{
    size_t i = 0;

    if (images == NULL) {
        return;
    }

    for (i = 0; i < images->images_len; i++) {
        oci_strip_dockerio(images->images[i]);
    }

    return;
}

int oci_list_images(const im_list_request *request, imagetool_images_list **images)
{
    int ret = 0;
    struct filters_args *image_filters = NULL;

    if (request != NULL && request->image_filters != NULL) {
        image_filters = request->image_filters;
    }

    *images = util_common_calloc_s(sizeof(imagetool_images_list));
    if (*images == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (image_filters != NULL) {
L
LiFeng 已提交
425
        ret = oci_list_images_by_filters(image_filters, *images);
D
dogsheng 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439
    } else {
        ret = oci_list_all_images(*images);
    }

    oci_strip_all_dockerios(*images);

out:
    if (ret != 0) {
        free_imagetool_images_list(*images);
        *images = NULL;
    }
    return ret;
}

L
LiFeng 已提交
440 441
size_t oci_get_images_count(void)
{
442
    return storage_get_img_count();
L
LiFeng 已提交
443 444
}

D
dogsheng 已提交
445 446 447
int oci_status_image(im_status_request *request, im_status_response **response)
{
    int ret = 0;
448 449
    imagetool_image_status *image_status = NULL;
    imagetool_image *image_info = NULL;
D
dogsheng 已提交
450 451 452 453 454 455 456 457
    char *image_ref = NULL;
    char *resolved_name = NULL;

    if (*response == NULL) {
        ERROR("Invalid arguments");
        return -1;
    }

458 459
    image_status = util_common_calloc_s(sizeof(imagetool_image_status));
    if (image_status == NULL) {
D
dogsheng 已提交
460 461 462 463
        ERROR("Out of memory");
        ret = -1;
        goto pack_response;
    }
464
    (*response)->image_info = image_status;
D
dogsheng 已提交
465 466 467 468

    image_ref = request->image.image;
    if (image_ref == NULL) {
        ERROR("Inspect image requires image ref");
L
LiuHao 已提交
469
        isulad_set_error_message("Inspect image requires image ref");
D
dogsheng 已提交
470 471 472 473 474 475 476
        ret = -1;
        goto pack_response;
    }

    resolved_name = oci_resolve_image_name(image_ref);
    if (resolved_name == NULL) {
        ERROR("Failed to reslove image name %s", image_ref);
L
LiuHao 已提交
477
        isulad_set_error_message("Failed to reslove image name %s", image_ref);
D
dogsheng 已提交
478 479 480 481 482 483
        ret = -1;
        goto pack_response;
    }

    EVENT("Event: {Object: %s, Type: statusing image}", resolved_name);

484
    image_info = storage_img_get(resolved_name);
D
dogsheng 已提交
485 486
    if (image_info == NULL) {
        ERROR("No such image:%s", resolved_name);
L
LiuHao 已提交
487
        isulad_set_error_message("No such image:%s", resolved_name);
D
dogsheng 已提交
488 489 490 491
        ret = -1;
        goto pack_response;
    }

492 493 494 495
    oci_strip_dockerio(image_info);

    (*response)->image_info->image = image_info;
    image_info = NULL;
D
dogsheng 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

    EVENT("Event: {Object: %s, Type: statused image}", resolved_name);

pack_response:
    free(resolved_name);
    return ret;
}

int oci_inspect_image(const im_inspect_request *im_request, char **inspected_json)
{
    int ret = 0;
    im_status_request request;
    im_status_response *response = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;

    if (im_request == NULL || inspected_json == NULL) {
        ERROR("Invalid input arguments");
        return -1;
    }

O
openeuler-iSula 已提交
517 518
    (void)memset(&request, 0, sizeof(im_status_request));

D
dogsheng 已提交
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
    request.image.image = im_request->image.image;

    response = (im_status_response *)util_common_calloc_s(sizeof(im_status_response));
    if (response == NULL) {
        ERROR("Out of memory");
        goto out;
    }

    ret = oci_status_image(&request, &response);
    if (ret != 0) {
        goto out;
    }

    *inspected_json = imagetool_image_status_generate_json(response->image_info, &ctx, &err);
    if (*inspected_json == NULL) {
        ERROR("Failed to generate image status request json:%s", err);
        ret = -1;
        goto out;
    }

out:
    free(err);
    free_im_status_response(response);
    return ret;
}

545
int oci_image_conf_merge_into_spec(const char *image_name, container_config *container_spec)
D
dogsheng 已提交
546 547 548
{
    int ret = 0;
    char *resolved_name = NULL;
549
    imagetool_image *image_info = NULL;
D
dogsheng 已提交
550

551
    if (container_spec == NULL || image_name == NULL) {
D
dogsheng 已提交
552 553 554 555 556 557 558 559 560 561 562
        ERROR("invalid NULL param");
        return -1;
    }

    resolved_name = oci_resolve_image_name(image_name);
    if (resolved_name == NULL) {
        ERROR("Resolve external config image name failed, image name is %s", image_name);
        ret = -1;
        goto out;
    }

563
    image_info = storage_img_get(resolved_name);
D
dogsheng 已提交
564 565 566 567 568
    if (image_info == NULL) {
        ERROR("Get image from image store failed, image name is %s", resolved_name);
        ret = -1;
        goto out;
    }
569 570

    ret = oci_image_merge_config(image_info, container_spec);
D
dogsheng 已提交
571 572 573 574 575 576 577 578 579 580 581
    if (ret != 0) {
        ERROR("Failed to merge oci config for image %s", resolved_name);
        ret = -1;
        goto out;
    }

out:
    free(resolved_name);
    return ret;
}