From 1678a4fbe45d9e0d2a7eb0b055787f6bf25bd2a1 Mon Sep 17 00:00:00 2001 From: Guillaume Rose Date: Mon, 14 Oct 2019 21:17:15 +0200 Subject: [PATCH 1/2] Run CI on amd64 Signed-off-by: Guillaume Rose --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4de276ada..1d7c348e3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ def buildImage = { String baseImage -> def image - wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) { + wrappedNode(label: "ubuntu && amd64 && !zfs", cleanWorkspace: true) { stage("build image for \"${baseImage}\"") { checkout(scm) def imageName = "dockerbuildbot/compose:${baseImage}-${gitCommit()}" @@ -29,7 +29,7 @@ def buildImage = { String baseImage -> def get_versions = { String imageId, int number -> def docker_versions - wrappedNode(label: "ubuntu && !zfs") { + wrappedNode(label: "ubuntu && amd64 && !zfs") { def result = sh(script: """docker run --rm \\ --entrypoint=/code/.tox/py27/bin/python \\ ${imageId} \\ @@ -55,7 +55,7 @@ def runTests = { Map settings -> } { -> - wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) { + wrappedNode(label: "ubuntu && amd64 && !zfs", cleanWorkspace: true) { stage("test python=${pythonVersions} / docker=${dockerVersions} / baseImage=${baseImage}") { checkout(scm) def storageDriver = sh(script: 'docker info | awk -F \': \' \'$1 == "Storage Driver" { print $2; exit }\'', returnStdout: true).trim() From dbe4d7323eb8d38c98cec2810469bcd65266edb0 Mon Sep 17 00:00:00 2001 From: Guillaume Rose Date: Mon, 14 Oct 2019 14:55:41 +0200 Subject: [PATCH 2/2] Add working dir, config files and env file in service labels Signed-off-by: Guillaume Rose --- compose/cli/command.py | 30 ++++++++++++++++++--- compose/const.py | 3 +++ compose/project.py | 3 ++- compose/service.py | 59 ++++++++++++++++++++++-------------------- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/compose/cli/command.py b/compose/cli/command.py index 2f38fe5af..c3a10a043 100644 --- a/compose/cli/command.py +++ b/compose/cli/command.py @@ -13,6 +13,9 @@ from .. import config from .. import parallel from ..config.environment import Environment from ..const import API_VERSIONS +from ..const import LABEL_CONFIG_FILES +from ..const import LABEL_ENVIRONMENT_FILE +from ..const import LABEL_WORKING_DIR from ..project import Project from .docker_client import docker_client from .docker_client import get_tls_version @@ -57,7 +60,8 @@ def project_from_options(project_dir, options, additional_options={}): environment=environment, override_dir=override_dir, compatibility=options.get('--compatibility'), - interpolate=(not additional_options.get('--no-interpolate')) + interpolate=(not additional_options.get('--no-interpolate')), + environment_file=environment_file ) @@ -125,7 +129,7 @@ def get_client(environment, verbose=False, version=None, tls_config=None, host=N def get_project(project_dir, config_path=None, project_name=None, verbose=False, host=None, tls_config=None, environment=None, override_dir=None, - compatibility=False, interpolate=True): + compatibility=False, interpolate=True, environment_file=None): if not environment: environment = Environment.from_env_file(project_dir) config_details = config.find(project_dir, config_path, environment, override_dir) @@ -145,10 +149,30 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False, with errors.handle_connection_errors(client): return Project.from_config( - project_name, config_data, client, environment.get('DOCKER_DEFAULT_PLATFORM') + project_name, + config_data, + client, + environment.get('DOCKER_DEFAULT_PLATFORM'), + execution_context_labels(config_details, environment_file), ) +def execution_context_labels(config_details, environment_file): + extra_labels = [ + '{0}={1}'.format(LABEL_WORKING_DIR, os.path.abspath(config_details.working_dir)), + '{0}={1}'.format(LABEL_CONFIG_FILES, config_files_label(config_details)), + ] + if environment_file is not None: + extra_labels.append('{0}={1}'.format(LABEL_ENVIRONMENT_FILE, + os.path.normpath(environment_file))) + return extra_labels + + +def config_files_label(config_details): + return ",".join( + map(str, (os.path.normpath(c.filename) for c in config_details.config_files))) + + def get_project_name(working_dir, project_name=None, environment=None): def normalize_name(name): return re.sub(r'[^-_a-z0-9]', '', name.lower()) diff --git a/compose/const.py b/compose/const.py index 46d81ae71..ab0389ce0 100644 --- a/compose/const.py +++ b/compose/const.py @@ -11,6 +11,9 @@ IS_WINDOWS_PLATFORM = (sys.platform == "win32") LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number' LABEL_ONE_OFF = 'com.docker.compose.oneoff' LABEL_PROJECT = 'com.docker.compose.project' +LABEL_WORKING_DIR = 'com.docker.compose.project.working_dir' +LABEL_CONFIG_FILES = 'com.docker.compose.project.config_files' +LABEL_ENVIRONMENT_FILE = 'com.docker.compose.project.environment_file' LABEL_SERVICE = 'com.docker.compose.service' LABEL_NETWORK = 'com.docker.compose.network' LABEL_VERSION = 'com.docker.compose.version' diff --git a/compose/project.py b/compose/project.py index 092c1e123..094ce4d7a 100644 --- a/compose/project.py +++ b/compose/project.py @@ -83,7 +83,7 @@ class Project(object): return labels @classmethod - def from_config(cls, name, config_data, client, default_platform=None): + def from_config(cls, name, config_data, client, default_platform=None, extra_labels=[]): """ Construct a Project from a config.Config object. """ @@ -136,6 +136,7 @@ class Project(object): pid_mode=pid_mode, platform=service_dict.pop('platform', None), default_platform=default_platform, + extra_labels=extra_labels, **service_dict) ) diff --git a/compose/service.py b/compose/service.py index 638cd71e5..ae4e7665c 100644 --- a/compose/service.py +++ b/compose/service.py @@ -68,7 +68,6 @@ else: log = logging.getLogger(__name__) - HOST_CONFIG_KEYS = [ 'cap_add', 'cap_drop', @@ -137,7 +136,6 @@ class NoSuchImageError(Exception): ServiceName = namedtuple('ServiceName', 'project service number') - ConvergencePlan = namedtuple('ConvergencePlan', 'action containers') @@ -173,20 +171,21 @@ class BuildAction(enum.Enum): class Service(object): def __init__( - self, - name, - client=None, - project='default', - use_networking=False, - links=None, - volumes_from=None, - network_mode=None, - networks=None, - secrets=None, - scale=1, - pid_mode=None, - default_platform=None, - **options + self, + name, + client=None, + project='default', + use_networking=False, + links=None, + volumes_from=None, + network_mode=None, + networks=None, + secrets=None, + scale=1, + pid_mode=None, + default_platform=None, + extra_labels=[], + **options ): self.name = name self.client = client @@ -201,6 +200,7 @@ class Service(object): self.scale_num = scale self.default_platform = default_platform self.options = options + self.extra_labels = extra_labels def __repr__(self): return ''.format(self.name) @@ -215,7 +215,7 @@ class Service(object): for container in self.client.containers( all=stopped, filters=filters)]) - ) + ) if result: return result @@ -404,8 +404,8 @@ class Service(object): return ConvergencePlan('start', containers) if ( - strategy is ConvergenceStrategy.always or - self._containers_have_diverged(containers) + strategy is ConvergenceStrategy.always or + self._containers_have_diverged(containers) ): return ConvergencePlan('recreate', containers) @@ -482,6 +482,7 @@ class Service(object): container, timeout=timeout, attach_logs=not detached, start_new_container=start, renew_anonymous_volumes=renew_anonymous_volumes ) + containers, errors = parallel_execute( containers, recreate, @@ -705,11 +706,11 @@ class Service(object): net_name = self.network_mode.service_name pid_namespace = self.pid_mode.service_name return ( - self.get_linked_service_names() + - self.get_volumes_from_names() + - ([net_name] if net_name else []) + - ([pid_namespace] if pid_namespace else []) + - list(self.options.get('depends_on', {}).keys()) + self.get_linked_service_names() + + self.get_volumes_from_names() + + ([net_name] if net_name else []) + + ([pid_namespace] if pid_namespace else []) + + list(self.options.get('depends_on', {}).keys()) ) def get_dependency_configs(self): @@ -899,7 +900,7 @@ class Service(object): container_options['labels'] = build_container_labels( container_options.get('labels', {}), - self.labels(one_off=one_off), + self.labels(one_off=one_off) + self.extra_labels, number, self.config_hash if add_config_hash else None, slug @@ -1552,9 +1553,9 @@ def warn_on_masked_volume(volumes_option, container_volumes, service): for volume in volumes_option: if ( - volume.external and - volume.internal in container_volumes and - container_volumes.get(volume.internal) != volume.external + volume.external and + volume.internal in container_volumes and + container_volumes.get(volume.internal) != volume.external ): log.warning(( "Service \"{service}\" is using volume \"{volume}\" from the " @@ -1601,6 +1602,7 @@ def build_mount(mount_spec): read_only=mount_spec.read_only, consistency=mount_spec.consistency, **kwargs ) + # Labels @@ -1655,6 +1657,7 @@ def format_environment(environment): if isinstance(value, six.binary_type): value = value.decode('utf-8') return '{key}={value}'.format(key=key, value=value) + return [format_env(*item) for item in environment.items()]