Skip to content

Commit 1879d51

Browse files
authored
feat: docker image building for installing pip requirements independently from OS (claranet#31)
1 parent 3c1ca8a commit 1879d51

File tree

2 files changed

+86
-32
lines changed

2 files changed

+86
-32
lines changed

package.py

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import operator
2121
import platform
2222
import subprocess
23-
from subprocess import check_call
23+
from subprocess import check_call, check_output
2424
from contextlib import contextmanager
2525
from base64 import b64encode
2626
import logging
@@ -550,12 +550,14 @@ def filter(self, path, prefix=None):
550550
rules = self._rules
551551

552552
def norm_path(path, root, filename=None):
553+
op = os.path.join(root, filename) if filename else root
553554
p = os.path.relpath(root, path)
554555
if prefix:
555-
p = os.path.normpath(os.path.join(prefix, p))
556-
p = os.path.join(p, filename) if filename else p + os.sep
557-
op = os.path.join(root, filename) if filename else root
558-
return op, p
556+
p = os.path.join(prefix, p)
557+
if filename:
558+
p = os.path.normpath(os.path.join(p, filename))
559+
return op, p
560+
return op, p + os.sep
559561

560562
def apply(path):
561563
d = True
@@ -806,6 +808,34 @@ def install_pip_requirements(query, requirements_file):
806808
runtime = query.runtime
807809
artifacts_dir = query.artifacts_dir
808810
docker = query.docker
811+
docker_image_tag_id = None
812+
813+
if docker:
814+
docker_file = docker.docker_file
815+
docker_image = docker.docker_image
816+
docker_build_root = docker.docker_build_root
817+
818+
if docker_image:
819+
ok = False
820+
while True:
821+
output = check_output(docker_image_id_command(docker_image))
822+
if output:
823+
docker_image_tag_id = output.decode().strip()
824+
log.debug("DOCKER TAG ID: %s -> %s",
825+
docker_image, docker_image_tag_id)
826+
ok = True
827+
if ok:
828+
break
829+
docker_cmd = docker_build_command(
830+
build_root=docker_build_root,
831+
docker_file=docker_file,
832+
tag=docker_image,
833+
)
834+
check_call(docker_cmd)
835+
ok = True
836+
elif docker_file or docker_build_root:
837+
raise ValueError('docker_image must be specified '
838+
'for a custom image future references')
809839

810840
working_dir = os.getcwd()
811841

@@ -824,6 +854,7 @@ def install_pip_requirements(query, requirements_file):
824854
'--requirement={}'.format(requirements_filename),
825855
]
826856
if docker:
857+
with_ssh_agent = docker.with_ssh_agent
827858
pip_cache_dir = docker.docker_pip_cache
828859
if pip_cache_dir:
829860
if isinstance(pip_cache_dir, str):
@@ -839,8 +870,10 @@ def install_pip_requirements(query, requirements_file):
839870
chown_mask, '.'])]
840871
shell_command = [' '.join(shell_command)]
841872
check_call(docker_run_command(
842-
'.', shell_command, runtime, shell=True,
843-
pip_cache_dir=pip_cache_dir
873+
'.', shell_command, runtime,
874+
image=docker_image_tag_id,
875+
shell=True, ssh_agent=with_ssh_agent,
876+
pip_cache_dir=pip_cache_dir,
844877
))
845878
else:
846879
cmd_log.info(shlex_join(pip_command))
@@ -851,13 +884,29 @@ def install_pip_requirements(query, requirements_file):
851884
yield temp_dir
852885

853886

854-
def docker_build_command(build_root, docker_file=None, tag=None):
887+
def docker_image_id_command(tag):
855888
""""""
889+
docker_cmd = ['docker', 'images', '--format={{.ID}}', tag]
890+
cmd_log.info(shlex_join(docker_cmd))
891+
log_handler and log_handler.flush()
892+
return docker_cmd
893+
894+
895+
def docker_build_command(tag=None, docker_file=None, build_root=False):
896+
""""""
897+
if not (build_root or docker_file):
898+
raise ValueError('docker_build_root or docker_file must be provided')
899+
856900
docker_cmd = ['docker', 'build']
857-
if docker_file:
858-
docker_cmd.extend(['--file', docker_file])
901+
859902
if tag:
860903
docker_cmd.extend(['--tag', tag])
904+
else:
905+
raise ValueError('docker_image must be specified')
906+
if not build_root:
907+
build_root = os.path.dirname(docker_file)
908+
if docker_file:
909+
docker_cmd.extend(['--file', docker_file])
861910
docker_cmd.append(build_root)
862911

