Test Failed
Branch v4.0-dev (e44d7e)
by Emmanuel
04:49
created

stakkr_compose._set_env_from_config()   A

Complexity

Conditions 3

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 12
rs 9.9
c 0
b 0
f 0
cc 3
nop 1
1
#!/usr/bin/env python
2
# coding: utf-8
3
"""
4
CLI Main Entry Point.
5
6
Wraps docker-compose and build it from what has been taken from config.
7
"""
8
9
import glob
10
import os
11
import subprocess
12
import sys
13
import click
14
from stakkr import file_utils
15
from stakkr.configreader import Config
16
17
18
@click.command(help="Wrapper for docker-compose",
19
               context_settings=dict(ignore_unknown_options=True))
20
@click.option('--config-file', '-c', help="Set stakkr config file location (default stakkr.yml)")
21
@click.argument('command', nargs=-1, type=click.UNPROCESSED)
22
def cli(config_file: str, command):
23
    """Command line entry point."""
24
    config, config_file = _get_config(config_file)
25
26
    # Set main config and services as env variables
27
    _set_env_from_config(config)
28
29
    # Register proxy env parameters
30
    _set_env_for_proxy(config['proxy'])
31
32
    # set the base command
33
    base_cmd = _get_base_command(config)
34
35
    msg = click.style('[VERBOSE] ', fg='green')
36
    msg += 'Compose command: ' + ' '.join(base_cmd + list(command))
37
    click.echo(msg, err=True)
38
    subprocess.call(base_cmd + list(command))
39
40
41
def _add_services_from_plugins(project_dir: str, available_services: list):
42
    """Read plugin path and extract services in subdirectories services/."""
43
    from pkg_resources import iter_entry_points
44
45
    # Override services with plugins
46
    for entry in iter_entry_points('stakkr.plugins'):
47
        plugin_dir = str(entry).split('=')[0].strip()
48
        services_dir = project_dir + '/plugins/' + plugin_dir + '/services'
49
50
        conf_files = _get_services_from_dir(services_dir)
51
        for conf_file in conf_files:
52
            available_services[conf_file[:-4]] = services_dir + '/' + conf_file
53
54
    return available_services
55
56
57
def _add_local_services(project_dir: str, available_services: list):
58
    """Get services in the virtualenv services/ directory, so specific to that stakkr."""
59
    services_dir = project_dir + '/services/*/docker-compose'
60
    for service_dir in glob.glob(services_dir):
61
        conf_files = _get_services_from_dir(service_dir)
62
        for conf_file in conf_files:
63
            available_services[conf_file[:-4]] = service_dir + '/' + conf_file
64
65
    return available_services
66
67
68
def get_available_services(project_dir: str):
69
    """Get standard services bundled with stakkr."""
70
    services_dir = file_utils.get_dir('static') + '/services/'
71
    conf_files = _get_services_from_dir(services_dir)
72
73
    services = dict()
74
    for conf_file in conf_files:
75
        services[conf_file[:-4]] = services_dir + conf_file
76
77
    services = _add_services_from_plugins(project_dir, services)
78
    services = _add_local_services(project_dir, services)
79
80
    return services
81
82
83
def _get_base_command(config: dict):
84
    """Build the docker-compose file to be run as a command."""
85
    main_file = 'docker-compose.yml'
86
    # Set the network subnet ?
87
    if config['subnet'] != '':
88
        main_file = 'docker-compose.subnet.yml'
89
    cmd = ['docker-compose', '-f', file_utils.get_file('static', main_file)]
90
91
    # What to load
92
    activated_services = _get_enabled_services_files(
93
        config['project_dir'],
94
        [svc for svc, opts in config['services'].items() if opts['enabled'] is True])
95
    # Create the command
96
    services = []
97
    for service in activated_services:
98
        services.append('-f')
99
        services.append(service)
100
101
    return cmd + services + ['-p', config['project_name']]
102
103
104
def _get_config(config_file: str):
105
    """Read main stakkr.yml file."""
106
    config_reader = Config(config_file)
107
    config = config_reader.read()
108
109
    if config is False:
110
        config.display_errors()
111
        sys.exit(1)
112
113
    return config, config_reader.config_file
114
115
116
def _get_enabled_services_files(project_dir: str, configured_services: list):
117
    """Compile all available services : standard, plugins, local install."""
118
    available_services = get_available_services(project_dir)
119
120
    services_files = []
121
    for service in configured_services:
122
        if service not in available_services:
123
            msg = 'Error: service "{}" has no configuration file. '.format(service)
124
            msg += 'Check your config'
125
            click.secho(msg, fg='red')
126
            sys.exit(1)
127
        services_files.append(available_services[service])
128
129
    return services_files
130
131
132
def _get_gid(gid: int):
133
    if gid is not None:
134
        return str(gid)
135
136
    return '1000' if os.name == 'nt' else str(os.getgid())
137
138
139
def _get_services_from_dir(services_dir: str):
140
    if os.path.isdir(services_dir) is False:
141
        return []
142
143
    return [service for service in os.listdir(services_dir) if service.endswith('.yml')]
144
145
146
def _get_uid(uid: int):
147
    if uid is not None:
148
        return str(uid)
149
150
    return '1000' if os.name == 'nt' else str(os.getuid())
151
152
153
def _set_env_for_proxy(config: dict):
154
    """Define environment variables to be used in services yaml."""
155
    os.environ['PROXY_ENABLED'] = str(config['enabled'])
156
    os.environ['PROXY_DOMAIN'] = str(config['domain'])
157
    os.environ['PROXY_PORT'] = str(config['port'])
158
159
160
def _set_env_for_services(services: dict):
161
    for service, params in services.items():
162
        if params['enabled'] is False:
163
            continue
164
165
        for param, value in params.items():
166
            env_var = 'DOCKER_{}_{}'.format(service, param).upper()
167
            os.environ[env_var] = str(value)
168
169
170
def _set_env_from_config(config: dict):
171
    """Define environment variables to be used in services yaml."""
172
    os.environ['COMPOSE_BASE_DIR'] = config['project_dir']
173
    os.environ['COMPOSE_PROJECT_NAME'] = config['project_name']
174
    os.environ['DOCKER_UID'] = _get_uid(config['uid'])
175
    os.environ['DOCKER_GID'] = _get_gid(config['gid'])
176
    for parameter, value in config.items():
177
        if parameter == 'services':
178
            _set_env_for_services(value)
179
            continue
180
181
        os.environ['DOCKER_{}'.format(parameter.upper())] = str(value)
182
183
184
if __name__ == '__main__':
185
    cli()
186