Passed
Push — master ( 87dd90...0fd795 )
by Emmanuel
14:51
created

stakkr_compose.get_configured_services()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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