863912
cmd_log.info(shlex_join(docker_cmd))
@@ -866,9 +915,12 @@ def docker_build_command(build_root, docker_file=None, tag=None):
866915

867916

868917
def docker_run_command(build_root, command, runtime,
869-
image=None, shell=None, interactive=False,
870-
pip_cache_dir=None):
918+
image=None, shell=None, ssh_agent=False,
919+
interactive=False, pip_cache_dir=None):
871920
""""""
921+
if platform.system() not in ('Linux', 'Darwin'):
922+
raise RuntimeError("Unsupported platform for docker building")
923+
872924
docker_cmd = ['docker', 'run', '--rm']
873925

874926
if interactive:
@@ -883,27 +935,28 @@ def docker_run_command(build_root, command, runtime,
883935
'-v', '{}/.ssh/known_hosts:/root/.ssh/known_hosts:z'.format(home),
884936
])
885937

886-
if platform.system() == 'Darwin':
887-
# https://docs.docker.com/docker-for-mac/osxfs/#ssh-agent-forwarding
888-
docker_cmd.extend([
889-
'--mount', 'type=bind,'
890-
'src=/run/host-services/ssh-auth.sock,'
891-
'target=/run/host-services/ssh-auth.sock',
892-
'-e', 'SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock',
893-
])
894-
elif platform.system() == 'Linux':
895-
sock = os.environ['SSH_AUTH_SOCK'] # TODO: Handle missing env var
896-
docker_cmd.extend([
897-
'-v', '{}:/tmp/ssh_sock:z'.format(sock),
898-
'-e', 'SSH_AUTH_SOCK=/tmp/ssh_sock',
899-
])
938+
if ssh_agent:
939+
if platform.system() == 'Darwin':
940+
# https://docs.docker.com/docker-for-mac/osxfs/#ssh-agent-forwarding
941+
docker_cmd.extend([
942+
'--mount', 'type=bind,'
943+
'src=/run/host-services/ssh-auth.sock,'
944+
'target=/run/host-services/ssh-auth.sock',
945+
'-e', 'SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock',
946+
])
947+
elif platform.system() == 'Linux':
948+
sock = os.environ['SSH_AUTH_SOCK'] # TODO: Handle missing env var
949+
docker_cmd.extend([
950+
'-v', '{}:/tmp/ssh_sock:z'.format(sock),
951+
'-e', 'SSH_AUTH_SOCK=/tmp/ssh_sock',
952+
])
953+
954+
if platform.system() == 'Linux':
900955
if pip_cache_dir:
901956
pip_cache_dir = os.path.abspath(pip_cache_dir)
902957
docker_cmd.extend([
903958
'-v', '{}:/root/.cache/pip:z'.format(pip_cache_dir),
904959
])
905-
else:
906-
raise RuntimeError("Unsupported platform for docker building")
907960

908961
if not image:
909962
image = 'lambci/lambda:build-{}'.format(runtime)

package.tf

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ data "external" "archive_prepare" {
1414
})
1515

1616
docker = var.build_in_docker ? jsonencode({
17-
docker_pip_cache = var.docker_pip_cache
18-
docker_file = var.docker_file
19-
docker_image = var.docker_image
20-
with_ssh_agent = var.docker_with_ssh_agent
17+
docker_pip_cache = var.docker_pip_cache
18+
docker_build_root = var.docker_build_root
19+
docker_file = var.docker_file
20+
docker_image = var.docker_image
21+
with_ssh_agent = var.docker_with_ssh_agent
2122
}) : null
2223

2324
artifacts_dir = var.artifacts_dir

0 commit comments

Comments
 (0)