Mercurial > libervia-backend
comparison sat/plugins/plugin_app_manager_docker/__init__.py @ 3373:f44402f8a81f
plugin app managed docker: handle Docker application with App Manager
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 28 Sep 2020 21:10:33 +0200 (2020-09-28) |
parents | |
children | 3b08caa805e7 |
comparison
equal
deleted
inserted
replaced
3372:5d926c7b0d99 | 3373:f44402f8a81f |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 # SàT plugin to manage Docker | |
4 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org) | |
5 | |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 from pathlib import Path | |
20 from twisted.python.procutils import which | |
21 from sat.core.i18n import _ | |
22 from sat.core.constants import Const as C | |
23 from sat.core import exceptions | |
24 from sat.core.log import getLogger | |
25 from sat.tools.common import async_process | |
26 | |
27 log = getLogger(__name__) | |
28 | |
29 | |
30 PLUGIN_INFO = { | |
31 C.PI_NAME: "Docker Applications Manager", | |
32 C.PI_IMPORT_NAME: "APP_MANAGER_DOCKER", | |
33 C.PI_TYPE: C.PLUG_TYPE_MISC, | |
34 C.PI_MODES: C.PLUG_MODE_BOTH, | |
35 C.PI_DEPENDENCIES: ["APP_MANAGER"], | |
36 C.PI_MAIN: "AppManagerDocker", | |
37 C.PI_HANDLER: "no", | |
38 C.PI_DESCRIPTION: _( | |
39 """Applications Manager for Docker"""), | |
40 } | |
41 | |
42 | |
43 class AppManagerDocker: | |
44 name = "docker-compose" | |
45 discover_path = Path(__file__).parent | |
46 | |
47 def __init__(self, host): | |
48 log.info(_("Docker App Manager initialization")) | |
49 try: | |
50 self.docker_compose_path = which('docker-compose')[0] | |
51 except IndexError: | |
52 raise exceptions.NotFound( | |
53 '"docker-compose" executable not found, Docker can\'t used with ' | |
54 'application manager') | |
55 self.host = host | |
56 self._am = host.plugins['APP_MANAGER'] | |
57 self._am.register(self) | |
58 | |
59 async def start(self, app_data: dict) -> None: | |
60 await self._am.startCommon(app_data) | |
61 working_dir = app_data['_instance_dir_path'] | |
62 try: | |
63 override = app_data['override'] | |
64 except KeyError: | |
65 pass | |
66 else: | |
67 log.debug("writting override file") | |
68 override_path = working_dir / "docker-compose.override.yml" | |
69 with override_path.open("w") as f: | |
70 self._am.dump(override, f) | |
71 await async_process.run( | |
72 self.docker_compose_path, | |
73 "up", | |
74 "--detach", | |
75 path=str(working_dir), | |
76 ) | |
77 | |
78 async def stop(self, app_data: dict) -> None: | |
79 working_dir = app_data['_instance_dir_path'] | |
80 await async_process.run( | |
81 self.docker_compose_path, | |
82 "down", | |
83 path=str(working_dir), | |
84 ) | |
85 | |
86 async def computeExpose(self, app_data: dict) -> dict: | |
87 working_dir = app_data['_instance_dir_path'] | |
88 expose = app_data['expose'] | |
89 ports = expose.get('ports', {}) | |
90 for name, port_data in list(ports.items()): | |
91 try: | |
92 service = port_data['service'] | |
93 private = port_data['private'] | |
94 int(private) | |
95 except (KeyError, ValueError): | |
96 log.warning( | |
97 f"invalid value found for {name!r} port in {app_data['_file_path']}") | |
98 continue | |
99 exposed_port = await async_process.run( | |
100 self.docker_compose_path, | |
101 "port", | |
102 service, | |
103 str(private), | |
104 path=str(working_dir), | |
105 ) | |
106 exposed_port = exposed_port.decode().strip() | |
107 try: | |
108 addr, port = exposed_port.split(':') | |
109 int(port) | |
110 except ValueError: | |
111 log.warning( | |
112 f"invalid exposed port for {name}, ignoring: {exposed_port!r}") | |
113 del ports[name] | |
114 else: | |
115 ports[name] = exposed_port |