annotate libervia/backend/plugins/plugin_misc_app_manager/__init__.py @ 4281:9e63e02318ec

core: show warning instead of exception in case of missing dependency when loading plugins
author Goffi <goffi@goffi.org>
date Fri, 12 Jul 2024 18:53:00 +0200
parents 0d7bb4df2343
children
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(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
48 "Missing module PyYAML, please download/install it. You can use "
3372
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 PLUGIN_INFO = {
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 C.PI_NAME: "Applications Manager",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 C.PI_IMPORT_NAME: "APP_MANAGER",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 C.PI_TYPE: C.PLUG_TYPE_MISC,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 C.PI_MODES: C.PLUG_MODE_BOTH,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 C.PI_MAIN: "AppManager",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 C.PI_HANDLER: "no",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 C.PI_DESCRIPTION: _(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 """Applications Manager
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 Manage external applications using packagers, OS virtualization/containers or other
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 software management tools.
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
74 """
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
75 ),
3372
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
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
78 APP_FILE_PREFIX = "libervia_app_"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79
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 class AppManager:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 load = partial(yaml.load, Loader=Loader)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 dump = partial(yaml.dump, Dumper=Dumper)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 def __init__(self, host):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 log.info(_("plugin Applications Manager initialization"))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 self.host = host
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 self._managers = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 self._apps = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 self._started = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 # instance id to app data map
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 self._instances = {}
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
93
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
94 self.persistent_data = persistent.LazyPersistentBinaryDict("app_manager")
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
95
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
96 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
97 "applications_list",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 in_sign="as",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 out_sign="as",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 method=self.list_applications,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
103 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
104 "application_start",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 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
107 out_sign="s",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 method=self._start,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
111 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
112 "application_stop",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 in_sign="sss",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 out_sign="",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 method=self._stop,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
119 host.bridge.add_method(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
120 "application_exposed_get",
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 ".plugin",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 in_sign="sss",
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 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
124 method=self._get_exposed,
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 async_=True,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 )
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
127 # 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
128 # args: name, instance_id, extra
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
129 host.bridge.add_signal("application_started", ".plugin", signature="sss")
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
130 # 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
131 # args: name, instance_id, extra
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
132 host.bridge.add_signal("application_error", ".plugin", signature="sss")
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
133 yaml.add_constructor("!libervia_conf", self._libervia_conf_constr, Loader=Loader)
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
134 yaml.add_constructor(
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
135 "!libervia_generate_pwd", self._libervia_generate_pwd_constr, Loader=Loader
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
136 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 yaml.add_constructor(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
138 "!libervia_param", self._libervia_param_constr, Loader=Loader
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
139 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
140
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 def unload(self):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 log.debug("unloading applications manager")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 for instances in self._started.values():
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 for instance in instances:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
145 data = instance["data"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
146 if not data["single_instance"]:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 log.debug(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
148 f"cleaning temporary directory at {data['_instance_dir_path']}"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
149 )
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
150 data["_instance_dir_obj"].cleanup()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
151
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
152 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
153 """Get a value from Libervia configuration
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
154
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 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
156 those parameters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 - section
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 - name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 - default value
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 - filter
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 filter can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 - "first": get the first item of the value
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
163 - "not": get the opposite value (to be used with booleans)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 config_data = loader.construct_sequence(node)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 if len(config_data) == 1:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 section, name, default, filter_ = "", config_data[0], None, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 if len(config_data) == 2:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 (section, name), default, filter_ = config_data, None, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 elif len(config_data) == 3:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 (section, name, default), filter_ = config_data, None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 elif len(config_data) == 4:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 section, name, default, filter_ = config_data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 raise ValueError(
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
176 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
177 "is expected"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
179
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
180 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
181 # FIXME: "public_url" is used only here and doesn't take multi-sites into account
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
182 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
183 if not value:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
184 log.warning(
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
185 _(
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
186 'No value found for "public_url", using "example.org" for '
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
187 "now, please set the proper value in libervia.conf"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
188 )
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
189 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 else:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
191 log.warning(
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
192 _(
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
193 'invalid value for "public_url" ({value}), it musts not start with '
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
194 'schema ("http"), ignoring it and using "example.org" '
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
195 "instead"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
196 ).format(value=value)
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
197 )
3564
2c9e95796371 plugin app manager: "public_url" must NOT have a schema
Goffi <goffi@goffi.org>
parents: 3479
diff changeset
198 value = "example.org"
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
199
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 if filter_ is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 pass
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
202 elif filter_ == "first":
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 value = value[0]
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
204 elif filter_ == "not":
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
205 value = C.bool(value)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
206 value = C.bool_const(not value).lower()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 raise ValueError(f"unmanaged filter: {filter_}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
209
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 return value
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
211
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
212 def _libervia_generate_pwd_constr(self, loader, node) -> str:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
213 """Generate a password and store it in persistent data.
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
214
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
215 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
216 Mapping arguments are:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
217 ``name`` (str) **required**
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
218 Name of the password. Will be used to store it.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
219 ``size`` (int)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
220 Size of the password to generate. Default to 30
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
221 """
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
222 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
223 kwargs = loader.construct_mapping(node)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
224 name = kwargs["name"]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
225 except (ConstructorError, KeyError):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
226 raise ValueError(
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
227 '!libervia_generate_pwd map arguments is missing. At least "name" '
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
228 "must be specified."
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
229 )
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
230 pwd_data_key = f"pwd_{name}"
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
231 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
232 key = self._app_persistent_data[pwd_data_key]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
233 except KeyError:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
234 alphabet = string.ascii_letters + string.digits
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
235 key_size = int(kwargs.get("size", 30))
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
236 key = "".join(secrets.choice(alphabet) for __ in range(key_size))
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
237 self._app_persistent_data[pwd_data_key] = key
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
238 else:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
239 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
240 return key
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
241
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
242 def _libervia_param_constr(self, loader, node) -> str:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 """Get a parameter specified when starting the application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
244
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 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
246 [name, default_value]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 name, default = loader.construct_sequence(node)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 except ConstructorError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
251 name, default = loader.construct_scalar(node), None
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
252 assert self._params is not None
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
253 return self._params.get(name, default)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
254
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 def register(self, manager):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
256 name = manager.name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
257 if name in self._managers:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
258 raise exceptions.ConflictError(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
259 f"There is already a manager with the name {name}"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
260 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 self._managers[manager.name] = manager
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
262 if manager.discover_path is not None:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
263 self.discover(manager.discover_path, manager)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
264
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
265 def get_manager(self, app_data: dict) -> AppManagerBackend:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
266 """Get manager instance needed for this app
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
267
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
268 @raise exceptions.DataError: something is wrong with the type
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
269 @raise exceptions.NotFound: manager is not registered
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
270 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
271 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
272 app_type = app_data["type"]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
273 except KeyError:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
274 raise exceptions.DataError('app file doesn\'t have the mandatory "type" key')
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
275 if not isinstance(app_type, str):
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
276 raise exceptions.DataError(f"invalid app data type: {app_type!r}")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 app_type = app_type.strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
279 return self._managers[app_type]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 raise exceptions.NotFound(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
282 f"No manager found to manage app of type {app_type!r}"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
283 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
284
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
285 def get_app_data(self, id_type: Optional[str], identifier: str) -> dict:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
286 """Retrieve instance's app_data from identifier
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
287
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
288 @param id_type: type of the identifier, can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 - "name": identifier is a canonical application name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 the first found instance of this application is returned
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
291 - "instance": identifier is an instance id
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
292 @param identifier: identifier according to id_type
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
293 @return: instance application data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
294 @raise exceptions.NotFound: no instance with this id can be found
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
295 @raise ValueError: id_type is invalid
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
296 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 if not id_type:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
298 id_type = "name"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
299 if id_type == "name":
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
300 identifier = identifier.lower().strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
301 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
302 return next(iter(self._started[identifier]))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
303 except (KeyError, StopIteration):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
304 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
305 f"No instance of {identifier!r} is currently running"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
306 )
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
307 elif id_type == "instance":
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
308 instance_id = identifier
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
309 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
310 return self._instances[instance_id]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
311 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
312 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
313 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
314 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
315 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
316 raise ValueError(f"invalid id_type: {id_type!r}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
317
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
318 def discover(self, dir_path: Path, manager: AppManagerBackend | None = None) -> None:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
319 """Search for app configuration file.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
320
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
321 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
322 extension.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
323 """
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
324 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
325 if manager is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
326 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
327 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
328 manager = self.get_manager(app_data)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
329 except (exceptions.DataError, exceptions.NotFound) as e:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
330 log.warning(f"Can't parse {file_path}, skipping: {e}")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
331 continue
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
332 app_name = file_path.stem[len(APP_FILE_PREFIX) :].strip().lower()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
333 if not app_name:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
334 log.warning(f"invalid app file name at {file_path}")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
335 continue
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
336 app_dict = self._apps.setdefault(app_name, {})
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
337 manager_set = app_dict.setdefault(manager, set())
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
338 manager_set.add(file_path)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
339 log.debug(f"{app_name!r} {manager.name} application found")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
340
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
341 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
342 """Parse Libervia application file
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
343
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
344 @param params: parameters for running this instance
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
345 @raise exceptions.DataError: something is wrong in the file
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
346 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
347 if params is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
348 params = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
349 with file_path.open() as f:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
350 # we set parameters to be used only with this instance
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
351 # no async method must used between this assignation and `load`
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
352 self._params = params
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
353 app_data = self.load(f)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
354 self._params = None
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
355 if "name" not in app_data:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
356 # 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
357 # uppercase may be set on purpose
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
358 app_data["name"] = file_path.stem[len(APP_FILE_PREFIX) :].strip()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
359 single_instance = app_data.setdefault("single_instance", True)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
360 if not isinstance(single_instance, bool):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
361 raise ValueError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
362 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
363 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
364 return app_data
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
365
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
366 def list_applications(self, filters: Optional[List[str]]) -> List[str]:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
367 """List available application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
368
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
369 @param filters: only show applications matching those filters.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
370 using None will list all known applications
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
371 a filter can be:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
372 - available: applications available locally
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
373 - running: only show launched applications
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
374 """
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
375 if not filters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
376 return list(self.apps)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
377 found = set()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
378 for filter_ in filters:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
379 if filter_ == "available":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
380 found.update(self._apps)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
381 elif filter_ == "running":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
382 found.update(self._started)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
383 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
384 raise ValueError(f"Unknown filter: {filter_}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
385 return list(found)
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 def _start(self, app_name, extra):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
388 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
389 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
390 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
391 return d
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
392
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
393 async def start(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
394 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
395 app_name: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
396 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
397 ) -> dict:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
398 """Start an application
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
399
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
400 @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
401 @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
402 @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
403 - 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
404 - 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
405 - 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
406 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
407 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
408 - 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
409 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
410 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
411 [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
412 """
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
413 # 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
414 # 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
415 # to be defined in app_data allows explicitly it.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
416 app_name = app_name.lower().strip()
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
417 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
418 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
419 except KeyError:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
420 raise exceptions.NotFound(f"No application found with the name {app_name!r}")
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
421 log.info(f"starting {app_name!r}")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
422 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
423 self._app_persistent_data["last_started"] = time.time()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
424 started_data = self._started.setdefault(app_name, [])
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
425 app_data = self.parse(app_file_path, extra)
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
426 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
427 app_data["_started"] = False
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
428 app_data["_file_path"] = app_file_path
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
429 app_data["_name_canonical"] = app_name
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
430 single_instance = app_data["single_instance"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
431 ret_data = {"name": app_name, "started": False}
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
432 if single_instance:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
433 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
434 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
435 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
436 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
437 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
438 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
439 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
440 )
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
441 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
442 return ret_data
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
443 else:
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3998
diff changeset
444 cache_path = self.host.memory.get_cache_path(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
445 PLUGIN_INFO[C.PI_IMPORT_NAME], app_name
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
446 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
447 cache_path.mkdir(0o700, parents=True, exist_ok=True)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
448 app_data["_instance_dir_path"] = cache_path
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
449 else:
4085
c93b02000ae4 plugin app manager: rename `sat` to `libervia`
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
450 dest_dir_obj = tempfile.TemporaryDirectory(prefix="libervia_app_")
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
451 app_data["_instance_dir_obj"] = dest_dir_obj
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
452 app_data["_instance_dir_path"] = Path(dest_dir_obj.name)
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
453 instance_id = ret_data["instance"] = app_data["_instance_id"] = shortuuid.uuid()
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
454 manager = self.get_manager(app_data)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
455 app_data["_manager"] = manager
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
456 started_data.append(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
457 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
458 # 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
459 # 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
460 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
461 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
462 )
3372
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 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
465 start = manager.start
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
466 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
467 raise exceptions.InternalError(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
468 f'{manager.name} doesn\'t have the mandatory "start" method'
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
469 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
470 else:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
471 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
472 return ret_data
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
473
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
474 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
475 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
476 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
477 try:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
478 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
479 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
480 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
481 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
482 app_name,
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
483 instance_id,
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
484 data_format.serialise({"class": str(type(e)), "msg": str(e)}),
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
485 )
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
486 else:
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
487 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
488 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
489 log.info(f"{app_name!r} started")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
490
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
491 def _stop(self, identifier, id_type, extra):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
492 extra = data_format.deserialise(extra)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
493 return defer.ensureDeferred(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
494 self.stop(str(identifier), str(id_type) or None, extra)
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
495 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
496
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
497 async def stop(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
498 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
499 identifier: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
500 id_type: Optional[str] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
501 extra: Optional[dict] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
502 ) -> None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
503 if extra is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
504 extra = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
505
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
506 app_data = self.get_app_data(id_type, identifier)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
507
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
508 log.info(f"stopping {app_data['name']!r}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
509
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
510 app_name = app_data["_name_canonical"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
511 instance_id = app_data["_instance_id"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
512 manager = app_data["_manager"]
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
513
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
514 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
515 stop = manager.stop
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
516 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
517 raise exceptions.InternalError(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
518 f'{manager.name} doesn\'t have the mandatory "stop" method'
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
519 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
520 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
521 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
522 await stop(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
523 except Exception as e:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
524 log.warning(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
525 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
526 f"properly: {e}"
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 return
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 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
531 del self._instances[instance_id]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
532 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
533 log.error(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
534 f"INTERNAL ERROR: {instance_id!r} is not present in self._instances"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
535 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
536
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
537 try:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
538 self._started[app_name].remove(app_data)
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
539 except ValueError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
540 log.error(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
541 "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
542 f"{instance_id!r}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
543 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
544
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
545 log.info(f"{app_name!r} stopped")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
546
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
547 def _get_exposed(self, identifier, id_type, extra):
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
548 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
549 d = defer.ensureDeferred(self.get_exposed(identifier, id_type, extra))
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
550 d.addCallback(lambda d: data_format.serialise(d))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
551 return d
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
552
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
553 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
554 """Return a value from app data from its path.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
555
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
556 @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
557 @return: requested value
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
558 @raise KeyError: Can't find the requested value.
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
559 """
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
560 return reduce(lambda l, k: l[k], path, data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
561
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
562 async def get_exposed(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
563 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
564 identifier: str,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
565 id_type: Optional[str] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
566 extra: Optional[dict] = None,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
567 ) -> dict:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
568 """Get data exposed by the application
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
569
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
570 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
571 to handle manager specific conventions.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
572 """
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
573 app_data = self.get_app_data(id_type, identifier)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
574 if app_data.get("_exposed_computed", False):
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
575 return app_data["expose"]
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
576 if extra is None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
577 extra = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
578 expose = app_data.setdefault("expose", {})
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
579 if "passwords" in expose:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
580 passwords = expose["passwords"]
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
581 for name, value in list(passwords.items()):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
582 if isinstance(value, list):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
583 # 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
584 # to expose.
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
585 try:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
586 passwords[name] = self.get_app_data_value(value, app_data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
587 except KeyError:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
588 log.warning(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
589 f"Can't retrieve exposed value for password {name!r}: {e}"
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
590 )
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
591 del passwords[name]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
592
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
593 for key in ("url_prefix", "front_url"):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
594 value = expose.get(key)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
595 if isinstance(value, list):
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
596 try:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
597 expose[key] = self.get_app_data_value(value, app_data)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
598 except KeyError:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
599 log.warning(f"Can't retrieve exposed value for {key!r} at {value}")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
600 del expose[key]
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
601
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
602 front_url = expose.get("front_url")
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
603 if front_url:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
604 # 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
605 parsed_url = urlparse(front_url)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
606 if not parsed_url.scheme:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
607 if not parsed_url.netloc:
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
608 path_elt = parsed_url.path.split("/", 1)
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
609 parsed_url = parsed_url._replace(
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
610 netloc=path_elt[0],
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
611 path=f"/{path_elt[1]}" if len(path_elt) > 1 else "",
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
612 )
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
613 parsed_url = parsed_url._replace(scheme="https")
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
614 expose["front_url"] = urlunparse(parsed_url)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
615
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
616 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
617 return expose
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
618
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
619 try:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
620 compute_expose = app_data["_manager"].compute_expose
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
621 except AttributeError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
622 pass
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
623 else:
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
624 await compute_expose(app_data)
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
625
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
626 app_data["_exposed_computed"] = True
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
627 return expose
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
628
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
629 async def _do_prepare(
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
630 self,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
631 app_data: dict,
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
632 ) -> None:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
633 name = app_data["name"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
634 dest_path = app_data["_instance_dir_path"]
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
635 if next(dest_path.iterdir(), None) != None:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
636 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
637 return
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
638 try:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
639 prepare = app_data["prepare"].copy()
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
640 except KeyError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
641 prepare = {}
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
642
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
643 if not prepare:
4247
4aa62767f501 plugin app manager: various improvements:
Goffi <goffi@goffi.org>
parents: 4085
diff changeset
644 log.debug(f"Nothing to prepare for {name!r}")
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
645 return
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
646
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
647 for action, value in list(prepare.items()):
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
648 log.debug(f"[{name}] [prepare] running {action!r} action")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
649 if action == "git":
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
650 try:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
651 git_path = which("git")[0]
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
652 except IndexError:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
653 raise exceptions.NotFound(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
654 "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
655 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
656 await async_process.run(git_path, "clone", value, str(dest_path))
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
657 log.debug(f"{value!r} git repository cloned at {dest_path}")
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
658 else:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
659 raise NotImplementedError(
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
660 f"{action!r} is not managed, can't start {name}"
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
661 )
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
662 del prepare[action]
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
663
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
664 if prepare:
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
665 raise exceptions.InternalError('"prepare" should be empty')
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
666
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
667 async def _do_create_files(
3565
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
668 self,
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
669 app_data: dict,
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
670 ) -> None:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
671 dest_path = app_data["_instance_dir_path"]
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4247
diff changeset
672 files = app_data.get("files")
3565
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
673 if not files:
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
674 return
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
675 if not isinstance(files, dict):
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
676 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
677 for filename, data in files.items():
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
678 path = dest_path / filename
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
679 if path.is_file():
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
680 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
681 with path.open("w") as f:
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
682 f.write(data.get("content", ""))
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
683 log.debug(f"{path} created")
d66a8453b02b plugin app manager: add a way to create files:
Goffi <goffi@goffi.org>
parents: 3564
diff changeset
684
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
685 async def start_common(self, app_data: dict) -> None:
3372
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
686 """Method running common action when starting a manager
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
687
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
688 It should be called by managers in "start" method.
5d926c7b0d99 plugin app manager: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
689 """
3998
402d31527af4 plugin app manager: `start` doesn't wait anymore for actual app start:
Goffi <goffi@goffi.org>
parents: 3565
diff changeset
690 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
691 await self._do_create_files(app_data)