annotate libervia/backend/plugins/plugin_misc_app_manager/__init__.py @ 4247:4aa62767f501

plugin app manager: various improvements: - Generated password must now be named and are stored, so they are re-used on following restarts. Password size can now be specified. - New `not` filter for `!libervia_param` to inverse a boolean value. - Former `front_url` field has been renamed to `web_url_path` as it is the URL path used for web frontend. All Web frontend related field are prefixed with `web_`. - `front_url` is now used to specify a whole front URL (notably useful if an app uses its own domain). A list can be used to retrieve a key, like for `url_prefix`, and `https` scheme is added if no scheme is specified. - An abstract class is now used for App Managers. - Last application start time is stored in persistent data.
author Goffi <goffi@goffi.org>
date Fri, 31 May 2024 11:08:14 +0200
parents libervia/backend/plugins/plugin_misc_app_manager.py@c93b02000ae4
children 0d7bb4df2343
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python3
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
3 # Libervia plugin to manage external applications
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
4 # Copyright (C) 2009-2024 Jérôme Poisson (goffi@goffi.org)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
5
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
19 from functools import partial, reduce
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from pathlib import Path
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 import secrets
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 import string
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
23 import tempfile
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
24 import time
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
25 from typing import Any, Callable, List, Optional
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
26 from urllib.parse import urlparse, urlunparse
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
27
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 import shortuuid
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 from twisted.internet import defer
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 from twisted.python.procutils import which
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
31 from yaml.constructor import ConstructorError
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
32
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
33 from libervia.backend.core import exceptions
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
34 from libervia.backend.core.constants import Const as C
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
35 from libervia.backend.core.i18n import _
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
36 from libervia.backend.core.log import getLogger
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
37 from libervia.backend.memory import persistent
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
38 from libervia.backend.plugins.plugin_misc_app_manager.models import AppManagerBackend
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
39 from libervia.backend.tools.common import data_format
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
40 from libervia.backend.tools.common import async_process
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 log = getLogger(__name__)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 import yaml
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 except ImportError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 raise exceptions.MissingModule(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 'Missing module PyYAML, please download/install it. You can use '
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 '"pip install pyyaml"'
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 from yaml import CLoader as Loader, CDumper as Dumper
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 except ImportError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 log.warning(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 "Can't use LibYAML binding (is libyaml installed?), pure Python version will be "
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 "used, but it is slower"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 from yaml import Loader, Dumper
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
61
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 PLUGIN_INFO = {
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 C.PI_NAME: "Applications Manager",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 C.PI_IMPORT_NAME: "APP_MANAGER",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 C.PI_TYPE: C.PLUG_TYPE_MISC,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 C.PI_MODES: C.PLUG_MODE_BOTH,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 C.PI_MAIN: "AppManager",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 C.PI_HANDLER: "no",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 C.PI_DESCRIPTION: _(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 """Applications Manager
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 Manage external applications using packagers, OS virtualization/containers or other
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 software management tools.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 """),
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 }
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
79 APP_FILE_PREFIX = "libervia_app_"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 class AppManager:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 load = partial(yaml.load, Loader=Loader)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 dump = partial(yaml.dump, Dumper=Dumper)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 def __init__(self, host):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 log.info(_("plugin Applications Manager initialization"))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 self.host = host
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 self._managers = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 self._apps = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 self._started = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 # instance id to app data map
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 self._instances = {}
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
94
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
95
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
96 self.persistent_data = persistent.LazyPersistentBinaryDict("app_manager")
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
97
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
98 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
99 "applications_list",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 in_sign="as",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 out_sign="as",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 method=self.list_applications,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
105 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
106 "application_start",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 in_sign="ss",
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
109 out_sign="s",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 method=self._start,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
113 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
114 "application_stop",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 in_sign="sss",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 out_sign="",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 method=self._stop,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
121 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
122 "application_exposed_get",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 in_sign="sss",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 out_sign="s",
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
126 method=self._get_exposed,
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 )
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
129 # application has been started succeesfully,
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
130 # args: name, instance_id, extra
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
131 host.bridge.add_signal(
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
132 "application_started", ".plugin", signature="sss"
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
133 )
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
134 # application went wrong with the application
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
135 # args: name, instance_id, extra
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
136 host.bridge.add_signal(
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
137 "application_error", ".plugin", signature="sss"
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
138 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 yaml.add_constructor(
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
140 "!libervia_conf", self._libervia_conf_constr, Loader=Loader)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 yaml.add_constructor(
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
142 "!libervia_generate_pwd", self._libervia_generate_pwd_constr, Loader=Loader)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 yaml.add_constructor(
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
144 "!libervia_param", self._libervia_param_constr, Loader=Loader)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
145
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 def unload(self):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 log.debug("unloading applications manager")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 for instances in self._started.values():
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 for instance in instances:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 data = instance['data']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 if not data['single_instance']:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 log.debug(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 f"cleaning temporary directory at {data['_instance_dir_path']}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 data['_instance_dir_obj'].cleanup()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
155
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
156 def _libervia_conf_constr(self, loader, node) -> str:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
157 """Get a value from Libervia configuration
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
158
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 A list is expected with either "name" of a config parameter, a one or more of
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 those parameters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 - section
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 - name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 - default value
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 - filter
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 filter can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 - "first": get the first item of the value
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
167 - "not": get the opposite value (to be used with booleans)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 config_data = loader.construct_sequence(node)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 if len(config_data) == 1:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 section, name, default, filter_ = "", config_data[0], None, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 if len(config_data) == 2:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 (section, name), default, filter_ = config_data, None, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 elif len(config_data) == 3:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 (section, name, default), filter_ = config_data, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 elif len(config_data) == 4:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 section, name, default, filter_ = config_data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 raise ValueError(
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
180 f"invalid !libervia_conf value ({config_data!r}), a list of 1 to 4 items "
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
181 "is expected"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
183
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
184 value = self.host.memory.config_get(section, name, default)
3564
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
185 # FIXME: "public_url" is used only here and doesn't take multi-sites into account
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
186 if name == "public_url" and (not value or value.startswith('http')):
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 if not value:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 log.warning(_(
3564
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
189 'No value found for "public_url", using "example.org" for '
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
190 'now, please set the proper value in libervia.conf'))
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 log.warning(_(
3564
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
193 'invalid value for "public_url" ({value}), it musts not start with '
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
194 'schema ("http"), ignoring it and using "example.org" '
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
195 'instead')
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 .format(value=value))
3564
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
197 value = "example.org"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
198
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 if filter_ is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 pass
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 elif filter_ == 'first':
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 value = value[0]
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
203 elif filter_ == "not":
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
204 value = C.bool(value)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
205 value = C.bool_const(not value).lower()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 raise ValueError(f"unmanaged filter: {filter_}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
208
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 return value
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
210
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
211 def _libervia_generate_pwd_constr(self, loader, node) -> str:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
212 """Generate a password and store it in persistent data.
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
213
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
214 If the password has already been generated previously, it is reused.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
215 Mapping arguments are:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
216 ``name`` (str) **required**
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
217 Name of the password. Will be used to store it.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
218 ``size`` (int)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
219 Size of the password to generate. Default to 30
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
220 """
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
221 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
222 kwargs = loader.construct_mapping(node)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
223 name = kwargs["name"]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
224 except (ConstructorError, KeyError):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
225 raise ValueError(
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
226 '!libervia_generate_pwd map arguments is missing. At least "name" '
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
227 "must be specified."
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
228 )
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
229 pwd_data_key = f"pwd_{name}"
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
230 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
231 key = self._app_persistent_data[pwd_data_key]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
232 except KeyError:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
233 alphabet = string.ascii_letters + string.digits
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
234 key_size = int(kwargs.get("size", 30))
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
235 key = ''.join(secrets.choice(alphabet) for __ in range(key_size))
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
236 self._app_persistent_data[pwd_data_key] = key
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
237 else:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
238 log.debug(f"Re-using existing key for {name!r} password.")
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
239 return key
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
240
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
241 def _libervia_param_constr(self, loader, node) -> str:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 """Get a parameter specified when starting the application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
243
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 The value can be either the name of the parameter to get, or a list as
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 [name, default_value]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 name, default = loader.construct_sequence(node)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 except ConstructorError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 name, default = loader.construct_scalar(node), None
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
251 assert self._params is not None
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
252 return self._params.get(name, default)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
253
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
254 def register(self, manager):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 name = manager.name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
256 if name in self._managers:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
257 raise exceptions.ConflictError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
258 f"There is already a manager with the name {name}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 self._managers[manager.name] = manager
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
260 if manager.discover_path is not None:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 self.discover(manager.discover_path, manager)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
262
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
263 def get_manager(self, app_data: dict) -> AppManagerBackend:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
264 """Get manager instance needed for this app
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
265
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
266 @raise exceptions.DataError: something is wrong with the type
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
267 @raise exceptions.NotFound: manager is not registered
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
268 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
269 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
270 app_type = app_data["type"]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
271 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
272 raise exceptions.DataError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
273 "app file doesn't have the mandatory \"type\" key"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
274 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
275 if not isinstance(app_type, str):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
276 raise exceptions.DataError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 f"invalid app data type: {app_type!r}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
279 app_type = app_type.strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 return self._managers[app_type]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
282 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
283 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
284 f"No manager found to manage app of type {app_type!r}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
285
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
286 def get_app_data(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
287 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
288 id_type: Optional[str],
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 identifier: str
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 ) -> dict:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
291 """Retrieve instance's app_data from identifier
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
292
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
293 @param id_type: type of the identifier, can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
294 - "name": identifier is a canonical application name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
295 the first found instance of this application is returned
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
296 - "instance": identifier is an instance id
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 @param identifier: identifier according to id_type
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
298 @return: instance application data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
299 @raise exceptions.NotFound: no instance with this id can be found
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
300 @raise ValueError: id_type is invalid
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
301 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
302 if not id_type:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
303 id_type = 'name'
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
304 if id_type == 'name':
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
305 identifier = identifier.lower().strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
306 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
307 return next(iter(self._started[identifier]))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
308 except (KeyError, StopIteration):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
309 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
310 f"No instance of {identifier!r} is currently running"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
311 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
312 elif id_type == 'instance':
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
313 instance_id = identifier
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
314 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
315 return self._instances[instance_id]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
316 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
317 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
318 f"There is no application instance running with id {instance_id!r}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
319 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
320 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
321 raise ValueError(f"invalid id_type: {id_type!r}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
322
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
323 def discover(
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
324 self,
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
325 dir_path: Path,
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
326 manager: AppManagerBackend|None = None
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
327 ) -> None:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
328 """Search for app configuration file.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
329
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
330 App configuration files must start with [APP_FILE_PREFIX] and have a ``.yaml``
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
331 extension.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
332 """
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
333 for file_path in dir_path.glob(f"{APP_FILE_PREFIX}*.yaml"):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
334 if manager is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
335 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
336 app_data = self.parse(file_path)
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
337 manager = self.get_manager(app_data)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
338 except (exceptions.DataError, exceptions.NotFound) as e:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
339 log.warning(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
340 f"Can't parse {file_path}, skipping: {e}")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
341 continue
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
342 app_name = file_path.stem[len(APP_FILE_PREFIX):].strip().lower()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
343 if not app_name:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
344 log.warning(f"invalid app file name at {file_path}")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
345 continue
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
346 app_dict = self._apps.setdefault(app_name, {})
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
347 manager_set = app_dict.setdefault(manager, set())
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
348 manager_set.add(file_path)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
349 log.debug(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
350 f"{app_name!r} {manager.name} application found"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
351 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
352
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
353 def parse(self, file_path: Path, params: Optional[dict] = None) -> dict:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
354 """Parse Libervia application file
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
355
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
356 @param params: parameters for running this instance
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
357 @raise exceptions.DataError: something is wrong in the file
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
358 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
359 if params is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
360 params = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
361 with file_path.open() as f:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
362 # we set parameters to be used only with this instance
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
363 # no async method must used between this assignation and `load`
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
364 self._params = params
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
365 app_data = self.load(f)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
366 self._params = None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
367 if "name" not in app_data:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
368 # note that we don't use lower() here as we want human readable name and
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
369 # uppercase may be set on purpose
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
370 app_data['name'] = file_path.stem[len(APP_FILE_PREFIX):].strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
371 single_instance = app_data.setdefault("single_instance", True)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
372 if not isinstance(single_instance, bool):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
373 raise ValueError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
374 f'"single_instance" must be a boolean, but it is {type(single_instance)}'
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
375 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
376 return app_data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
377
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
378 def list_applications(self, filters: Optional[List[str]]) -> List[str]:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
379 """List available application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
380
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
381 @param filters: only show applications matching those filters.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
382 using None will list all known applications
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
383 a filter can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
384 - available: applications available locally
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
385 - running: only show launched applications
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
386 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
387 if not filters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
388 return list(self.apps)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
389 found = set()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
390 for filter_ in filters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
391 if filter_ == "available":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
392 found.update(self._apps)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
393 elif filter_ == "running":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
394 found.update(self._started)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
395 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
396 raise ValueError(f"Unknown filter: {filter_}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
397 return list(found)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
398
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
399 def _start(self, app_name, extra):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
400 extra = data_format.deserialise(extra)
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
401 d = defer.ensureDeferred(self.start(str(app_name), extra))
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
402 d.addCallback(data_format.serialise)
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
403 return d
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
404
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
405 async def start(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
406 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
407 app_name: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
408 extra: Optional[dict] = None,
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
409 ) -> dict:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
410 """Start an application
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
411
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
412 @param app_name: name of the application to start
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
413 @param extra: extra parameters
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
414 @return: data with following keys:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
415 - name (str): canonical application name
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
416 - instance (str): instance ID
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
417 - started (bool): True if the application is already started
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
418 if False, the "application_started" signal should be used to get notificed
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
419 when the application is actually started
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
420 - expose (dict): exposed data as given by [self.get_exposed]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
421 exposed data which need to be computed are NOT returned, they will
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
422 available when the app will be fully started, throught the
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
423 [self.get_exposed] method.
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
424 """
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
425 # FIXME: for now we use the first app manager available for the requested app_name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
426 # TODO: implement running multiple instance of the same app if some metadata
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
427 # to be defined in app_data allows explicitly it.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
428 app_name = app_name.lower().strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
429 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
430 app_file_path = next(iter(next(iter(self._apps[app_name].values()))))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
431 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
432 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
433 f"No application found with the name {app_name!r}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
434 )
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
435 log.info(f"starting {app_name!r}")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
436 self._app_persistent_data = await self.persistent_data.get(app_name) or {}
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
437 self._app_persistent_data["last_started"] = time.time()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
438 started_data = self._started.setdefault(app_name, [])
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
439 app_data = self.parse(app_file_path, extra)
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
440 await self.persistent_data.aset(app_name, self._app_persistent_data)
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
441 app_data["_started"] = False
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
442 app_data['_file_path'] = app_file_path
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
443 app_data['_name_canonical'] = app_name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
444 single_instance = app_data['single_instance']
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
445 ret_data = {
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
446 "name": app_name,
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
447 "started": False
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
448 }
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
449 if single_instance:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
450 if started_data:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
451 instance_data = started_data[0]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
452 instance_id = instance_data["_instance_id"]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
453 ret_data["instance"] = instance_id
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
454 ret_data["started"] = instance_data["_started"]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
455 ret_data["expose"] = await self.get_exposed(
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
456 instance_id, "instance", {"skip_compute": True}
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
457 )
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
458 log.info(f"{app_name!r} is already started or being started")
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
459 return ret_data
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
460 else:
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
461 cache_path = self.host.memory.get_cache_path(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
462 PLUGIN_INFO[C.PI_IMPORT_NAME], app_name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
463 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
464 cache_path.mkdir(0o700, parents=True, exist_ok=True)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
465 app_data['_instance_dir_path'] = cache_path
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
466 else:
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
467 dest_dir_obj = tempfile.TemporaryDirectory(prefix="libervia_app_")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
468 app_data['_instance_dir_obj'] = dest_dir_obj
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
469 app_data['_instance_dir_path'] = Path(dest_dir_obj.name)
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
470 instance_id = ret_data["instance"] = app_data['_instance_id'] = shortuuid.uuid()
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
471 manager = self.get_manager(app_data)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
472 app_data['_manager'] = manager
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
473 started_data.append(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
474 self._instances[instance_id] = app_data
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
475 # we retrieve exposed data such as url_prefix which can be useful computed exposed
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
476 # data must wait for the app to be started, so we skip them for now
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
477 ret_data["expose"] = await self.get_exposed(
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
478 instance_id, "instance", {"skip_compute": True}
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
479 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
480
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
481 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
482 start = manager.start
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
483 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
484 raise exceptions.InternalError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
485 f"{manager.name} doesn't have the mandatory \"start\" method"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
486 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
487 else:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
488 defer.ensureDeferred(self.start_app(start, app_data))
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
489 return ret_data
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
490
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
491 async def start_app(self, start_cb: Callable, app_data: dict) -> None:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
492 app_name = app_data["_name_canonical"]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
493 instance_id = app_data["_instance_id"]
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
494 try:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
495 await start_cb(app_data)
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
496 except Exception as e:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
497 log.exception(f"Can't start libervia app {app_name!r}")
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
498 self.host.bridge.application_error(
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
499 app_name,
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
500 instance_id,
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
501 data_format.serialise(
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
502 {
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
503 "class": str(type(e)),
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
504 "msg": str(e)
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
505 }
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
506 ))
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
507 else:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
508 app_data["_started"] = True
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
509 self.host.bridge.application_started(app_name, instance_id, "")
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
510 log.info(f"{app_name!r} started")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
511
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
512 def _stop(self, identifier, id_type, extra):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
513 extra = data_format.deserialise(extra)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
514 return defer.ensureDeferred(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
515 self.stop(str(identifier), str(id_type) or None, extra))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
516
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
517 async def stop(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
518 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
519 identifier: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
520 id_type: Optional[str] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
521 extra: Optional[dict] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
522 ) -> None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
523 if extra is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
524 extra = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
525
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
526 app_data = self.get_app_data(id_type, identifier)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
527
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
528 log.info(f"stopping {app_data['name']!r}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
529
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
530 app_name = app_data['_name_canonical']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
531 instance_id = app_data['_instance_id']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
532 manager = app_data['_manager']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
533
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
534 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
535 stop = manager.stop
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
536 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
537 raise exceptions.InternalError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
538 f"{manager.name} doesn't have the mandatory \"stop\" method"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
539 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
540 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
541 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
542 await stop(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
543 except Exception as e:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
544 log.warning(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
545 f"Instance {instance_id} of application {app_name} can't be stopped "
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
546 f"properly: {e}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
547 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
548 return
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
549
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
550 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
551 del self._instances[instance_id]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
552 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
553 log.error(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
554 f"INTERNAL ERROR: {instance_id!r} is not present in self._instances")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
555
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
556 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
557 self._started[app_name].remove(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
558 except ValueError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
559 log.error(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
560 "INTERNAL ERROR: there is no app data in self._started with id "
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
561 f"{instance_id!r}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
562 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
563
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
564 log.info(f"{app_name!r} stopped")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
565
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
566 def _get_exposed(self, identifier, id_type, extra):
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
567 extra = data_format.deserialise(extra)
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
568 d = defer.ensureDeferred(self.get_exposed(identifier, id_type, extra))
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
569 d.addCallback(lambda d: data_format.serialise(d))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
570 return d
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
571
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
572 def get_app_data_value(self, path: list[str], data: dict[str, Any]) -> Any:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
573 """Return a value from app data from its path.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
574
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
575 @param path: sequence of keys to get to retrieve the value
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
576 @return: requested value
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
577 @raise KeyError: Can't find the requested value.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
578 """
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
579 return reduce(lambda l, k: l[k], path, data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
580
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
581 async def get_exposed(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
582 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
583 identifier: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
584 id_type: Optional[str] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
585 extra: Optional[dict] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
586 ) -> dict:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
587 """Get data exposed by the application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
588
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
589 The manager's "compute_expose" method will be called if it exists. It can be used
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
590 to handle manager specific conventions.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
591 """
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
592 app_data = self.get_app_data(id_type, identifier)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
593 if app_data.get('_exposed_computed', False):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
594 return app_data['expose']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
595 if extra is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
596 extra = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
597 expose = app_data.setdefault("expose", {})
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
598 if "passwords" in expose:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
599 passwords = expose['passwords']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
600 for name, value in list(passwords.items()):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
601 if isinstance(value, list):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
602 # if we have a list, is the sequence of keys leading to the value
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
603 # to expose.
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
604 try:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
605 passwords[name] = self.get_app_data_value(value, app_data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
606 except KeyError:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
607 log.warning(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
608 f"Can't retrieve exposed value for password {name!r}: {e}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
609 del passwords[name]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
610
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
611 for key in ("url_prefix", "front_url"):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
612 value = expose.get(key)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
613 if isinstance(value, list):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
614 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
615 expose[key] = self.get_app_data_value(value, app_data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
616 except KeyError:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
617 log.warning(
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
618 f"Can't retrieve exposed value for {key!r} at {value}"
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
619 )
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
620 del expose[key]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
621
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
622 front_url = expose.get("front_url")
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
623 if front_url:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
624 # we want to be sure that a scheme is defined, defaulting to ``https``
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
625 parsed_url = urlparse(front_url)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
626 if not parsed_url.scheme:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
627 if not parsed_url.netloc:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
628 path_elt = parsed_url.path.split("/", 1)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
629 parsed_url = parsed_url._replace(
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
630 netloc=path_elt[0],
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
631 path=f"/{path_elt[1]}" if len(path_elt) > 1 else ""
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
632 )
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
633 parsed_url = parsed_url._replace(scheme='https')
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
634 expose["front_url"] = urlunparse(parsed_url)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
635
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
636 if extra.get("skip_compute", False):
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
637 return expose
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
638
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
639 try:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
640 compute_expose = app_data['_manager'].compute_expose
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
641 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
642 pass
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
643 else:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
644 await compute_expose(app_data)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
645
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
646 app_data['_exposed_computed'] = True
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
647 return expose
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
648
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
649 async def _do_prepare(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
650 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
651 app_data: dict,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
652 ) -> None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
653 name = app_data['name']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
654 dest_path = app_data['_instance_dir_path']
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
655 if next(dest_path.iterdir(), None) != None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
656 log.debug(f"There is already a prepared dir at {dest_path}, nothing to do")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
657 return
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
658 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
659 prepare = app_data['prepare'].copy()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
660 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
661 prepare = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
662
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
663 if not prepare:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
664 log.debug(f"Nothing to prepare for {name!r}")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
665 return
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
666
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
667 for action, value in list(prepare.items()):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
668 log.debug(f"[{name}] [prepare] running {action!r} action")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
669 if action == "git":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
670 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
671 git_path = which('git')[0]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
672 except IndexError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
673 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
674 "Can't find \"git\" executable, {name} can't be started without it"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
675 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
676 await async_process.run(git_path, "clone", value, str(dest_path))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
677 log.debug(f"{value!r} git repository cloned at {dest_path}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
678 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
679 raise NotImplementedError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
680 f"{action!r} is not managed, can't start {name}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
681 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
682 del prepare[action]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
683
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
684 if prepare:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
685 raise exceptions.InternalError('"prepare" should be empty')
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
686
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
687 async def _do_create_files(
3565
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
688 self,
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
689 app_data: dict,
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
690 ) -> None:
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
691 dest_path = app_data['_instance_dir_path']
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
692 files = app_data.get('files')
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
693 if not files:
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
694 return
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
695 if not isinstance(files, dict):
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
696 raise ValueError('"files" must be a dictionary')
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
697 for filename, data in files.items():
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
698 path = dest_path / filename
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
699 if path.is_file():
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
700 log.info(f"{path} already exists, skipping")
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
701 with path.open("w") as f:
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
702 f.write(data.get("content", ""))
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
703 log.debug(f"{path} created")
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
704
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
705 async def start_common(self, app_data: dict) -> None:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
706 """Method running common action when starting a manager
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
707
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
708 It should be called by managers in "start" method.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
709 """
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
710 await self._do_prepare(app_data)
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
711 await self._do_create_files(app_data)