Exemplo n.º 1
0
def build_config_details(contents,
                         working_dir='working_dir',
                         filename='filename.yml'):
    return ConfigDetails(
        working_dir,
        [ConfigFile(filename, contents)],
    )
Exemplo n.º 2
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)
Exemplo n.º 3
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
    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)
Exemplo n.º 5
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
Exemplo n.º 6
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
Exemplo n.º 7
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
Exemplo n.º 8
0
    def test_build_native_builder_called(self, cli_build):
        options = {
            '--build-arg': ['MYVAR', 'ARG=123'],
            '--no-cache': True,
            '--pull': True,
            '--force-rm': False,
            '--memory': True,
            '--compress': False,
            '--parallel': False,
            '--quiet': True,
            '--progress': 'progress',
            'SERVICE': ['service'],
            'COMMAND': 'build',
        }
        env = Environment({
            'MYVAR': 'MYVALUE',
        })

        if cli_build:
            env['COMPOSE_DOCKER_CLI_BUILD'] = '1'
            env['COMPOSE_DOCKER_CLI_BUILD_EXTRA_ARGS'] = '--extra0 --extra1=1'

        iidfile = [None]

        def mock_mktemp():
            iidfile[0] = tempfile.mktemp()
            with open(iidfile[0], 'w') as f:
                f.write(':12345')
            return iidfile[0]

        with mock.patch('compose.cli.main.TopLevelCommand.toplevel_environment', new=env), \
                mock.patch('compose.cli.main.Environment.from_env_file', return_value=env), \
                mock.patch('compose.service.subprocess.Popen') as mock_subprocess_popen, \
                mock.patch('compose.service.tempfile', new=mock.Mock(mktemp=mock_mktemp)), \
                mock.patch('compose.cli.command.get_client') as mock_get_client, \
                mock.patch('compose.cli.command.config.find') as mock_config_find, \
                mock.patch('compose.cli.command.config.load') as mock_config_load:
            mock_config_find.return_value = ConfigDetails(
                working_dir='working_dir',
                config_files=[ConfigFile(filename='config_file', config={})],
                environment=env,
            )
            mock_config_load.return_value = Config(
                version=COMPOSEFILE_V3_4,
                services=[{
                    'name': 'service',
                    'build': {
                        'context': '.',
                    },
                }],
                volumes={},
                networks={},
                secrets={},
                configs={},
            )
            mock_get_client.return_value.api_version = '1.35'
            mock_build = mock_get_client.return_value.build
            mock_build.return_value = \
                mock_subprocess_popen.return_value.__enter__.return_value.stdout = \
                io.StringIO('{"stream": "Successfully built 12345"}')

            project = [None]

            def handler(command, options):
                project[0] = command.project
                command.build(options)

            perform_command(options, handler=handler, command_options=options)
            if not cli_build:
                assert mock_build.called
                assert mock_build.call_args[1]['buildargs'] == {
                    'MYVAR': 'MYVALUE',
                    'ARG': '123'
                }
                assert mock_build.call_args[1]['pull']
                assert mock_build.call_args[1]['nocache']
                assert not mock_build.call_args[1]['forcerm']
                assert not mock_build.call_args[1]['gzip']
                assert not project[0].native_build_enabled
            else:
                assert mock_subprocess_popen.call_args[0][0] == [
                    'docker',
                    'build',
                    '--build-arg',
                    'MYVAR=MYVALUE',
                    '--build-arg',
                    'ARG=123',
                    '--memory',
                    'True',
                    '--no-cache',
                    '--progress',
                    'progress',
                    '--pull',
                    '--tag',
                    'working_dir_service',
                    '--iidfile',
                    iidfile[0],
                    '--extra0',
                    '--extra1=1',
                    '.',
                ]
                assert project[0].native_build_enabled
Exemplo n.º 9
0
    def test_build_native_args_propagated(self, cli_build):
        options = {
            '--build-arg': ['MYVAR', 'ARG=123'],
            '--no-cache': True,
            '--pull': True,
            '--force-rm': True,
            '--memory': True,
            '--compress': True,
            '--parallel': True,
            '--quiet': True,
            '--progress': 'progress',
            'SERVICE': ['service'],
            'COMMAND': 'build',
        }
        env = Environment({
            'MYVAR': 'MYVALUE',
        })
        if cli_build:
            env['COMPOSE_DOCKER_CLI_BUILD'] = '1'
        with mock.patch('compose.cli.main.TopLevelCommand.toplevel_environment', new=env), \
                mock.patch('compose.cli.main.Environment.from_env_file', return_value=env), \
                mock.patch('compose.project.Project.build') as mock_build, \
                mock.patch('compose.cli.command.config.find') as mock_config_find, \
                mock.patch('compose.cli.command.config.load') as mock_config_load:
            mock_config_find.return_value = ConfigDetails(
                working_dir='working_dir',
                config_files=[ConfigFile(filename='config_file', config={})],
                environment=env,
            )
            mock_config_load.return_value = Config(
                version=COMPOSEFILE_V3_4,
                services=[],
                volumes={},
                networks={},
                secrets={},
                configs={},
            )
            project = [None]

            def handler(command, options):
                project[0] = command.project
                command.build(options)

            perform_command(options, handler=handler, command_options=options)
            assert mock_build.call_args == mock.call(
                service_names=['service'],
                no_cache=True,
                pull=True,
                force_rm=True,
                memory=True,
                rm=True,
                build_args={
                    'MYVAR': 'MYVALUE',
                    'ARG': '123'
                },
                gzip=True,
                parallel_build=True,
                silent=True,
                progress='progress',
            )
            assert project[0].native_build_enabled == bool(cli_build)
Exemplo n.º 10
0
if not os.path.exists(os.path.join(WORKDIR, '.env')):
    copyfile(
        os.path.join(WORKDIR, './.env.example'),
        os.path.join(WORKDIR, './.env'),
    )

configs = []
for file in CONFIGS:
    print(f'Reading file: {file}')
    with open(file, 'r') as f:
        configs.append(ConfigFile(None, yaml.safe_load(f.read())))

print('Building config')
env = config.environment.Environment()
details = ConfigDetails(WORKDIR, configs, env)
cfg = config.load(details, False)


def relativize(path: str) -> str:
    result = f'./{os.path.relpath(path, WORKDIR)}' if path and path.startswith(
        WORKDIR) else path
    if result in REPLACE_MOUNTS:
        result = REPLACE_MOUNTS[result]
    return result


print('Preprocessing config')
for service in cfg.services:
    print(f'\tPreprocessing service: {service["name"]}')
    if 'build' in service:
Exemplo n.º 11
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)