ominfra 0.0.0.dev189__py3-none-any.whl → 0.0.0.dev190__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ominfra/__about__.py +1 -0
- ominfra/manage/deploy/apps.py +42 -90
- ominfra/manage/deploy/commands.py +1 -1
- ominfra/manage/deploy/conf/manager.py +20 -12
- ominfra/manage/deploy/conf/specs.py +9 -0
- ominfra/manage/deploy/deploy.py +207 -2
- ominfra/manage/deploy/inject.py +4 -6
- ominfra/manage/deploy/nginx.py +8 -0
- ominfra/manage/deploy/paths/paths.py +5 -1
- ominfra/manage/deploy/specs.py +12 -1
- ominfra/manage/deploy/systemd.py +110 -0
- ominfra/manage/deploy/venvs.py +0 -2
- ominfra/scripts/manage.py +489 -152
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/METADATA +4 -3
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/RECORD +19 -18
- ominfra/manage/deploy/driver.py +0 -62
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev190.dist-info}/top_level.txt +0 -0
ominfra/__about__.py
CHANGED
ominfra/manage/deploy/apps.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
2
3
|
import os.path
|
3
4
|
import typing as ta
|
4
5
|
|
5
6
|
from omlish.lite.cached import cached_nullary
|
6
7
|
from omlish.lite.check import check
|
7
|
-
from omlish.
|
8
|
+
from omlish.lite.json import json_dumps_pretty
|
9
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
8
10
|
|
9
11
|
from .conf.manager import DeployConfManager
|
10
12
|
from .git import DeployGitManager
|
@@ -20,39 +22,31 @@ class DeployAppManager(DeployPathOwner):
|
|
20
22
|
def __init__(
|
21
23
|
self,
|
22
24
|
*,
|
23
|
-
conf: DeployConfManager,
|
24
25
|
git: DeployGitManager,
|
25
26
|
venvs: DeployVenvManager,
|
27
|
+
conf: DeployConfManager,
|
28
|
+
|
29
|
+
msh: ObjMarshalerManager,
|
26
30
|
) -> None:
|
27
31
|
super().__init__()
|
28
32
|
|
29
|
-
self._conf = conf
|
30
33
|
self._git = git
|
31
34
|
self._venvs = venvs
|
35
|
+
self._conf = conf
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
_APP_DIR_STR = 'apps/@app/@time--@app-rev--@app-key/'
|
36
|
-
_APP_DIR = DeployPath.parse(_APP_DIR_STR)
|
37
|
+
self._msh = msh
|
37
38
|
|
38
|
-
|
39
|
-
_DEPLOY_DIR = DeployPath.parse(_DEPLOY_DIR_STR)
|
39
|
+
#
|
40
40
|
|
41
|
-
|
42
|
-
_CONF_DEPLOY_DIR = DeployPath.parse(f'{_DEPLOY_DIR_STR}conf/@conf/')
|
41
|
+
APP_DIR = DeployPath.parse('apps/@app/@time--@app-rev--@app-key/')
|
43
42
|
|
44
43
|
@cached_nullary
|
45
44
|
def get_owned_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
|
46
45
|
return {
|
47
|
-
self.
|
48
|
-
|
49
|
-
self._DEPLOY_DIR,
|
50
|
-
|
51
|
-
self._APP_DEPLOY_LINK,
|
52
|
-
self._CONF_DEPLOY_DIR,
|
46
|
+
self.APP_DIR,
|
53
47
|
|
54
48
|
*[
|
55
|
-
DeployPath.parse(f'{self.
|
49
|
+
DeployPath.parse(f'{self.APP_DIR}{sfx}/')
|
56
50
|
for sfx in [
|
57
51
|
'conf',
|
58
52
|
'git',
|
@@ -63,115 +57,73 @@ class DeployAppManager(DeployPathOwner):
|
|
63
57
|
|
64
58
|
#
|
65
59
|
|
60
|
+
@dc.dataclass(frozen=True)
|
61
|
+
class PreparedApp:
|
62
|
+
app_dir: str
|
63
|
+
|
64
|
+
git_dir: ta.Optional[str] = None
|
65
|
+
venv_dir: ta.Optional[str] = None
|
66
|
+
conf_dir: ta.Optional[str] = None
|
67
|
+
|
66
68
|
async def prepare_app(
|
67
69
|
self,
|
68
70
|
spec: DeployAppSpec,
|
69
71
|
home: DeployHome,
|
70
72
|
tags: DeployTagMap,
|
71
|
-
) ->
|
72
|
-
|
73
|
-
|
74
|
-
def build_path(pth: DeployPath) -> str:
|
75
|
-
return os.path.join(home, pth.render(tags))
|
76
|
-
|
77
|
-
app_dir = build_path(self._APP_DIR)
|
78
|
-
deploy_dir = build_path(self._DEPLOY_DIR)
|
79
|
-
app_deploy_link = build_path(self._APP_DEPLOY_LINK)
|
73
|
+
) -> PreparedApp:
|
74
|
+
spec_json = json_dumps_pretty(self._msh.marshal_obj(spec))
|
80
75
|
|
81
76
|
#
|
82
77
|
|
83
|
-
|
84
|
-
|
85
|
-
deploying_link = os.path.join(home, 'deploys/deploying')
|
86
|
-
if os.path.exists(deploying_link):
|
87
|
-
os.unlink(deploying_link)
|
88
|
-
relative_symlink(
|
89
|
-
deploy_dir,
|
90
|
-
deploying_link,
|
91
|
-
target_is_directory=True,
|
92
|
-
make_dirs=True,
|
93
|
-
)
|
78
|
+
check.non_empty_str(home)
|
94
79
|
|
95
|
-
|
80
|
+
app_dir = os.path.join(home, self.APP_DIR.render(tags))
|
96
81
|
|
97
|
-
os.makedirs(app_dir)
|
98
|
-
relative_symlink(
|
99
|
-
app_dir,
|
100
|
-
app_deploy_link,
|
101
|
-
target_is_directory=True,
|
102
|
-
make_dirs=True,
|
103
|
-
)
|
82
|
+
os.makedirs(app_dir, exist_ok=True)
|
104
83
|
|
105
84
|
#
|
106
85
|
|
107
|
-
|
108
|
-
|
86
|
+
rkw: ta.Dict[str, ta.Any] = dict(
|
87
|
+
app_dir=app_dir,
|
88
|
+
)
|
109
89
|
|
110
90
|
#
|
111
91
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
# shutil.copy2(
|
116
|
-
# lp,
|
117
|
-
# os.path.join(dst, os.path.relpath(lp, src)),
|
118
|
-
# follow_symlinks=False,
|
119
|
-
# )
|
120
|
-
#
|
121
|
-
# for dp, dns, fns in os.walk(src, followlinks=False):
|
122
|
-
# for fn in fns:
|
123
|
-
# mirror_link(os.path.join(dp, fn))
|
124
|
-
#
|
125
|
-
# for dn in dns:
|
126
|
-
# dp2 = os.path.join(dp, dn)
|
127
|
-
# if os.path.islink(dp2):
|
128
|
-
# mirror_link(dp2)
|
129
|
-
# else:
|
130
|
-
# os.makedirs(os.path.join(dst, os.path.relpath(dp2, src)))
|
131
|
-
|
132
|
-
current_link = os.path.join(home, 'deploys/current')
|
133
|
-
|
134
|
-
# if os.path.exists(current_link):
|
135
|
-
# mirror_symlinks(
|
136
|
-
# os.path.join(current_link, 'conf'),
|
137
|
-
# conf_tag_dir,
|
138
|
-
# )
|
139
|
-
# mirror_symlinks(
|
140
|
-
# os.path.join(current_link, 'apps'),
|
141
|
-
# os.path.join(deploy_dir, 'apps'),
|
142
|
-
# )
|
92
|
+
spec_file = os.path.join(app_dir, 'spec.json')
|
93
|
+
with open(spec_file, 'w') as f: # noqa
|
94
|
+
f.write(spec_json)
|
143
95
|
|
144
96
|
#
|
145
97
|
|
146
|
-
|
98
|
+
git_dir = os.path.join(app_dir, 'git')
|
99
|
+
rkw.update(git_dir=git_dir)
|
147
100
|
await self._git.checkout(
|
148
101
|
spec.git,
|
149
102
|
home,
|
150
|
-
|
103
|
+
git_dir,
|
151
104
|
)
|
152
105
|
|
153
106
|
#
|
154
107
|
|
155
108
|
if spec.venv is not None:
|
156
|
-
|
109
|
+
venv_dir = os.path.join(app_dir, 'venv')
|
110
|
+
rkw.update(venv_dir=venv_dir)
|
157
111
|
await self._venvs.setup_venv(
|
158
112
|
spec.venv,
|
159
|
-
|
160
|
-
|
161
|
-
app_venv_dir,
|
113
|
+
git_dir,
|
114
|
+
venv_dir,
|
162
115
|
)
|
163
116
|
|
164
117
|
#
|
165
118
|
|
166
119
|
if spec.conf is not None:
|
167
|
-
|
120
|
+
conf_dir = os.path.join(app_dir, 'conf')
|
121
|
+
rkw.update(conf_dir=conf_dir)
|
168
122
|
await self._conf.write_app_conf(
|
169
123
|
spec.conf,
|
170
|
-
|
171
|
-
app_conf_dir,
|
172
|
-
deploy_conf_dir,
|
124
|
+
conf_dir,
|
173
125
|
)
|
174
126
|
|
175
127
|
#
|
176
128
|
|
177
|
-
|
129
|
+
return DeployAppManager.PreparedApp(**rkw)
|
@@ -24,6 +24,8 @@ from omlish.lite.json import json_dumps_pretty
|
|
24
24
|
from omlish.lite.strings import strip_with_newline
|
25
25
|
from omlish.os.paths import is_path_in_dir
|
26
26
|
from omlish.os.paths import relative_symlink
|
27
|
+
from omserv.nginx.configs import NginxConfigItems
|
28
|
+
from omserv.nginx.configs import render_nginx_config_str
|
27
29
|
|
28
30
|
from ....configs import render_ini_config
|
29
31
|
from ..paths.paths import DeployPath
|
@@ -37,6 +39,7 @@ from .specs import DeployAppConfLink
|
|
37
39
|
from .specs import DeployAppConfSpec
|
38
40
|
from .specs import IniDeployAppConfContent
|
39
41
|
from .specs import JsonDeployAppConfContent
|
42
|
+
from .specs import NginxDeployAppConfContent
|
40
43
|
from .specs import RawDeployAppConfContent
|
41
44
|
|
42
45
|
|
@@ -51,6 +54,10 @@ class DeployConfManager:
|
|
51
54
|
elif isinstance(ac, IniDeployAppConfContent):
|
52
55
|
return strip_with_newline(render_ini_config(ac.sections))
|
53
56
|
|
57
|
+
elif isinstance(ac, NginxDeployAppConfContent):
|
58
|
+
ni = NginxConfigItems.of(ac.items)
|
59
|
+
return strip_with_newline(render_nginx_config_str(ni))
|
60
|
+
|
54
61
|
else:
|
55
62
|
raise TypeError(ac)
|
56
63
|
|
@@ -69,6 +76,17 @@ class DeployConfManager:
|
|
69
76
|
with open(conf_file, 'w') as f: # noqa
|
70
77
|
f.write(body)
|
71
78
|
|
79
|
+
async def write_app_conf(
|
80
|
+
self,
|
81
|
+
spec: DeployAppConfSpec,
|
82
|
+
app_conf_dir: str,
|
83
|
+
) -> None:
|
84
|
+
for acf in spec.files or []:
|
85
|
+
await self._write_app_conf_file(
|
86
|
+
acf,
|
87
|
+
app_conf_dir,
|
88
|
+
)
|
89
|
+
|
72
90
|
#
|
73
91
|
|
74
92
|
class _ComputedConfLink(ta.NamedTuple):
|
@@ -178,23 +196,13 @@ class DeployConfManager:
|
|
178
196
|
make_dirs=True,
|
179
197
|
)
|
180
198
|
|
181
|
-
|
182
|
-
|
183
|
-
async def write_app_conf(
|
199
|
+
async def link_app_conf(
|
184
200
|
self,
|
185
201
|
spec: DeployAppConfSpec,
|
186
202
|
tags: DeployTagMap,
|
187
203
|
app_conf_dir: str,
|
188
204
|
conf_link_dir: str,
|
189
|
-
)
|
190
|
-
for acf in spec.files or []:
|
191
|
-
await self._write_app_conf_file(
|
192
|
-
acf,
|
193
|
-
app_conf_dir,
|
194
|
-
)
|
195
|
-
|
196
|
-
#
|
197
|
-
|
205
|
+
):
|
198
206
|
for link in spec.links or []:
|
199
207
|
await self._make_app_conf_link(
|
200
208
|
link,
|
@@ -44,6 +44,15 @@ class IniDeployAppConfContent(DeployAppConfContent):
|
|
44
44
|
sections: IniConfigSectionSettingsMap
|
45
45
|
|
46
46
|
|
47
|
+
#
|
48
|
+
|
49
|
+
|
50
|
+
@register_single_field_type_obj_marshaler('items')
|
51
|
+
@dc.dataclass(frozen=True)
|
52
|
+
class NginxDeployAppConfContent(DeployAppConfContent):
|
53
|
+
items: ta.Any
|
54
|
+
|
55
|
+
|
47
56
|
##
|
48
57
|
|
49
58
|
|
ominfra/manage/deploy/deploy.py
CHANGED
@@ -1,10 +1,31 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
import datetime
|
3
|
+
import os.path
|
3
4
|
import typing as ta
|
4
5
|
|
6
|
+
from omlish.lite.cached import cached_nullary
|
7
|
+
from omlish.lite.check import check
|
8
|
+
from omlish.lite.json import json_dumps_pretty
|
9
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
5
10
|
from omlish.lite.typing import Func0
|
11
|
+
from omlish.lite.typing import Func1
|
12
|
+
from omlish.os.paths import relative_symlink
|
6
13
|
|
14
|
+
from .apps import DeployAppManager
|
15
|
+
from .conf.manager import DeployConfManager
|
16
|
+
from .paths.manager import DeployPathsManager
|
17
|
+
from .paths.owners import DeployPathOwner
|
18
|
+
from .paths.paths import DeployPath
|
19
|
+
from .specs import DeployAppSpec
|
20
|
+
from .specs import DeploySpec
|
21
|
+
from .systemd import DeploySystemdManager
|
22
|
+
from .tags import DeployAppRev
|
23
|
+
from .tags import DeployTagMap
|
7
24
|
from .tags import DeployTime
|
25
|
+
from .types import DeployHome
|
26
|
+
|
27
|
+
|
28
|
+
##
|
8
29
|
|
9
30
|
|
10
31
|
DEPLOY_TAG_DATETIME_FMT = '%Y%m%dT%H%M%SZ'
|
@@ -13,17 +34,52 @@ DEPLOY_TAG_DATETIME_FMT = '%Y%m%dT%H%M%SZ'
|
|
13
34
|
DeployManagerUtcClock = ta.NewType('DeployManagerUtcClock', Func0[datetime.datetime])
|
14
35
|
|
15
36
|
|
16
|
-
class DeployManager:
|
37
|
+
class DeployManager(DeployPathOwner):
|
17
38
|
def __init__(
|
18
39
|
self,
|
19
40
|
*,
|
20
|
-
|
21
41
|
utc_clock: ta.Optional[DeployManagerUtcClock] = None,
|
22
42
|
):
|
23
43
|
super().__init__()
|
24
44
|
|
25
45
|
self._utc_clock = utc_clock
|
26
46
|
|
47
|
+
#
|
48
|
+
|
49
|
+
DEPLOYS_DIR = DeployPath.parse('deploys/')
|
50
|
+
|
51
|
+
CURRENT_DEPLOY_LINK = DeployPath.parse(f'{DEPLOYS_DIR}current')
|
52
|
+
DEPLOYING_DEPLOY_LINK = DeployPath.parse(f'{DEPLOYS_DIR}deploying')
|
53
|
+
|
54
|
+
DEPLOY_DIR = DeployPath.parse(f'{DEPLOYS_DIR}@time--@deploy-key/')
|
55
|
+
DEPLOY_SPEC_FILE = DeployPath.parse(f'{DEPLOY_DIR}spec.json')
|
56
|
+
|
57
|
+
APPS_DEPLOY_DIR = DeployPath.parse(f'{DEPLOY_DIR}apps/')
|
58
|
+
APP_DEPLOY_LINK = DeployPath.parse(f'{APPS_DEPLOY_DIR}@app')
|
59
|
+
|
60
|
+
CONFS_DEPLOY_DIR = DeployPath.parse(f'{DEPLOY_DIR}conf/')
|
61
|
+
CONF_DEPLOY_DIR = DeployPath.parse(f'{CONFS_DEPLOY_DIR}@conf/')
|
62
|
+
|
63
|
+
@cached_nullary
|
64
|
+
def get_owned_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
|
65
|
+
return {
|
66
|
+
self.DEPLOYS_DIR,
|
67
|
+
|
68
|
+
self.CURRENT_DEPLOY_LINK,
|
69
|
+
self.DEPLOYING_DEPLOY_LINK,
|
70
|
+
|
71
|
+
self.DEPLOY_DIR,
|
72
|
+
self.DEPLOY_SPEC_FILE,
|
73
|
+
|
74
|
+
self.APPS_DEPLOY_DIR,
|
75
|
+
self.APP_DEPLOY_LINK,
|
76
|
+
|
77
|
+
self.CONFS_DEPLOY_DIR,
|
78
|
+
self.CONF_DEPLOY_DIR,
|
79
|
+
}
|
80
|
+
|
81
|
+
#
|
82
|
+
|
27
83
|
def _utc_now(self) -> datetime.datetime:
|
28
84
|
if self._utc_clock is not None:
|
29
85
|
return self._utc_clock() # noqa
|
@@ -32,3 +88,152 @@ class DeployManager:
|
|
32
88
|
|
33
89
|
def make_deploy_time(self) -> DeployTime:
|
34
90
|
return DeployTime(self._utc_now().strftime(DEPLOY_TAG_DATETIME_FMT))
|
91
|
+
|
92
|
+
|
93
|
+
##
|
94
|
+
|
95
|
+
|
96
|
+
class DeployDriverFactory(Func1[DeploySpec, ta.ContextManager['DeployDriver']]):
|
97
|
+
pass
|
98
|
+
|
99
|
+
|
100
|
+
class DeployDriver:
|
101
|
+
def __init__(
|
102
|
+
self,
|
103
|
+
*,
|
104
|
+
spec: DeploySpec,
|
105
|
+
home: DeployHome,
|
106
|
+
time: DeployTime,
|
107
|
+
|
108
|
+
deploys: DeployManager,
|
109
|
+
paths: DeployPathsManager,
|
110
|
+
apps: DeployAppManager,
|
111
|
+
conf: DeployConfManager,
|
112
|
+
systemd: DeploySystemdManager,
|
113
|
+
|
114
|
+
msh: ObjMarshalerManager,
|
115
|
+
) -> None:
|
116
|
+
super().__init__()
|
117
|
+
|
118
|
+
self._spec = spec
|
119
|
+
self._home = home
|
120
|
+
self._time = time
|
121
|
+
|
122
|
+
self._deploys = deploys
|
123
|
+
self._paths = paths
|
124
|
+
self._apps = apps
|
125
|
+
self._conf = conf
|
126
|
+
self._systemd = systemd
|
127
|
+
|
128
|
+
self._msh = msh
|
129
|
+
|
130
|
+
#
|
131
|
+
|
132
|
+
@property
|
133
|
+
def deploy_tags(self) -> DeployTagMap:
|
134
|
+
return DeployTagMap(
|
135
|
+
self._time,
|
136
|
+
self._spec.key(),
|
137
|
+
)
|
138
|
+
|
139
|
+
def render_deploy_path(self, pth: DeployPath, tags: ta.Optional[DeployTagMap] = None) -> str:
|
140
|
+
return os.path.join(self._home, pth.render(tags if tags is not None else self.deploy_tags))
|
141
|
+
|
142
|
+
@property
|
143
|
+
def deploy_dir(self) -> str:
|
144
|
+
return self.render_deploy_path(self._deploys.DEPLOY_DIR)
|
145
|
+
|
146
|
+
#
|
147
|
+
|
148
|
+
async def drive_deploy(self) -> None:
|
149
|
+
spec_json = json_dumps_pretty(self._msh.marshal_obj(self._spec))
|
150
|
+
|
151
|
+
#
|
152
|
+
|
153
|
+
self._paths.validate_deploy_paths()
|
154
|
+
|
155
|
+
#
|
156
|
+
|
157
|
+
os.makedirs(self.deploy_dir)
|
158
|
+
|
159
|
+
#
|
160
|
+
|
161
|
+
spec_file = self.render_deploy_path(self._deploys.DEPLOY_SPEC_FILE)
|
162
|
+
with open(spec_file, 'w') as f: # noqa
|
163
|
+
f.write(spec_json)
|
164
|
+
|
165
|
+
#
|
166
|
+
|
167
|
+
deploying_link = self.render_deploy_path(self._deploys.DEPLOYING_DEPLOY_LINK)
|
168
|
+
if os.path.exists(deploying_link):
|
169
|
+
os.unlink(deploying_link)
|
170
|
+
relative_symlink(
|
171
|
+
self.deploy_dir,
|
172
|
+
deploying_link,
|
173
|
+
target_is_directory=True,
|
174
|
+
make_dirs=True,
|
175
|
+
)
|
176
|
+
|
177
|
+
#
|
178
|
+
|
179
|
+
for md in [
|
180
|
+
self._deploys.APPS_DEPLOY_DIR,
|
181
|
+
self._deploys.CONFS_DEPLOY_DIR,
|
182
|
+
]:
|
183
|
+
os.makedirs(self.render_deploy_path(md))
|
184
|
+
|
185
|
+
#
|
186
|
+
|
187
|
+
for app in self._spec.apps:
|
188
|
+
await self.drive_app_deploy(app)
|
189
|
+
|
190
|
+
#
|
191
|
+
|
192
|
+
current_link = self.render_deploy_path(self._deploys.CURRENT_DEPLOY_LINK)
|
193
|
+
os.replace(deploying_link, current_link)
|
194
|
+
|
195
|
+
#
|
196
|
+
|
197
|
+
await self._systemd.sync_systemd(
|
198
|
+
self._spec.systemd,
|
199
|
+
self._home,
|
200
|
+
os.path.join(self.deploy_dir, 'conf', 'systemd'), # FIXME
|
201
|
+
)
|
202
|
+
|
203
|
+
#
|
204
|
+
|
205
|
+
async def drive_app_deploy(self, app: DeployAppSpec) -> None:
|
206
|
+
app_tags = self.deploy_tags.add(
|
207
|
+
app.app,
|
208
|
+
app.key(),
|
209
|
+
DeployAppRev(app.git.rev),
|
210
|
+
)
|
211
|
+
|
212
|
+
#
|
213
|
+
|
214
|
+
da = await self._apps.prepare_app(
|
215
|
+
app,
|
216
|
+
self._home,
|
217
|
+
app_tags,
|
218
|
+
)
|
219
|
+
|
220
|
+
#
|
221
|
+
|
222
|
+
app_link = self.render_deploy_path(self._deploys.APP_DEPLOY_LINK, app_tags)
|
223
|
+
relative_symlink(
|
224
|
+
da.app_dir,
|
225
|
+
app_link,
|
226
|
+
target_is_directory=True,
|
227
|
+
make_dirs=True,
|
228
|
+
)
|
229
|
+
|
230
|
+
#
|
231
|
+
|
232
|
+
deploy_conf_dir = self.render_deploy_path(self._deploys.CONFS_DEPLOY_DIR)
|
233
|
+
if app.conf is not None:
|
234
|
+
await self._conf.link_app_conf(
|
235
|
+
app.conf,
|
236
|
+
app_tags,
|
237
|
+
check.non_empty_str(da.conf_dir),
|
238
|
+
deploy_conf_dir,
|
239
|
+
)
|
ominfra/manage/deploy/inject.py
CHANGED
@@ -16,15 +16,16 @@ from .commands import DeployCommand
|
|
16
16
|
from .commands import DeployCommandExecutor
|
17
17
|
from .conf.inject import bind_deploy_conf
|
18
18
|
from .config import DeployConfig
|
19
|
+
from .deploy import DeployDriver
|
20
|
+
from .deploy import DeployDriverFactory
|
19
21
|
from .deploy import DeployManager
|
20
|
-
from .driver import DeployDriver
|
21
|
-
from .driver import DeployDriverFactory
|
22
22
|
from .git import DeployGitManager
|
23
23
|
from .inject_ import bind_deploy_manager
|
24
24
|
from .interp import InterpCommand
|
25
25
|
from .interp import InterpCommandExecutor
|
26
26
|
from .paths.inject import bind_deploy_paths
|
27
27
|
from .specs import DeploySpec
|
28
|
+
from .systemd import DeploySystemdManager
|
28
29
|
from .tags import DeployTime
|
29
30
|
from .tmp import DeployHomeAtomics
|
30
31
|
from .tmp import DeployTmpManager
|
@@ -101,13 +102,10 @@ def bind_deploy(
|
|
101
102
|
|
102
103
|
lst.extend([
|
103
104
|
bind_deploy_manager(DeployAppManager),
|
104
|
-
|
105
105
|
bind_deploy_manager(DeployGitManager),
|
106
|
-
|
107
106
|
bind_deploy_manager(DeployManager),
|
108
|
-
|
107
|
+
bind_deploy_manager(DeploySystemdManager),
|
109
108
|
bind_deploy_manager(DeployTmpManager),
|
110
|
-
|
111
109
|
bind_deploy_manager(DeployVenvManager),
|
112
110
|
])
|
113
111
|
|
@@ -33,6 +33,10 @@ class DeployPathError(Exception):
|
|
33
33
|
|
34
34
|
|
35
35
|
class DeployPathRenderable(abc.ABC):
|
36
|
+
@cached_nullary
|
37
|
+
def __str__(self) -> str:
|
38
|
+
return self.render(None)
|
39
|
+
|
36
40
|
@abc.abstractmethod
|
37
41
|
def render(self, tags: ta.Optional[DeployTagMap] = None) -> str:
|
38
42
|
raise NotImplementedError
|
@@ -174,7 +178,7 @@ class FileDeployPathPart(DeployPathPart):
|
|
174
178
|
|
175
179
|
|
176
180
|
@dc.dataclass(frozen=True)
|
177
|
-
class DeployPath:
|
181
|
+
class DeployPath(DeployPathRenderable):
|
178
182
|
parts: ta.Sequence[DeployPathPart]
|
179
183
|
|
180
184
|
@property
|
ominfra/manage/deploy/specs.py
CHANGED
@@ -94,11 +94,22 @@ class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
|
|
94
94
|
##
|
95
95
|
|
96
96
|
|
97
|
+
@dc.dataclass(frozen=True)
|
98
|
+
class DeploySystemdSpec:
|
99
|
+
# ~/.config/systemd/user/
|
100
|
+
unit_dir: ta.Optional[str] = None
|
101
|
+
|
102
|
+
|
103
|
+
##
|
104
|
+
|
105
|
+
|
97
106
|
@dc.dataclass(frozen=True)
|
98
107
|
class DeploySpec(DeploySpecKeyed[DeployKey]):
|
99
108
|
home: DeployHome
|
100
109
|
|
101
|
-
apps: ta.Sequence[DeployAppSpec]
|
110
|
+
apps: ta.Sequence[DeployAppSpec] = ()
|
111
|
+
|
112
|
+
systemd: ta.Optional[DeploySystemdSpec] = None
|
102
113
|
|
103
114
|
def __post_init__(self) -> None:
|
104
115
|
check.non_empty_str(self.home)
|