chiark / gitweb /
import: introduce new mini-daemon systemd-importd, and make machinectl a client to it
[elogind.git] / src / import / import-dkr.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <curl/curl.h>
23 #include <sys/prctl.h>
24
25 #include "set.h"
26 #include "json.h"
27 #include "strv.h"
28 #include "btrfs-util.h"
29 #include "utf8.h"
30 #include "mkdir.h"
31 #include "import-util.h"
32 #include "curl-util.h"
33 #include "aufs-util.h"
34 #include "import-job.h"
35 #include "import-common.h"
36 #include "import-dkr.h"
37
38 struct DkrImport {
39         sd_event *event;
40         CurlGlue *glue;
41
42         char *index_url;
43         char *image_root;
44
45         ImportJob *images_job;
46         ImportJob *tags_job;
47         ImportJob *ancestry_job;
48         ImportJob *json_job;
49         ImportJob *layer_job;
50
51         char *name;
52         char *tag;
53         char *id;
54
55         char *response_token;
56         char **response_registries;
57
58         char **ancestry;
59         unsigned current_ancestry;
60
61         DkrImportFinished on_finished;
62         void *userdata;
63
64         char *local;
65         bool force_local;
66
67         char *temp_path;
68         char *final_path;
69
70         pid_t tar_pid;
71 };
72
73 #define PROTOCOL_PREFIX "https://"
74
75 #define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:"
76 #define HEADER_REGISTRY "X-Do" /*the HTTP header for the registry */ "cker-Endpoints:"
77
78 #define LAYERS_MAX 2048
79
80 static void dkr_import_job_on_finished(ImportJob *j);
81
82 DkrImport* dkr_import_unref(DkrImport *i) {
83         if (!i)
84                 return NULL;
85
86         if (i->tar_pid > 1) {
87                 (void) kill_and_sigcont(i->tar_pid, SIGKILL);
88                 (void) wait_for_terminate(i->tar_pid, NULL);
89         }
90
91         import_job_unref(i->images_job);
92         import_job_unref(i->tags_job);
93         import_job_unref(i->ancestry_job);
94         import_job_unref(i->json_job);
95         import_job_unref(i->layer_job);
96
97         curl_glue_unref(i->glue);
98         sd_event_unref(i->event);
99
100         if (i->temp_path) {
101                 (void) btrfs_subvol_remove(i->temp_path);
102                 (void) rm_rf_dangerous(i->temp_path, false, true, false);
103                 free(i->temp_path);
104         }
105
106         free(i->name);
107         free(i->tag);
108         free(i->id);
109         free(i->response_token);
110         free(i->response_registries);
111         strv_free(i->ancestry);
112         free(i->final_path);
113         free(i->index_url);
114         free(i->image_root);
115         free(i->local);
116         free(i);
117
118         return NULL;
119 }
120
121 int dkr_import_new(
122                 DkrImport **ret,
123                 sd_event *event,
124                 const char *index_url,
125                 const char *image_root,
126                 DkrImportFinished on_finished,
127                 void *userdata) {
128
129         _cleanup_(dkr_import_unrefp) DkrImport *i = NULL;
130         char *e;
131         int r;
132
133         assert(ret);
134         assert(index_url);
135
136         if (!http_url_is_valid(index_url))
137                 return -EINVAL;
138
139         i = new0(DkrImport, 1);
140         if (!i)
141                 return -ENOMEM;
142
143         i->on_finished = on_finished;
144         i->userdata = userdata;
145
146         i->image_root = strdup(image_root ?: "/var/lib/machines");
147         if (!i->image_root)
148                 return -ENOMEM;
149
150         i->index_url = strdup(index_url);
151         if (!i->index_url)
152                 return -ENOMEM;
153
154         e = endswith(i->index_url, "/");
155         if (e)
156                 *e = 0;
157
158         if (event)
159                 i->event = sd_event_ref(event);
160         else {
161                 r = sd_event_default(&i->event);
162                 if (r < 0)
163                         return r;
164         }
165
166         r = curl_glue_new(&i->glue, i->event);
167         if (r < 0)
168                 return r;
169
170         i->glue->on_finished = import_job_curl_on_finished;
171         i->glue->userdata = i;
172
173         *ret = i;
174         i = NULL;
175
176         return 0;
177 }
178
179 static int parse_id(const void *payload, size_t size, char **ret) {
180         _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL;
181         union json_value v = {};
182         void *json_state = NULL;
183         const char *p;
184         int t;
185
186         assert(payload);
187         assert(ret);
188
189         if (size <= 0)
190                 return -EBADMSG;
191
192         if (memchr(payload, 0, size))
193                 return -EBADMSG;
194
195         buf = strndup(payload, size);
196         if (!buf)
197                 return -ENOMEM;
198
199         p = buf;
200         t = json_tokenize(&p, &id, &v, &json_state, NULL);
201         if (t < 0)
202                 return t;
203         if (t != JSON_STRING)
204                 return -EBADMSG;
205
206         t = json_tokenize(&p, &other, &v, &json_state, NULL);
207         if (t < 0)
208                 return t;
209         if (t != JSON_END)
210                 return -EBADMSG;
211
212         if (!dkr_id_is_valid(id))
213                 return -EBADMSG;
214
215         *ret = id;
216         id = NULL;
217
218         return 0;
219 }
220
221 static int parse_ancestry(const void *payload, size_t size, char ***ret) {
222         _cleanup_free_ char *buf = NULL;
223         void *json_state = NULL;
224         const char *p;
225         enum {
226                 STATE_BEGIN,
227                 STATE_ITEM,
228                 STATE_COMMA,
229                 STATE_END,
230         } state = STATE_BEGIN;
231         _cleanup_strv_free_ char **l = NULL;
232         size_t n = 0, allocated = 0;
233
234         if (size <= 0)
235                 return -EBADMSG;
236
237         if (memchr(payload, 0, size))
238                 return -EBADMSG;
239
240         buf = strndup(payload, size);
241         if (!buf)
242                 return -ENOMEM;
243
244         p = buf;
245         for (;;) {
246                 _cleanup_free_ char *str;
247                 union json_value v = {};
248                 int t;
249
250                 t = json_tokenize(&p, &str, &v, &json_state, NULL);
251                 if (t < 0)
252                         return t;
253
254                 switch (state) {
255
256                 case STATE_BEGIN:
257                         if (t == JSON_ARRAY_OPEN)
258                                 state = STATE_ITEM;
259                         else
260                                 return -EBADMSG;
261
262                         break;
263
264                 case STATE_ITEM:
265                         if (t == JSON_STRING) {
266                                 if (!dkr_id_is_valid(str))
267                                         return -EBADMSG;
268
269                                 if (n+1 > LAYERS_MAX)
270                                         return -EFBIG;
271
272                                 if (!GREEDY_REALLOC(l, allocated, n + 2))
273                                         return -ENOMEM;
274
275                                 l[n++] = str;
276                                 str = NULL;
277                                 l[n] = NULL;
278
279                                 state = STATE_COMMA;
280
281                         } else if (t == JSON_ARRAY_CLOSE)
282                                 state = STATE_END;
283                         else
284                                 return -EBADMSG;
285
286                         break;
287
288                 case STATE_COMMA:
289                         if (t == JSON_COMMA)
290                                 state = STATE_ITEM;
291                         else if (t == JSON_ARRAY_CLOSE)
292                                 state = STATE_END;
293                         else
294                                 return -EBADMSG;
295                         break;
296
297                 case STATE_END:
298                         if (t == JSON_END) {
299
300                                 if (strv_isempty(l))
301                                         return -EBADMSG;
302
303                                 if (!strv_is_uniq(l))
304                                         return -EBADMSG;
305
306                                 l = strv_reverse(l);
307
308                                 *ret = l;
309                                 l = NULL;
310                                 return 0;
311                         } else
312                                 return -EBADMSG;
313                 }
314
315         }
316 }
317
318 static const char *dkr_import_current_layer(DkrImport *i) {
319         assert(i);
320
321         if (strv_isempty(i->ancestry))
322                 return NULL;
323
324         return i->ancestry[i->current_ancestry];
325 }
326
327 static const char *dkr_import_current_base_layer(DkrImport *i) {
328         assert(i);
329
330         if (strv_isempty(i->ancestry))
331                 return NULL;
332
333         if (i->current_ancestry <= 0)
334                 return NULL;
335
336         return i->ancestry[i->current_ancestry-1];
337 }
338
339 static int dkr_import_add_token(DkrImport *i, ImportJob *j) {
340         const char *t;
341
342         assert(i);
343         assert(j);
344
345         if (i->response_token)
346                 t = strappenda("Authorization: Token ", i->response_token);
347         else
348                 t = HEADER_TOKEN " true";
349
350         j->request_header = curl_slist_new("Accept: application/json", t, NULL);
351         if (!j->request_header)
352                 return -ENOMEM;
353
354         return 0;
355 }
356
357 static bool dkr_import_is_done(DkrImport *i) {
358         assert(i);
359         assert(i->images_job);
360
361         if (i->images_job->state != IMPORT_JOB_DONE)
362                 return false;
363
364         if (!i->tags_job || i->tags_job->state != IMPORT_JOB_DONE)
365                 return false;
366
367         if (!i->ancestry_job || i->ancestry_job->state != IMPORT_JOB_DONE)
368                 return false;
369
370         if (!i->json_job || i->json_job->state != IMPORT_JOB_DONE)
371                 return false;
372
373         if (i->layer_job && i->layer_job->state != IMPORT_JOB_DONE)
374                 return false;
375
376         if (dkr_import_current_layer(i))
377                 return false;
378
379         return true;
380 }
381
382 static int dkr_import_make_local_copy(DkrImport *i) {
383         int r;
384
385         assert(i);
386
387         if (!i->local)
388                 return 0;
389
390         if (!i->final_path) {
391                 i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL);
392                 if (!i->final_path)
393                         return log_oom();
394         }
395
396         r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
397         if (r < 0)
398                 return r;
399
400         return 0;
401 }
402
403 static int dkr_import_job_on_open_disk(ImportJob *j) {
404         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
405         const char *base;
406         DkrImport *i;
407         int r;
408
409         assert(j);
410         assert(j->userdata);
411
412         i = j->userdata;
413         assert(i->layer_job == j);
414         assert(i->final_path);
415         assert(!i->temp_path);
416         assert(i->tar_pid <= 0);
417
418         r = tempfn_random(i->final_path, &i->temp_path);
419         if (r < 0)
420                 return log_oom();
421
422         mkdir_parents_label(i->temp_path, 0700);
423
424         base = dkr_import_current_base_layer(i);
425         if (base) {
426                 const char *base_path;
427
428                 base_path = strappenda(i->image_root, "/.dkr-", base);
429                 r = btrfs_subvol_snapshot(base_path, i->temp_path, false, true);
430         } else
431                 r = btrfs_subvol_make(i->temp_path);
432         if (r < 0)
433                 return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
434
435         if (pipe2(pipefd, O_CLOEXEC) < 0)
436                 return log_error_errno(errno, "Failed to create pipe for tar: %m");
437
438         i->tar_pid = fork();
439         if (i->tar_pid < 0)
440                 return log_error_errno(errno, "Failed to fork off tar: %m");
441         if (i->tar_pid == 0) {
442                 int null_fd;
443
444                 /* Child */
445
446                 reset_all_signal_handlers();
447                 reset_signal_mask();
448                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
449
450                 pipefd[1] = safe_close(pipefd[1]);
451
452                 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
453                         log_error_errno(errno, "Failed to dup2() fd: %m");
454                         _exit(EXIT_FAILURE);
455                 }
456
457                 if (pipefd[0] != STDIN_FILENO)
458                         pipefd[0] = safe_close(pipefd[0]);
459
460                 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
461                 if (null_fd < 0) {
462                         log_error_errno(errno, "Failed to open /dev/null: %m");
463                         _exit(EXIT_FAILURE);
464                 }
465
466                 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
467                         log_error_errno(errno, "Failed to dup2() fd: %m");
468                         _exit(EXIT_FAILURE);
469                 }
470
471                 if (null_fd != STDOUT_FILENO)
472                         null_fd = safe_close(null_fd);
473
474                 fd_cloexec(STDIN_FILENO, false);
475                 fd_cloexec(STDOUT_FILENO, false);
476                 fd_cloexec(STDERR_FILENO, false);
477
478                 execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
479                 log_error_errno(errno, "Failed to execute tar: %m");
480                 _exit(EXIT_FAILURE);
481         }
482
483         pipefd[0] = safe_close(pipefd[0]);
484
485         j->disk_fd = pipefd[1];
486         pipefd[1] = -1;
487
488         return 0;
489 }
490
491 static int dkr_import_pull_layer(DkrImport *i) {
492         _cleanup_free_ char *path = NULL;
493         const char *url, *layer = NULL;
494         int r;
495
496         assert(i);
497         assert(!i->layer_job);
498         assert(!i->temp_path);
499         assert(!i->final_path);
500
501         for (;;) {
502                 layer = dkr_import_current_layer(i);
503                 if (!layer)
504                         return 0; /* no more layers */
505
506                 path = strjoin(i->image_root, "/.dkr-", layer, NULL);
507                 if (!path)
508                         return log_oom();
509
510                 if (laccess(path, F_OK) < 0) {
511                         if (errno == ENOENT)
512                                 break;
513
514                         return log_error_errno(errno, "Failed to check for container: %m");
515                 }
516
517                 log_info("Layer %s already exists, skipping.", layer);
518
519                 i->current_ancestry++;
520
521                 free(path);
522                 path = NULL;
523         }
524
525         log_info("Pulling layer %s...", layer);
526
527         i->final_path = path;
528         path = NULL;
529
530         url = strappenda(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer");
531         r = import_job_new(&i->layer_job, url, i->glue, i);
532         if (r < 0)
533                 return log_error_errno(r, "Failed to allocate layer job: %m");
534
535         r = dkr_import_add_token(i, i->layer_job);
536         if (r < 0)
537                 return log_oom();
538
539         i->layer_job->on_finished = dkr_import_job_on_finished;
540         i->layer_job->on_open_disk = dkr_import_job_on_open_disk;
541
542         r = import_job_begin(i->layer_job);
543         if (r < 0)
544                 return log_error_errno(r, "Failed to start layer job: %m");
545
546         return 0;
547 }
548
549 static void dkr_import_job_on_finished(ImportJob *j) {
550         DkrImport *i;
551         int r;
552
553         assert(j);
554         assert(j->userdata);
555
556         i = j->userdata;
557         if (j->error != 0) {
558                 if (j == i->images_job)
559                         log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)");
560                 else if (j == i->tags_job)
561                         log_error_errno(j->error, "Failed to retrieve tags list.");
562                 else if (j == i->ancestry_job)
563                         log_error_errno(j->error, "Failed to retrieve ancestry list.");
564                 else if (j == i->json_job)
565                         log_error_errno(j->error, "Failed to retrieve json data.");
566                 else
567                         log_error_errno(j->error, "Failed to retrieve layer data.");
568
569                 r = j->error;
570                 goto finish;
571         }
572
573         if (i->images_job == j) {
574                 const char *url;
575
576                 assert(!i->tags_job);
577                 assert(!i->ancestry_job);
578                 assert(!i->json_job);
579                 assert(!i->layer_job);
580
581                 if (strv_isempty(i->response_registries)) {
582                         r = -EBADMSG;
583                         log_error("Didn't get registry information.");
584                         goto finish;
585                 }
586
587                 log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]);
588
589                 url = strappenda(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->tag);
590                 r = import_job_new(&i->tags_job, url, i->glue, i);
591                 if (r < 0) {
592                         log_error_errno(r, "Failed to allocate tags job: %m");
593                         goto finish;
594                 }
595
596                 r = dkr_import_add_token(i, i->tags_job);
597                 if (r < 0) {
598                         log_oom();
599                         goto finish;
600                 }
601
602                 i->tags_job->on_finished = dkr_import_job_on_finished;
603
604                 r = import_job_begin(i->tags_job);
605                 if (r < 0) {
606                         log_error_errno(r, "Failed to start tags job: %m");
607                         goto finish;
608                 }
609
610         } else if (i->tags_job == j) {
611                 const char *url;
612                 char *id = NULL;
613
614                 assert(!i->ancestry_job);
615                 assert(!i->json_job);
616                 assert(!i->layer_job);
617
618                 r = parse_id(j->payload, j->payload_size, &id);
619                 if (r < 0) {
620                         log_error_errno(r, "Failed to parse JSON id.");
621                         goto finish;
622                 }
623
624                 free(i->id);
625                 i->id = id;
626
627                 log_info("Tag lookup succeeded, resolved to layer %s.", i->id);
628
629                 url = strappenda(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry");
630                 r = import_job_new(&i->ancestry_job, url, i->glue, i);
631                 if (r < 0) {
632                         log_error_errno(r, "Failed to allocate ancestry job: %m");
633                         goto finish;
634                 }
635
636                 r = dkr_import_add_token(i, i->ancestry_job);
637                 if (r < 0) {
638                         log_oom();
639                         goto finish;
640                 }
641
642                 i->ancestry_job->on_finished = dkr_import_job_on_finished;
643
644                 url = strappenda(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json");
645                 r = import_job_new(&i->json_job, url, i->glue, i);
646                 if (r < 0) {
647                         log_error_errno(r, "Failed to allocate json job: %m");
648                         goto finish;
649                 }
650
651                 r = dkr_import_add_token(i, i->json_job);
652                 if (r < 0) {
653                         log_oom();
654                         goto finish;
655                 }
656
657                 i->json_job->on_finished = dkr_import_job_on_finished;
658
659                 r = import_job_begin(i->ancestry_job);
660                 if (r < 0) {
661                         log_error_errno(r, "Failed to start ancestry job: %m");
662                         goto finish;
663                 }
664
665                 r = import_job_begin(i->json_job);
666                 if (r < 0) {
667                         log_error_errno(r, "Failed to start json job: %m");
668                         goto finish;
669                 }
670
671         } else if (i->ancestry_job == j) {
672                 char **ancestry = NULL, **k;
673                 unsigned n;
674
675                 assert(!i->layer_job);
676
677                 r = parse_ancestry(j->payload, j->payload_size, &ancestry);
678                 if (r < 0) {
679                         log_error_errno(r, "Failed to parse JSON id.");
680                         goto finish;
681                 }
682
683                 n = strv_length(ancestry);
684                 if (n <= 0 || !streq(ancestry[n-1], i->id)) {
685                         log_error("Ancestry doesn't end in main layer.");
686                         strv_free(ancestry);
687                         r = -EBADMSG;
688                         goto finish;
689                 }
690
691                 log_info("Ancestor lookup succeeded, requires layers:\n");
692                 STRV_FOREACH(k, ancestry)
693                         log_info("\t%s", *k);
694
695                 strv_free(i->ancestry);
696                 i->ancestry = ancestry;
697
698                 i->current_ancestry = 0;
699                 r = dkr_import_pull_layer(i);
700                 if (r < 0)
701                         goto finish;
702
703         } else if (i->layer_job == j) {
704                 assert(i->temp_path);
705                 assert(i->final_path);
706
707                 j->disk_fd = safe_close(j->disk_fd);
708
709                 if (i->tar_pid > 0) {
710                         r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
711                         i->tar_pid = 0;
712                         if (r < 0)
713                                 goto finish;
714                 }
715
716                 r = aufs_resolve(i->temp_path);
717                 if (r < 0) {
718                         log_error_errno(r, "Failed to resolve aufs whiteouts: %m");
719                         goto finish;
720                 }
721
722                 r = btrfs_subvol_set_read_only(i->temp_path, true);
723                 if (r < 0) {
724                         log_error_errno(r, "Failed to mark snapshort read-only: %m");
725                         goto finish;
726                 }
727
728                 if (rename(i->temp_path, i->final_path) < 0) {
729                         log_error_errno(errno, "Failed to rename snaphsot: %m");
730                         goto finish;
731                 }
732
733                 log_info("Completed writing to layer %s.", i->final_path);
734
735                 i->layer_job = import_job_unref(i->layer_job);
736                 free(i->temp_path);
737                 i->temp_path = NULL;
738                 free(i->final_path);
739                 i->final_path = NULL;
740
741                 i->current_ancestry ++;
742                 r = dkr_import_pull_layer(i);
743                 if (r < 0)
744                         goto finish;
745
746         } else if (i->json_job != j)
747                 assert_not_reached("Got finished event for unknown curl object");
748
749         if (!dkr_import_is_done(i))
750                 return;
751
752         r = dkr_import_make_local_copy(i);
753         if (r < 0)
754                 goto finish;
755
756         r = 0;
757
758 finish:
759         if (i->on_finished)
760                 i->on_finished(i, r, i->userdata);
761         else
762                 sd_event_exit(i->event, r);
763 }
764
765 static int dkr_import_job_on_header(ImportJob *j, const char *header, size_t sz)  {
766         _cleanup_free_ char *registry = NULL;
767         char *token;
768         DkrImport *i;
769         int r;
770
771         assert(j);
772         assert(j->userdata);
773
774         i = j->userdata;
775
776         r = curl_header_strdup(header, sz, HEADER_TOKEN, &token);
777         if (r < 0)
778                 return log_oom();
779         if (r > 0) {
780                 free(i->response_token);
781                 i->response_token = token;
782                 return 0;
783         }
784
785         r = curl_header_strdup(header, sz, HEADER_REGISTRY, &registry);
786         if (r < 0)
787                 return log_oom();
788         if (r > 0) {
789                 char **l, **k;
790
791                 l = strv_split(registry, ",");
792                 if (!l)
793                         return log_oom();
794
795                 STRV_FOREACH(k, l) {
796                         if (!hostname_is_valid(*k)) {
797                                 log_error("Registry hostname is not valid.");
798                                 strv_free(l);
799                                 return -EBADMSG;
800                         }
801                 }
802
803                 strv_free(i->response_registries);
804                 i->response_registries = l;
805         }
806
807         return 0;
808 }
809
810 int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char *local, bool force_local) {
811         const char *url;
812         int r;
813
814         assert(i);
815
816         if (!dkr_name_is_valid(name))
817                 return -EINVAL;
818
819         if (tag && !dkr_tag_is_valid(tag))
820                 return -EINVAL;
821
822         if (local && !machine_name_is_valid(local))
823                 return -EINVAL;
824
825         if (i->images_job)
826                 return -EBUSY;
827
828         if (!tag)
829                 tag = "latest";
830
831         r = free_and_strdup(&i->local, local);
832         if (r < 0)
833                 return r;
834         i->force_local = force_local;
835
836         r = free_and_strdup(&i->name, name);
837         if (r < 0)
838                 return r;
839         r = free_and_strdup(&i->tag, tag);
840         if (r < 0)
841                 return r;
842
843         url = strappenda(i->index_url, "/v1/repositories/", name, "/images");
844
845         r = import_job_new(&i->images_job, url, i->glue, i);
846         if (r < 0)
847                 return r;
848
849         r = dkr_import_add_token(i, i->images_job);
850         if (r < 0)
851                 return r;
852
853         i->images_job->on_finished = dkr_import_job_on_finished;
854         i->images_job->on_header = dkr_import_job_on_header;
855
856         return import_job_begin(i->images_job);
857 }