diff --git a/src/api/services/images/images.proto b/src/api/services/images/images.proto index 71cce227172728d46d50cece2beb4e92098e9aa7..3bfc222824d6e541ab4fae113ae848421e2e992c 100644 --- a/src/api/services/images/images.proto +++ b/src/api/services/images/images.proto @@ -43,6 +43,7 @@ message Image { Descriptor target = 3; google.protobuf.Timestamp created_at = 4; google.protobuf.Timestamp updated_at = 5; + string digest = 6; } message ListImagesRequest { diff --git a/src/client/connect/grpc/grpc_images_client.cc b/src/client/connect/grpc/grpc_images_client.cc index 1bc12e69070cd211917741c63492a1e88dcd0844..0528871c559692717d941e33bbf1c1f52c2abdd7 100644 --- a/src/client/connect/grpc/grpc_images_client.cc +++ b/src/client/connect/grpc/grpc_images_client.cc @@ -84,8 +84,8 @@ public: const char *media_type = !image.target().media_type().empty() ? image.target().media_type().c_str() : "-"; images_list[i].type = util_strdup_s(media_type); - const char *digest = !image.target().digest().empty() ? image.target().digest().c_str() : "-"; - images_list[i].digest = util_strdup_s(digest); + const char *imageid = !image.target().digest().empty() ? image.target().digest().c_str() : "-"; + images_list[i].imageid = util_strdup_s(imageid); images_list[i].size = image.target().size(); } if (image.has_created_at()) { @@ -94,6 +94,8 @@ public: } const char *name = !image.name().empty() ? image.name().c_str() : "-"; images_list[i].imageref = util_strdup_s(name); + const char *digest = !image.digest().empty() ? image.digest().c_str() : "-"; + images_list[i].digest = util_strdup_s(digest); } response->images_list = images_list; diff --git a/src/client/connect/protocol_type.c b/src/client/connect/protocol_type.c index 94f682a8d60f88fb487cf918f81f838db8a8c7a0..daf505e20189ab6fa0e38becf64525b07aa02021 100644 --- a/src/client/connect/protocol_type.c +++ b/src/client/connect/protocol_type.c @@ -953,6 +953,7 @@ void isula_images_list_free(size_t images_num, struct isula_image_info *images_l free(in->imageref); free(in->type); free(in->digest); + free(in->imageid); } free(images_list); diff --git a/src/client/connect/protocol_type.h b/src/client/connect/protocol_type.h index 32f55b51a956485608f36adc6070b928c83ba4bb..e9aa9bd7eabc1601f2b1aaaefcf2cc5996ff68ee 100644 --- a/src/client/connect/protocol_type.h +++ b/src/client/connect/protocol_type.h @@ -428,6 +428,7 @@ struct isula_image_info { char *imageref; char *type; char *digest; + char *imageid; int64_t created; /* seconds */ int32_t created_nanos; int64_t size; /* Bytes */ diff --git a/src/cmd/isula/client_arguments.h b/src/cmd/isula/client_arguments.h index adb45104169dc6be07bed4457d4fd7343b7b21ef..897e552f36caf171a15dd7e1ae0e1fead728489e 100644 --- a/src/cmd/isula/client_arguments.h +++ b/src/cmd/isula/client_arguments.h @@ -292,6 +292,7 @@ struct client_arguments { bool list_all; char **filters; bool no_trunc; + bool digests; // inspect char *format; diff --git a/src/cmd/isula/images/images.c b/src/cmd/isula/images/images.c index 3d538aa51d7a20bddebf392fab9608332bdae2d9..6644af0c7eb31f6319bdb54b90090c1fac1401ce 100644 --- a/src/cmd/isula/images/images.c +++ b/src/cmd/isula/images/images.c @@ -34,6 +34,7 @@ #include "utils_verify.h" #define IMAGES_OPTIONS(cmdargs) \ + { CMD_OPT_TYPE_BOOL, false, "digests", 0, &((cmdargs).digests), "Show digests", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "quiet", 'q', &((cmdargs).dispname), "Only display image names", NULL }, \ { \ CMD_OPT_TYPE_CALLBACK, false, "filter", 'f', &(cmdargs).filters, "Filter output based on conditions provided", \ @@ -52,6 +53,7 @@ struct lengths { unsigned int registry_length; unsigned int tag_length; unsigned int digest_length; + unsigned int imageid_length; unsigned int created_length; unsigned int size_length; }; @@ -85,7 +87,7 @@ static void list_print_table(struct isula_image_info *images_list, const size_t const struct isula_image_info *in = NULL; size_t i = 0; char *created = NULL; - char *digest = NULL; + char *imageid = NULL; char *image_size = NULL; if (length == NULL) { return; @@ -93,7 +95,10 @@ static void list_print_table(struct isula_image_info *images_list, const size_t /* print header */ printf("%-*s ", (int)length->registry_length, "REPOSITORY"); printf("%-*s ", (int)length->tag_length, "TAG"); - printf("%-*s ", (int)length->digest_length, "IMAGE ID"); + if (g_cmd_images_args.digests) { + printf("%-*s ", (int)length->digest_length, "DIGEST"); + } + printf("%-*s ", (int)length->imageid_length, "IMAGE ID"); printf("%-*s ", (int)length->created_length, "CREATED"); printf("%-*s ", (int)length->size_length, "SIZE"); printf("\n"); @@ -119,9 +124,13 @@ static void list_print_table(struct isula_image_info *images_list, const size_t free(copy_name); } - digest = util_short_digest(in->digest); - printf("%-*s ", (int)length->digest_length, digest ? digest : "-"); - free(digest); + if (g_cmd_images_args.digests) { + printf("%-*s ", (int)length->digest_length, in->digest ? in->digest : "-"); + } + + imageid = util_short_digest(in->imageid); + printf("%-*s ", (int)length->imageid_length, imageid ? imageid : "-"); + free(imageid); created = trans_time(in->created); printf("%-*s ", (int)length->created_length, created ? created : "-"); @@ -183,10 +192,10 @@ static void list_field_width(const struct isula_image_info *images_list, const s return; } } - if (in->digest) { + if (in->imageid) { len = SHORT_DIGEST_LEN; - if (len > l->digest_length) { - l->digest_length = (unsigned int)len; + if (len > l->imageid_length) { + l->imageid_length = (unsigned int)len; } } if (in->created) { @@ -215,7 +224,8 @@ static void images_info_print(const struct isula_list_images_response *response) struct lengths max_len = { .registry_length = 30, /* registry */ .tag_length = 10, /* tag */ - .digest_length = 20, /* digest */ + .digest_length = 71, /* digest */ + .imageid_length = 20, /* digest */ .created_length = 20, /* created */ .size_length = 10, /* size */ }; diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.cc b/src/daemon/entry/connect/grpc/grpc_images_service.cc index 57a51ee07d4c3a6500057f4cb5b09578edc4974a..ff3f9bf9ac08bcf4e099ec94d185ae1a0d0b9d3d 100644 --- a/src/daemon/entry/connect/grpc/grpc_images_service.cc +++ b/src/daemon/entry/connect/grpc/grpc_images_service.cc @@ -106,6 +106,9 @@ void ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response * if (response->images[i]->name != nullptr) { image->set_name(response->images[i]->name); } + if (response->images[i]->digest != nullptr) { + image->set_digest(response->images[i]->digest); + } target = new (std::nothrow) Descriptor; if (target == nullptr) { ERROR("Out of memory"); diff --git a/src/daemon/executor/image_cb/image_cb.c b/src/daemon/executor/image_cb/image_cb.c index 156cf88c358c9892cbc7ff95f46cb7ef86810890..01a6c8f1c204a3ba9d955a526feb369379c1398e 100644 --- a/src/daemon/executor/image_cb/image_cb.c +++ b/src/daemon/executor/image_cb/image_cb.c @@ -553,6 +553,46 @@ static bool valid_repo_tags(char * const * const repo_tags, size_t repo_index) return false; } +static bool valid_repo_digest(char * const * const repo_digests, size_t digest_index) +{ + if (repo_digests != NULL && repo_digests[digest_index] != NULL) { + return true; + } + + return false; +} + +static char *get_digest_from_repo_digest(const char *repo_digest) +{ + char **parts = NULL; + char *digest = NULL; + int ret = 0; + + // repo digest format: + // test@sha256:2bf1de4c5264b8ada56ef85e9554acdf8f7141b76720a31d95887bd9ee7220d8 + parts = util_string_split(repo_digest, '@'); + if (parts == NULL || util_array_len((const char **) parts) != 2) { + ret = -1; + goto out; + } + + if (!util_valid_digest(parts[1])) { + ret = -1; + goto out; + } + + digest = util_strdup_s(parts[1]); + +out: + util_free_array(parts); + if (ret != 0) { + free(digest); + digest = NULL; + } + + return digest; +} + static int trans_one_image(image_list_images_response *response, size_t image_index, const imagetool_image_summary *im_image, size_t repo_index) { @@ -573,6 +613,11 @@ static int trans_one_image(image_list_images_response *response, size_t image_in out_image->name = util_strdup_s(im_image->repo_tags[repo_index]); } + // any one of repo_digests contain digest, so we use index 0 + if (valid_repo_digest(im_image->repo_digests, 0)) { + out_image->digest = get_digest_from_repo_digest(im_image->repo_digests[0]); + } + out_image->target = util_common_calloc_s(sizeof(image_descriptor)); if (out_image->target == NULL) { ERROR("Out of memory");