Add support for pull credentials on builds and build triggers
This commit is contained in:
parent
1fc3c922a9
commit
2006917e03
17 changed files with 355 additions and 37 deletions
|
@ -56,15 +56,21 @@ def unwrap_stream(json_stream):
|
|||
|
||||
class DockerfileBuildContext(object):
|
||||
def __init__(self, build_context_dir, dockerfile_subdir, repo, tag_names,
|
||||
push_token, build_uuid):
|
||||
push_token, build_uuid, pull_credentials=None):
|
||||
self._build_dir = build_context_dir
|
||||
self._dockerfile_subdir = dockerfile_subdir
|
||||
self._repo = repo
|
||||
self._tag_names = tag_names
|
||||
self._push_token = push_token
|
||||
self._cl = Client(timeout=1200)
|
||||
self._status = StatusWrapper(build_uuid)
|
||||
self._build_logger = partial(build_logs.append_log_message, build_uuid)
|
||||
self._pull_credentials = pull_credentials
|
||||
|
||||
# Note: We have two different clients here because we (potentially) login
|
||||
# with both, but with different credentials that we do not want shared between
|
||||
# the build and push operations.
|
||||
self._push_cl = Client(timeout=1200)
|
||||
self._build_cl = Client(timeout=1200)
|
||||
|
||||
dockerfile_path = os.path.join(self._build_dir, dockerfile_subdir,
|
||||
"Dockerfile")
|
||||
|
@ -99,6 +105,13 @@ class DockerfileBuildContext(object):
|
|||
return float(sent_bytes)/total_bytes*percentage_with_sizes
|
||||
|
||||
def build(self):
|
||||
# Login with the specified credentials (if any).
|
||||
if self._pull_credentials:
|
||||
logger.debug('Logging in with pull credentials.')
|
||||
self.build_cl_.login(self._pull_credentials['username'], self._pull_credentials['password'],
|
||||
registry=self._pull_credentials['registry'], reauth=True)
|
||||
|
||||
# Start the build itself.
|
||||
logger.debug('Starting build.')
|
||||
|
||||
with self._status as status:
|
||||
|
@ -110,7 +123,7 @@ class DockerfileBuildContext(object):
|
|||
logger.debug('Final context path: %s exists: %s' %
|
||||
(context_path, os.path.exists(context_path)))
|
||||
|
||||
build_status = self._cl.build(path=context_path, stream=True)
|
||||
build_status = self._build_cl.build(path=context_path, stream=True)
|
||||
|
||||
current_step = 0
|
||||
built_image = None
|
||||
|
@ -158,7 +171,7 @@ class DockerfileBuildContext(object):
|
|||
logger.debug('Attempting login to registry: %s' % registry_endpoint)
|
||||
|
||||
try:
|
||||
self._cl.login('$token', self._push_token, registry=registry_endpoint)
|
||||
self._push_cl.login('$token', self._push_token, registry=registry_endpoint)
|
||||
break
|
||||
except APIError:
|
||||
pass # Probably the wrong protocol
|
||||
|
@ -166,15 +179,15 @@ class DockerfileBuildContext(object):
|
|||
for tag in self._tag_names:
|
||||
logger.debug('Tagging image %s as %s:%s' %
|
||||
(built_image, self._repo, tag))
|
||||
self._cl.tag(built_image, self._repo, tag)
|
||||
self._push_cl.tag(built_image, self._repo, tag)
|
||||
|
||||
history = json.loads(self._cl.history(built_image))
|
||||
history = json.loads(self._push_cl.history(built_image))
|
||||
num_images = len(history)
|
||||
with self._status as status:
|
||||
status['total_images'] = num_images
|
||||
|
||||
logger.debug('Pushing to repo %s' % self._repo)
|
||||
resp = self._cl.push(self._repo, stream=True)
|
||||
resp = self._push_cl.push(self._repo, stream=True)
|
||||
|
||||
for status_str in resp:
|
||||
status = json.loads(status_str)
|
||||
|
@ -204,20 +217,20 @@ class DockerfileBuildContext(object):
|
|||
|
||||
def __cleanup(self):
|
||||
# First clean up any containers that might be holding the images
|
||||
for running in self._cl.containers(quiet=True):
|
||||
for running in self._build_cl.containers(quiet=True):
|
||||
logger.debug('Killing container: %s' % running['Id'])
|
||||
self._cl.kill(running['Id'])
|
||||
self._build_cl.kill(running['Id'])
|
||||
|
||||
# Next, remove all of the containers (which should all now be killed)
|
||||
for container in self._cl.containers(all=True, quiet=True):
|
||||
for container in self._build_cl.containers(all=True, quiet=True):
|
||||
logger.debug('Removing container: %s' % container['Id'])
|
||||
self._cl.remove_container(container['Id'])
|
||||
self._build_cl.remove_container(container['Id'])
|
||||
|
||||
# Iterate all of the images and remove the ones that the public registry
|
||||
# doesn't know about, this should preserve base images.
|
||||
images_to_remove = set()
|
||||
repos = set()
|
||||
for image in self._cl.images():
|
||||
for image in self._build_cl.images():
|
||||
images_to_remove.add(image['Id'])
|
||||
|
||||
for tag in image['RepoTags']:
|
||||
|
@ -237,13 +250,13 @@ class DockerfileBuildContext(object):
|
|||
for to_remove in images_to_remove:
|
||||
logger.debug('Removing private image: %s' % to_remove)
|
||||
try:
|
||||
self._cl.remove_image(to_remove)
|
||||
self._build_cl.remove_image(to_remove)
|
||||
except APIError:
|
||||
# Sometimes an upstream image removed this one
|
||||
pass
|
||||
|
||||
# Verify that our images were actually removed
|
||||
for image in self._cl.images():
|
||||
for image in self._build_cl.images():
|
||||
if image['Id'] in images_to_remove:
|
||||
raise RuntimeError('Image was not removed: %s' % image['Id'])
|
||||
|
||||
|
@ -291,6 +304,7 @@ class DockerfileBuildWorker(Worker):
|
|||
tag_names = job_config['docker_tags']
|
||||
build_subdir = job_config['build_subdir']
|
||||
repo = job_config['repository']
|
||||
pull_credentials = job_config.get('pull_credentials', None)
|
||||
|
||||
access_token = repository_build.access_token.code
|
||||
|
||||
|
@ -325,7 +339,7 @@ class DockerfileBuildWorker(Worker):
|
|||
|
||||
with DockerfileBuildContext(build_dir, build_subdir, repo, tag_names,
|
||||
access_token,
|
||||
repository_build.uuid) as build_ctxt:
|
||||
repository_build.uuid, pull_credentials) as build_ctxt:
|
||||
try:
|
||||
built_image = build_ctxt.build()
|
||||
|
||||
|
@ -379,4 +393,4 @@ else:
|
|||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(formatter)
|
||||
root_logger.addHandler(handler)
|
||||
worker.start()
|
||||
worker.start()
|
||||
|
|
Reference in a new issue