skia2/infra/bots/recipe_modules/docker/api.py
Eric Boren 1f218ee143 [recipes] Port to Python 3
Lots of potentially messy changes.

Also includes a major recipe roll.

Bug: chromium:1256037
Change-Id: Id05779802c5ca05921d93fa73c21930723793585
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/467980
Reviewed-by: Ravi Mistry <rmistry@google.com>
Commit-Queue: Eric Boren <borenet@google.com>
2021-11-10 20:17:28 +00:00

98 lines
3.5 KiB
Python

# Copyright 2019 Google LLC
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import posixpath
from recipe_engine import recipe_api
MOUNT_SRC = '/SRC'
MOUNT_OUT = '/OUT'
class DockerApi(recipe_api.RecipeApi):
def _chmod(self, filepath, mode, recursive=False):
cmd = ['chmod']
if recursive:
cmd.append('-R')
cmd.extend([mode, filepath])
name = ' '.join([str(elem) for elem in cmd])
self.m.step(name, cmd=cmd, infra_step=True)
def mount_src(self):
return MOUNT_SRC
def mount_out(self):
return MOUNT_OUT
# Unless match_directory_structure ==True, src_dir must be
# self.m.path['start_dir'] for the script to be located correctly.
def run(self, name, docker_image, src_dir, out_dir, script, args=None, docker_args=None, copies=None, recursive_read=None, attempts=1, match_directory_structure=False):
# Setup. Docker runs as a different user, so we need to give it access to
# read, write, and execute certain files.
with self.m.step.nest('Docker setup'):
step_stdout = self.m.python.inline(
name='Get uid and gid',
program='''import os
print('%d:%d' % (os.getuid(), os.getgid()))
''',
stdout=self.m.raw_io.output(),
step_test_data=(
lambda: self.m.raw_io.test_api.stream_output('13:17'))
).stdout.decode('utf-8')
uid_gid_pair = step_stdout.rstrip() if step_stdout else ''
# Make sure out_dir exists, otherwise mounting will fail.
# (Note that the docker --mount option, unlike the --volume option, does
# not create this dir as root if it doesn't exist.)
self.m.file.ensure_directory('mkdirs out_dir', out_dir, mode=0o777)
# ensure_directory won't change the permissions if the dir already exists,
# so we need to do that explicitly.
self._chmod(out_dir, '777')
# chmod the src_dir, but not recursively; Swarming writes some files which
# we can't access, so "chmod -R" will fail if this is the root workdir.
self._chmod(src_dir, '755')
# Need to make the script executable, or Docker can't run it.
self._chmod(script, '0755')
# Copy any requested files.
if copies:
for copy in copies:
src = copy['src']
dest = copy['dst']
dirname = self.m.path.dirname(dest)
self.m.file.ensure_directory(
'mkdirs %s' % dirname, dirname, mode=0o777)
self.m.file.copy('cp %s %s' % (src, dest), src, dest)
self._chmod(dest, '644')
# Recursive chmod any requested directories.
if recursive_read:
for elem in recursive_read:
self._chmod(elem, 'a+r', recursive=True)
# Run.
cmd = [
'docker', 'run', '--shm-size=2gb', '--rm', '--user', uid_gid_pair,
'--mount', 'type=bind,source=%s,target=%s' %
(src_dir, src_dir if match_directory_structure else MOUNT_SRC),
'--mount', 'type=bind,source=%s,target=%s' %
(out_dir, out_dir if match_directory_structure else MOUNT_OUT),
]
if docker_args:
cmd.extend(docker_args)
if not match_directory_structure:
# This only works when src_dir == self.m.path['start_dir'] but that's our
# only use case for now.
script = MOUNT_SRC + '/' + posixpath.relpath(str(script), str(self.m.path['start_dir']))
cmd.extend([docker_image, script])
if args:
cmd.extend(args)
env = {'DOCKER_CONFIG': '/home/chrome-bot/.docker'}
with self.m.env(env):
self.m.run.with_retry(self.m.step, name, attempts, cmd=cmd)