338 lines
11 KiB
C
Raw Normal View History

2019-09-30 10:53:41 -04:00
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
* iSulad licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* 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.
* See the Mulan PSL v1 for more details.
* Author: lifeng
* Create: 2018-11-08
* Description: provide container image functions
******************************************************************************/
#include "images.h"
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include "utils.h"
#include "arguments.h"
#include "isula_connect.h"
2019-09-30 10:53:41 -04:00
#include "log.h"
2019-12-25 15:50:34 +08:00
#define IMAGES_OPTIONS(cmdargs) \
{ 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", command_append_array }
2019-09-30 10:53:41 -04:00
#define CREATED_DISPLAY_FORMAT "YYYY-MM-DD HH:MM:SS"
#define SHORT_DIGEST_LEN 12
const char g_cmd_images_desc[] = "List images";
const char g_cmd_images_usage[] = "images";
struct client_arguments g_cmd_images_args = {};
/* keep track of field widths for printing. */
struct lengths {
2019-12-25 15:50:34 +08:00
unsigned int registry_length;
unsigned int tag_length;
2019-09-30 10:53:41 -04:00
unsigned int digest_length;
unsigned int created_length;
unsigned int size_length;
};
/* trans time */
static char *trans_time(int64_t created)
{
struct tm t;
int nret = 0;
char formated_time[sizeof(CREATED_DISPLAY_FORMAT)] = { 0 };
time_t created_time = (time_t)created;
if (!localtime_r(&created_time, &t)) {
ERROR("translate time for created failed: %s", strerror(errno));
return NULL;
}
nret = snprintf(formated_time, sizeof(formated_time), "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
if (nret < 0 || nret >= sizeof(formated_time)) {
2019-09-30 10:53:41 -04:00
ERROR("format created time failed");
return NULL;
}
return util_strdup_s(formated_time);
}
/* list print table */
static void list_print_table(struct isula_image_info *images_list, const size_t size, const struct lengths *length)
2019-09-30 10:53:41 -04:00
{
const struct isula_image_info *in = NULL;
2019-09-30 10:53:41 -04:00
size_t i = 0;
char *created = NULL;
char *digest = NULL;
char *image_size = NULL;
if (length == NULL) {
return;
}
/* print header */
2019-12-25 15:50:34 +08:00
printf("%-*s ", (int)length->registry_length, "REPOSITORY");
printf("%-*s ", (int)length->tag_length, "TAG");
2019-09-30 10:53:41 -04:00
printf("%-*s ", (int)length->digest_length, "IMAGE ID");
printf("%-*s ", (int)length->created_length, "CREATED");
printf("%-*s ", (int)length->size_length, "SIZE");
printf("\n");
for (i = 0, in = images_list; i < size && in != NULL; i++, in++) {
2019-12-25 15:50:34 +08:00
if (in->imageref == NULL || strcmp(in->imageref, "-") == 0) {
printf("%-*s ", (int)length->registry_length, "<none>");
printf("%-*s ", (int)length->tag_length, "<none>");
} else {
char *copy_name = util_strdup_s(in->imageref);
char *tag_pos = util_tag_pos(copy_name);
if (tag_pos == NULL) {
printf("%-*s ", (int)length->registry_length, copy_name);
printf("%-*s ", (int)length->tag_length, "<none>");
} else {
*tag_pos = '\0';
tag_pos++;
printf("%-*s ", (int)length->registry_length, copy_name);
printf("%-*s ", (int)length->tag_length, tag_pos);
tag_pos--;
*tag_pos = ':';
}
free(copy_name);
}
2019-09-30 10:53:41 -04:00
digest = util_short_digest(in->digest);
printf("%-*s ", (int)length->digest_length, digest ? digest : "-");
free(digest);
created = trans_time(in->created);
printf("%-*s ", (int)length->created_length, created ? created : "-");
free(created);
image_size = util_human_size_decimal(in->size);
printf("%-*s ", (int)length->size_length, image_size ? image_size : "-");
free(image_size);
printf("\n");
}
}
static int update_image_ref_width(const struct isula_image_info *in, struct lengths *l)
2019-12-25 15:50:34 +08:00
{
size_t len;
char *copy_name = util_strdup_s(in->imageref);
char *tag_pos = util_tag_pos(copy_name);
if (tag_pos == NULL) {
len = strlen(copy_name);
if (len > l->registry_length) {
l->registry_length = (unsigned int)len;
}
len = strlen("<none>");
if (len > l->tag_length) {
l->tag_length = (unsigned int)len;
}
} else {
*tag_pos = '\0';
tag_pos++;
len = strlen(copy_name);
if (len > l->registry_length) {
l->registry_length = (unsigned int)len;
}
len = strlen(tag_pos);
if (len > l->tag_length) {
l->tag_length = (unsigned int)len;
}
tag_pos--;
*tag_pos = ':';
}
free(copy_name);
return 0;
}
2019-09-30 10:53:41 -04:00
/* list field width */
static void list_field_width(const struct isula_image_info *images_list, const size_t size, struct lengths *l)
2019-09-30 10:53:41 -04:00
{
const struct isula_image_info *in = NULL;
2019-09-30 10:53:41 -04:00
size_t i = 0;
char tmpbuffer[30];
for (i = 0, in = images_list; i < size && in != NULL; i++, in++) {
size_t len;
int slen;
if (in->imageref) {
2019-12-25 15:50:34 +08:00
if (update_image_ref_width(in, l) != 0) {
return;
2019-09-30 10:53:41 -04:00
}
}
if (in->digest) {
len = SHORT_DIGEST_LEN;
if (len > l->digest_length) {
l->digest_length = (unsigned int)len;
}
}
if (in->created) {
len = strlen(CREATED_DISPLAY_FORMAT);
if (len > l->created_length) {
l->created_length = (unsigned int)len;
}
}
slen = snprintf(tmpbuffer, sizeof(tmpbuffer), "%.2f", (float)(in->size) / (1024 * 1024));
if (slen < 0 || (size_t)slen >= sizeof(tmpbuffer)) {
2019-09-30 10:53:41 -04:00
ERROR("sprintf tmpbuffer failed");
return;
}
if ((unsigned int)slen > l->size_length) {
l->size_length = (unsigned int)slen;
}
}
}
/*
* list all images from isulad
2019-09-30 10:53:41 -04:00
*/
static void images_info_print(const struct isula_list_images_response *response)
2019-09-30 10:53:41 -04:00
{
struct lengths max_len = {
2019-12-25 15:50:34 +08:00
.registry_length = 30, /* registry */
.tag_length = 10, /* tag */
2019-09-30 10:53:41 -04:00
.digest_length = 20, /* digest */
.created_length = 20, /* created */
.size_length = 10, /* size */
};
list_field_width(response->images_list, (size_t)response->images_num, &max_len);
list_print_table(response->images_list, (size_t)response->images_num, &max_len);
}
/* images info print quiet */
static void images_info_print_quiet(const struct isula_list_images_response *response)
2019-09-30 10:53:41 -04:00
{
const struct isula_image_info *in = NULL;
2019-09-30 10:53:41 -04:00
size_t i = 0;
for (i = 0, in = response->images_list; in != NULL && i < response->images_num; i++, in++) {
2019-12-25 15:50:34 +08:00
char *digest = util_short_digest(in->digest);
printf("%-*s ", SHORT_DIGEST_LEN, digest ? digest : "<none>");
2019-09-30 10:53:41 -04:00
printf("\n");
2019-12-25 15:50:34 +08:00
free(digest);
2019-09-30 10:53:41 -04:00
}
}
/*
* used by qsort function for comparing image created time
*/
static inline int isula_image_cmp(struct isula_image_info *first, struct isula_image_info *second)
2019-09-30 10:53:41 -04:00
{
if (second->created > first->created) {
return 1;
} else if (second->created < first->created) {
return -1;
} else {
return second->created_nanos > first->created_nanos;
}
}
/*
* list the images from remote
*/
static int list_images(const struct client_arguments *args)
{
isula_connect_ops *ops = NULL;
struct isula_list_images_request request = { 0 };
struct isula_list_images_response *response = NULL;
2019-09-30 10:53:41 -04:00
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct isula_list_images_response));
2019-09-30 10:53:41 -04:00
if (response == NULL) {
ERROR("Imagelist: Out of memory");
return -1;
}
ops = get_connect_client_ops();
if (ops == NULL || ops->image.list == NULL) {
ERROR("Unimplemented image list op");
ret = -1;
goto out;
}
2019-12-25 15:50:34 +08:00
if (args->filters != NULL) {
request.filters = isula_filters_parse_args((const char **)args->filters,
util_array_len((const char **)(args->filters)));
2019-12-25 15:50:34 +08:00
if (request.filters == NULL) {
ERROR("Failed to parse filters args");
ret = -1;
goto out;
}
}
2019-09-30 10:53:41 -04:00
config = get_connect_config(args);
ret = ops->image.list(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
if (response->images_list != NULL && response->images_num > 0) {
qsort(response->images_list, (size_t)(response->images_num), sizeof(struct isula_image_info),
(int (*)(const void *, const void *))isula_image_cmp);
2019-09-30 10:53:41 -04:00
}
if (args->dispname) {
images_info_print_quiet(response);
} else {
images_info_print(response);
}
out:
isula_filters_free(request.filters);
isula_list_images_response_free(response);
2019-09-30 10:53:41 -04:00
return ret;
}
/* cmd images main */
int cmd_images_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
int exit_code = ECOMMON;
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_images_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_images_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
IMAGES_OPTIONS(g_cmd_images_args),
COMMON_OPTIONS(g_cmd_images_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_images_desc,
g_cmd_images_usage);
if (command_parse_args(&cmd, &g_cmd_images_args.argc, &g_cmd_images_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Images: log init failed");
exit(exit_code);
}
if (list_images(&g_cmd_images_args)) {
ERROR("Can not list any images");
exit(exit_code);
}
exit(EXIT_SUCCESS);
}
2019-11-06 19:33:20 +08:00