11
11
import sys
12
12
import logging
13
13
import os
14
+ import entrypoints
14
15
import getpass
15
16
import shutil
16
17
import tempfile
17
18
import time
18
19
19
- import docker
20
+ from . engine import BuildError , ContainerEngineException , ImageLoadError
20
21
from urllib .parse import urlparse
21
- from docker .utils import kwargs_from_env
22
- from docker .errors import DockerException
23
22
import escapism
24
23
from pythonjsonlogger import jsonlogger
25
24
@@ -382,6 +381,33 @@ def _user_name_default(self):
382
381
config = True ,
383
382
)
384
383
384
+ engine = Unicode (
385
+ "docker" ,
386
+ config = True ,
387
+ help = """
388
+ Name of the container engine.
389
+
390
+ Defaults to 'docker'.
391
+ """ ,
392
+ )
393
+
394
+ def get_engine (self ):
395
+ """Return an instance of the container engine.
396
+
397
+ Currently no arguments are passed to the engine constructor.
398
+ """
399
+ engines = entrypoints .get_group_named ("repo2docker.engines" )
400
+ try :
401
+ entry = engines [self .engine ]
402
+ except KeyError :
403
+ raise ContainerEngineException (
404
+ "Container engine '{}' not found. Available engines: {}" .format (
405
+ self .engine , "," .join (engines .keys ())
406
+ )
407
+ )
408
+ engine_class = entry .load ()
409
+ return engine_class (parent = self )
410
+
385
411
def fetch (self , url , ref , checkout_path ):
386
412
"""Fetch the contents of `url` and place it in `checkout_path`.
387
413
@@ -474,13 +500,18 @@ def initialize(self):
474
500
475
501
def push_image (self ):
476
502
"""Push docker image to registry"""
477
- client = docker . APIClient ( version = "auto" , ** kwargs_from_env () )
503
+ client = self . get_engine ( )
478
504
# Build a progress setup for each layer, and only emit per-layer
479
505
# info every 1.5s
480
506
progress_layers = {}
481
507
layers = {}
482
508
last_emit_time = time .time ()
483
- for chunk in client .push (self .output_image_spec , stream = True ):
509
+ for chunk in client .push (self .output_image_spec ):
510
+ if client .string_output :
511
+ self .log .info (chunk , extra = dict (phase = "pushing" ))
512
+ continue
513
+ # else this is Docker output
514
+
484
515
# each chunk can be one or more lines of json events
485
516
# split lines here in case multiple are delivered at once
486
517
for line in chunk .splitlines ():
@@ -492,7 +523,7 @@ def push_image(self):
492
523
continue
493
524
if "error" in progress :
494
525
self .log .error (progress ["error" ], extra = dict (phase = "failed" ))
495
- raise docker . errors . ImageLoadError (progress ["error" ])
526
+ raise ImageLoadError (progress ["error" ])
496
527
if "id" not in progress :
497
528
continue
498
529
# deprecated truncated-progress data
@@ -528,7 +559,7 @@ def start_container(self):
528
559
529
560
Returns running container
530
561
"""
531
- client = docker . from_env ( version = "auto" )
562
+ client = self . get_engine ( )
532
563
533
564
docker_host = os .environ .get ("DOCKER_HOST" )
534
565
if docker_host :
@@ -565,11 +596,8 @@ def start_container(self):
565
596
566
597
container_volumes = {}
567
598
if self .volumes :
568
- api_client = docker .APIClient (
569
- version = "auto" , ** docker .utils .kwargs_from_env ()
570
- )
571
- image = api_client .inspect_image (self .output_image_spec )
572
- image_workdir = image ["ContainerConfig" ]["WorkingDir" ]
599
+ image = client .inspect_image (self .output_image_spec )
600
+ image_workdir = image .config ["WorkingDir" ]
573
601
574
602
for k , v in self .volumes .items ():
575
603
container_volumes [os .path .abspath (k )] = {
@@ -580,15 +608,14 @@ def start_container(self):
580
608
run_kwargs = dict (
581
609
publish_all_ports = self .all_ports ,
582
610
ports = ports ,
583
- detach = True ,
584
611
command = run_cmd ,
585
612
volumes = container_volumes ,
586
613
environment = self .environment ,
587
614
)
588
615
589
616
run_kwargs .update (self .extra_run_kwargs )
590
617
591
- container = client .containers . run (self .output_image_spec , ** run_kwargs )
618
+ container = client .run (self .output_image_spec , ** run_kwargs )
592
619
593
620
while container .status == "created" :
594
621
time .sleep (0.5 )
@@ -611,7 +638,7 @@ def wait_for_container(self, container):
611
638
if container .status == "running" :
612
639
self .log .info ("Stopping container...\n " , extra = dict (phase = "running" ))
613
640
container .kill ()
614
- exit_code = container .attrs [ "State" ][ "ExitCode" ]
641
+ exit_code = container .exitcode
615
642
616
643
container .wait ()
617
644
@@ -645,12 +672,11 @@ def find_image(self):
645
672
if self .dry_run :
646
673
return False
647
674
# check if we already have an image for this content
648
- client = docker . APIClient ( version = "auto" , ** kwargs_from_env () )
675
+ client = self . get_engine ( )
649
676
for image in client .images ():
650
- if image ["RepoTags" ] is not None :
651
- for tag in image ["RepoTags" ]:
652
- if tag == self .output_image_spec + ":latest" :
653
- return True
677
+ for tag in image .tags :
678
+ if tag == self .output_image_spec + ":latest" :
679
+ return True
654
680
return False
655
681
656
682
def build (self ):
@@ -660,12 +686,9 @@ def build(self):
660
686
# Check if r2d can connect to docker daemon
661
687
if not self .dry_run :
662
688
try :
663
- docker_client = docker .APIClient (version = "auto" , ** kwargs_from_env ())
664
- except DockerException as e :
665
- self .log .error (
666
- "\n Docker client initialization error: %s.\n Check if docker is running on the host.\n " ,
667
- e ,
668
- )
689
+ docker_client = self .get_engine ()
690
+ except ContainerEngineException as e :
691
+ self .log .error ("\n Container engine initialization error: %s\n " , e )
669
692
self .exit (1 )
670
693
671
694
# If the source to be executed is a directory, continue using the
@@ -751,11 +774,14 @@ def build(self):
751
774
self .cache_from ,
752
775
self .extra_build_kwargs ,
753
776
):
754
- if "stream" in l :
777
+ if docker_client .string_output :
778
+ self .log .info (l , extra = dict (phase = "building" ))
779
+ # else this is Docker output
780
+ elif "stream" in l :
755
781
self .log .info (l ["stream" ], extra = dict (phase = "building" ))
756
782
elif "error" in l :
757
783
self .log .info (l ["error" ], extra = dict (phase = "failure" ))
758
- raise docker . errors . BuildError (l ["error" ], build_log = "" )
784
+ raise BuildError (l ["error" ])
759
785
elif "status" in l :
760
786
self .log .info (
761
787
"Fetching base image...\r " , extra = dict (phase = "building" )
0 commit comments