Пример #1
0
def store_config_file(ctx, compose_file, considered_files):
    filepath = Path(compose_file.filename)
    fileparent = filepath.parent

    put_config_file(ctx, filepath, considered_files)

    if compose_file.version == '1':
        services = compose_file.config
    elif compose_file.version.startswith('2.'):
        services = compose_file.config['services']
    else:
        log.error('Unsupported config version: %s' % compose_file.version)
        raise SystemExit(1)

    for service in services.values():
        env_files = service.get('env_file', ())
        if isinstance(env_files, str):
            env_files = (env_files,)
        for env_file in env_files:
            env_file_path = fileparent / env_file
            put_config_file(ctx, env_file_path, considered_files)

        extends_file = service.get('extends', {}).get('file')
        if extends_file is None:
            continue

        extends_file_path = fileparent / extends_file
        extends_file = ConfigFile.from_filename(str(extends_file_path))
        store_config_file(ctx, extends_file, considered_files)
Пример #2
0
def store_config_file(ctx, compose_file, considered_files):
    filepath = Path(compose_file.filename)
    fileparent = filepath.parent
    compose_file_version = compose_file.version
    if not isinstance(compose_file_version,
                      ComposeVersion):  # up to Docker-Compose 1.14
        compose_file_version = ComposeVersion(compose_file_version)

    put_config_file(ctx, filepath, considered_files)

    if compose_file_version < ComposeVersion('2'):
        services = compose_file.config
    elif compose_file_version < ComposeVersion('4'):
        services = compose_file.config['services']
    else:
        log.error('Unsupported config version: %s' % compose_file.version)
        raise SystemExit(1)

    for service in services.values():
        env_files = service.get('env_file', ())
        if isinstance(env_files, str):
            env_files = (env_files, )
        for env_file in env_files:
            env_file_path = fileparent / env_file
            put_config_file(ctx, env_file_path, considered_files)

        extends_file = service.get('extends', {}).get('file')
        if extends_file is None:
            continue

        extends_file_path = fileparent / extends_file
        extends_file = ConfigFile.from_filename(str(extends_file_path))
        store_config_file(ctx, extends_file, considered_files)
Пример #3
0
    def test_compose(self):
        from compose.config.config import ConfigFile, ConfigDetails
        from compose.config.config import load as load_config
        from compose.project import Project

        composefile = """
        version: '2'
        services:
          first:
            image: alpine
            command: sleep 3600
          
          second:
            image: alpine
            command: sleep 3600
          
          pygen:
            image: pygen-build
            command: >
              --template '#
                {% for c in containers %}
                  Name={{ c.name }}
                {% endfor %}

                1st={{ containers.matching("first")|length }}
                2nd={{ containers.matching("second")|length }}'
              --one-shot
            volumes:
              - /var/run/docker.sock:/var/run/docker.sock:ro
            depends_on:
              - first
              - second
        """

        with open('/tmp/pygen-composefile.yml', 'w') as target:
            target.write(composefile)

        config = ConfigFile.from_filename('/tmp/pygen-composefile.yml')
        details = ConfigDetails('/tmp', [config])
        project = Project.from_config('cmpse', load_config(details),
                                      self.remote_client.api)

        with self.suppress_stderr():
            project.up(detached=True, scale_override={'second': 2})

            pygen_service = project.get_service('pygen')
            pygen_container = next(iter(pygen_service.containers()))
            pygen_container.wait()

            output = ''.join(pygen_container.logs(stdout=True, stderr=False))

            self.assertIn('Name=cmpse_first_1', output)
            self.assertIn('Name=cmpse_second_1', output)
            self.assertIn('Name=cmpse_second_2', output)
            self.assertIn('Name=cmpse_pygen_1', output)

            self.assertIn('1st=1', output)
            self.assertIn('2nd=2', output)
Пример #4
0
 def __init__(self, name, working_dir, config_file):
     config_file_path = os.path.join(working_dir, config_file)
     cfg_file = ConfigFile.from_filename(config_file_path)
     c = ConfigDetails(
         working_dir,
         [cfg_file],
     )
     self.cd = load(c)
     self.name = name
Пример #5
0
def format_dot(yml_path):
    """
    :param yml_path: str, path of the docker-compose yml to draw.
    :return: str, formatted dot template describing the graph.
    """
    from compose.config.config import ConfigFile
    config_file = ConfigFile.from_filename(yml_path)
    return template.format(
            nodes=format_nodes(config_file),
            links=format_links(config_file)
    )
    def __init__(self,
                 project_name,
                 directory,
                 composefile="docker-compose.yml",
                 output="{{ result }}",
                 **invocations):
        config = ConfigFile.from_filename("%s/%s" % (directory, composefile))
        details = ConfigDetails(directory, [config])
        self.project = Project.from_config(project_name, load_config(details),
                                           self.client.api)

        super(DockerComposeAction, self).__init__(output, **invocations)
Пример #7
0
def update_image(filename, new_image, service_name='web'):
    """
    Update service image name to new_image.
    """

    path = os.path.dirname(filename)
    conf_file = ConfigFile.from_filename(filename)
    conf = load(ConfigDetails(path, [conf_file], None))

    # find service
    for i in range(len(conf.services)):
        service = conf.services[i]
        if service['name'] == service_name:
            conf.services[i]['image'] = new_image

            out = open(filename, 'w')
            out.write(serialize_config(conf))
            out.close()

            return filename
Пример #8
0
def update_image(filename, new_image, service_name='web'):
    """
    Update service image name to new_image.
    """

    path = os.path.dirname(filename)
    conf_file = ConfigFile.from_filename(filename)
    conf = load(ConfigDetails(path, [conf_file], None))

    # find service
    for i in range(len(conf.services)):
        service = conf.services[i]
        if service['name'] == service_name:
            conf.services[i]['image'] = new_image

            out = open(filename, 'w')
            out.write(serialize_config(conf))
            out.close()

            return filename
Пример #9
0
def build(filename, env_dict=None, output_path=None):
    """
    Build docker-compose.yml file from services & env.
    """

    path = os.path.dirname(filename)
    conf_file = ConfigFile.from_filename(filename)
    env = Environment(env_dict) if env_dict else None
    conf = load(ConfigDetails(path, [conf_file], env))

    output_path = output_path if output_path else path + '/docker-compose.yml'

    # try to make directory
    if os.path.dirname(output_path):
        os.makedirs(os.path.dirname(output_path))

    out = open(output_path, 'w')
    out.write(serialize_config(conf))
    out.close()

    return output_path
Пример #10
0
def build(filename, env_dict=None, output_path=None):
    """
    Build docker-compose.yml file from services & env.
    """

    path = os.path.dirname(filename)
    conf_file = ConfigFile.from_filename(filename)
    env = Environment(env_dict) if env_dict else None
    conf = load(ConfigDetails(path, [conf_file], env))

    output_path = output_path if output_path else path + '/docker-compose.yml'

    # try to make directory
    if os.path.dirname(output_path):
        os.makedirs(os.path.dirname(output_path))

    out = open(output_path, 'w')
    out.write(serialize_config(conf))
    out.close()

    return output_path
Пример #11
0
    def start_compose_project(self,
                              name,
                              directory,
                              composefile_name,
                              composefile_contents=None):
        if composefile_contents:
            with open(relative_path('%s/%s' % (directory, composefile_name)),
                      'w') as composefile:
                composefile.write(composefile_contents)

        config = ConfigFile.from_filename(
            relative_path('%s/%s' % (directory, composefile_name)))
        details = ConfigDetails(relative_path(directory), [config])
        project = Project.from_config(name, load_config(details),
                                      self.docker_client.api)

        self.started_compose_projects.append(project)

        project.up(detached=True)

        if composefile_contents:
            os.remove(relative_path('%s/%s' % (directory, composefile_name)))

        return project
Пример #12
0
#
# Possible values - LR, RL, BT, TB... for left->right, bottom->top, etc.
DIRECTION="TB"

import sys
import yaml
import pygraphviz as pgv

from collections import defaultdict
# seemingly undocumented magic that might prove useful
from compose.config.config import ConfigFile

# arg sanity check
try:
    dcompose = ConfigFile.from_filename(sys.argv[1])

except IndexError as e:
    print "Usage: file.yml"
    sys.exit(1)
except Exception as e:
    print "Error: %s" % e
    sys.exit(2)

filename      = sys.argv[1]
# assume it's a foo.bar kinda file
filebase      = filename.split('.')[0]

# this is where we draw the relationships
compose       = defaultdict(lambda : defaultdict(list))
# various things to look for inside compose file
Пример #13
0
    def test_restart_compose_service(self):
        from compose.config.config import ConfigFile, ConfigDetails
        from compose.config.config import load as load_config
        from compose.project import Project

        composefile = """
        version: '2'
        services:
          app:
            image: alpine
            command: sh -c 'date +%s ; sleep 3600'

          pygen:
            image: pygen-build
            command: >
              --template '#ok'
              --restart app
              --one-shot
            volumes:
              - /var/run/docker.sock:/var/run/docker.sock:ro
            depends_on:
              - app
        """

        with open('/tmp/pygen-composefile.yml', 'w') as target:
            target.write(composefile)

        config = ConfigFile.from_filename('/tmp/pygen-composefile.yml')
        details = ConfigDetails('/tmp', [config])
        project = Project.from_config('cmpse', load_config(details),
                                      self.remote_client.api)

        with self.suppress_stderr():
            project.up(detached=True,
                       service_names=['app'],
                       scale_override={'app': 2})

            app = project.get_service('app')

            for _ in range(60):
                if len(app.containers()) < 2 or not all(
                        c.is_running for c in app.containers()):
                    self.wait(0.5)

            initial_logs = list(''.join(
                c.logs(stdout=True) for c in app.containers()).splitlines())

            project.up(detached=True, scale_override={'app': 2})

            pygen_service = project.get_service('pygen')
            pygen_container = next(iter(pygen_service.containers()))
            pygen_container.wait()

            for _ in range(60):
                if len(app.containers()) < 2 or not all(
                        c.is_running for c in app.containers()):
                    self.wait(0.5)

            newer_logs = list(''.join(
                c.logs(stdout=True) for c in app.containers()).splitlines())

            self.assertNotEqual(tuple(sorted(newer_logs)),
                                tuple(sorted(initial_logs)))
            self.assertEqual(len(newer_logs), 4)