ominfra 0.0.0.dev189__py3-none-any.whl → 0.0.0.dev191__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 +109 -88
- ominfra/manage/deploy/commands.py +1 -1
- ominfra/manage/deploy/conf/manager.py +82 -17
- ominfra/manage/deploy/conf/specs.py +9 -0
- ominfra/manage/deploy/deploy.py +294 -1
- 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 +21 -1
- ominfra/manage/deploy/systemd.py +131 -0
- ominfra/manage/deploy/tags.py +1 -1
- ominfra/manage/deploy/venvs.py +8 -6
- ominfra/scripts/manage.py +733 -160
- ominfra/systemd.py +49 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/METADATA +4 -3
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/RECORD +21 -19
- ominfra/manage/deploy/driver.py +0 -62
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev189.dist-info → ominfra-0.0.0.dev191.dist-info}/top_level.txt +0 -0
ominfra/__about__.py
CHANGED
ominfra/manage/deploy/apps.py
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
3
|
+
import json
|
2
4
|
import os.path
|
3
5
|
import typing as ta
|
4
6
|
|
5
7
|
from omlish.lite.cached import cached_nullary
|
6
8
|
from omlish.lite.check import check
|
7
|
-
from omlish.
|
9
|
+
from omlish.lite.json import json_dumps_pretty
|
10
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
8
11
|
|
9
12
|
from .conf.manager import DeployConfManager
|
10
13
|
from .git import DeployGitManager
|
11
14
|
from .paths.owners import DeployPathOwner
|
12
15
|
from .paths.paths import DeployPath
|
13
16
|
from .specs import DeployAppSpec
|
17
|
+
from .tags import DeployAppRev
|
14
18
|
from .tags import DeployTagMap
|
15
19
|
from .types import DeployHome
|
16
20
|
from .venvs import DeployVenvManager
|
@@ -20,39 +24,31 @@ class DeployAppManager(DeployPathOwner):
|
|
20
24
|
def __init__(
|
21
25
|
self,
|
22
26
|
*,
|
23
|
-
conf: DeployConfManager,
|
24
27
|
git: DeployGitManager,
|
25
28
|
venvs: DeployVenvManager,
|
29
|
+
conf: DeployConfManager,
|
30
|
+
|
31
|
+
msh: ObjMarshalerManager,
|
26
32
|
) -> None:
|
27
33
|
super().__init__()
|
28
34
|
|
29
|
-
self._conf = conf
|
30
35
|
self._git = git
|
31
36
|
self._venvs = venvs
|
37
|
+
self._conf = conf
|
32
38
|
|
33
|
-
|
34
|
-
|
35
|
-
_APP_DIR_STR = 'apps/@app/@time--@app-rev--@app-key/'
|
36
|
-
_APP_DIR = DeployPath.parse(_APP_DIR_STR)
|
39
|
+
self._msh = msh
|
37
40
|
|
38
|
-
|
39
|
-
_DEPLOY_DIR = DeployPath.parse(_DEPLOY_DIR_STR)
|
41
|
+
#
|
40
42
|
|
41
|
-
|
42
|
-
_CONF_DEPLOY_DIR = DeployPath.parse(f'{_DEPLOY_DIR_STR}conf/@conf/')
|
43
|
+
APP_DIR = DeployPath.parse('apps/@app/@time--@app-rev--@app-key/')
|
43
44
|
|
44
45
|
@cached_nullary
|
45
46
|
def get_owned_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
|
46
47
|
return {
|
47
|
-
self.
|
48
|
-
|
49
|
-
self._DEPLOY_DIR,
|
50
|
-
|
51
|
-
self._APP_DEPLOY_LINK,
|
52
|
-
self._CONF_DEPLOY_DIR,
|
48
|
+
self.APP_DIR,
|
53
49
|
|
54
50
|
*[
|
55
|
-
DeployPath.parse(f'{self.
|
51
|
+
DeployPath.parse(f'{self.APP_DIR}{sfx}/')
|
56
52
|
for sfx in [
|
57
53
|
'conf',
|
58
54
|
'git',
|
@@ -63,115 +59,140 @@ class DeployAppManager(DeployPathOwner):
|
|
63
59
|
|
64
60
|
#
|
65
61
|
|
62
|
+
def _make_tags(self, spec: DeployAppSpec) -> DeployTagMap:
|
63
|
+
return DeployTagMap(
|
64
|
+
spec.app,
|
65
|
+
spec.key(),
|
66
|
+
DeployAppRev(spec.git.rev),
|
67
|
+
)
|
68
|
+
|
69
|
+
#
|
70
|
+
|
71
|
+
@dc.dataclass(frozen=True)
|
72
|
+
class PreparedApp:
|
73
|
+
spec: DeployAppSpec
|
74
|
+
tags: DeployTagMap
|
75
|
+
|
76
|
+
dir: str
|
77
|
+
|
78
|
+
git_dir: ta.Optional[str] = None
|
79
|
+
venv_dir: ta.Optional[str] = None
|
80
|
+
conf_dir: ta.Optional[str] = None
|
81
|
+
|
66
82
|
async def prepare_app(
|
67
83
|
self,
|
68
84
|
spec: DeployAppSpec,
|
69
85
|
home: DeployHome,
|
70
86
|
tags: DeployTagMap,
|
71
|
-
) ->
|
72
|
-
|
87
|
+
) -> PreparedApp:
|
88
|
+
spec_json = json_dumps_pretty(self._msh.marshal_obj(spec))
|
73
89
|
|
74
|
-
|
75
|
-
return os.path.join(home, pth.render(tags))
|
90
|
+
#
|
76
91
|
|
77
|
-
|
78
|
-
deploy_dir = build_path(self._DEPLOY_DIR)
|
79
|
-
app_deploy_link = build_path(self._APP_DEPLOY_LINK)
|
92
|
+
app_tags = tags.add(*self._make_tags(spec))
|
80
93
|
|
81
94
|
#
|
82
95
|
|
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
|
-
)
|
96
|
+
check.non_empty_str(home)
|
94
97
|
|
95
|
-
|
98
|
+
app_dir = os.path.join(home, self.APP_DIR.render(app_tags))
|
96
99
|
|
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
|
-
)
|
100
|
+
os.makedirs(app_dir, exist_ok=True)
|
104
101
|
|
105
102
|
#
|
106
103
|
|
107
|
-
|
108
|
-
|
104
|
+
rkw: ta.Dict[str, ta.Any] = dict(
|
105
|
+
spec=spec,
|
106
|
+
tags=app_tags,
|
109
107
|
|
110
|
-
|
108
|
+
dir=app_dir,
|
109
|
+
)
|
111
110
|
|
112
|
-
# def mirror_symlinks(src: str, dst: str) -> None:
|
113
|
-
# def mirror_link(lp: str) -> None:
|
114
|
-
# check.state(os.path.islink(lp))
|
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
111
|
#
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
# )
|
112
|
+
|
113
|
+
spec_file = os.path.join(app_dir, 'spec.json')
|
114
|
+
with open(spec_file, 'w') as f: # noqa
|
115
|
+
f.write(spec_json)
|
143
116
|
|
144
117
|
#
|
145
118
|
|
146
|
-
|
119
|
+
git_dir = os.path.join(app_dir, 'git')
|
120
|
+
rkw.update(git_dir=git_dir)
|
147
121
|
await self._git.checkout(
|
148
122
|
spec.git,
|
149
123
|
home,
|
150
|
-
|
124
|
+
git_dir,
|
151
125
|
)
|
152
126
|
|
153
127
|
#
|
154
128
|
|
155
129
|
if spec.venv is not None:
|
156
|
-
|
130
|
+
venv_dir = os.path.join(app_dir, 'venv')
|
131
|
+
rkw.update(venv_dir=venv_dir)
|
157
132
|
await self._venvs.setup_venv(
|
158
133
|
spec.venv,
|
159
|
-
|
160
|
-
|
161
|
-
app_venv_dir,
|
134
|
+
git_dir,
|
135
|
+
venv_dir,
|
162
136
|
)
|
163
137
|
|
164
138
|
#
|
165
139
|
|
166
140
|
if spec.conf is not None:
|
167
|
-
|
141
|
+
conf_dir = os.path.join(app_dir, 'conf')
|
142
|
+
rkw.update(conf_dir=conf_dir)
|
168
143
|
await self._conf.write_app_conf(
|
169
144
|
spec.conf,
|
170
|
-
|
171
|
-
app_conf_dir,
|
172
|
-
deploy_conf_dir,
|
145
|
+
conf_dir,
|
173
146
|
)
|
174
147
|
|
175
148
|
#
|
176
149
|
|
177
|
-
|
150
|
+
return DeployAppManager.PreparedApp(**rkw)
|
151
|
+
|
152
|
+
async def prepare_app_link(
|
153
|
+
self,
|
154
|
+
tags: DeployTagMap,
|
155
|
+
app_dir: str,
|
156
|
+
) -> PreparedApp:
|
157
|
+
spec_file = os.path.join(app_dir, 'spec.json')
|
158
|
+
with open(spec_file) as f: # noqa
|
159
|
+
spec_json = f.read()
|
160
|
+
|
161
|
+
spec: DeployAppSpec = self._msh.unmarshal_obj(json.loads(spec_json), DeployAppSpec)
|
162
|
+
|
163
|
+
#
|
164
|
+
|
165
|
+
app_tags = tags.add(*self._make_tags(spec))
|
166
|
+
|
167
|
+
#
|
168
|
+
|
169
|
+
rkw: ta.Dict[str, ta.Any] = dict(
|
170
|
+
spec=spec,
|
171
|
+
tags=app_tags,
|
172
|
+
|
173
|
+
dir=app_dir,
|
174
|
+
)
|
175
|
+
|
176
|
+
#
|
177
|
+
|
178
|
+
git_dir = os.path.join(app_dir, 'git')
|
179
|
+
check.state(os.path.isdir(git_dir))
|
180
|
+
rkw.update(git_dir=git_dir)
|
181
|
+
|
182
|
+
#
|
183
|
+
|
184
|
+
if spec.venv is not None:
|
185
|
+
venv_dir = os.path.join(app_dir, 'venv')
|
186
|
+
check.state(os.path.isdir(venv_dir))
|
187
|
+
rkw.update(venv_dir=venv_dir)
|
188
|
+
|
189
|
+
#
|
190
|
+
|
191
|
+
if spec.conf is not None:
|
192
|
+
conf_dir = os.path.join(app_dir, 'conf')
|
193
|
+
check.state(os.path.isdir(conf_dir))
|
194
|
+
rkw.update(conf_dir=conf_dir)
|
195
|
+
|
196
|
+
#
|
197
|
+
|
198
|
+
return DeployAppManager.PreparedApp(**rkw)
|
@@ -16,6 +16,8 @@ TODO:
|
|
16
16
|
- some things (venvs) cannot be moved, thus the /deploy/venvs dir
|
17
17
|
- ** ensure (enforce) equivalent relpath nesting
|
18
18
|
"""
|
19
|
+
import collections.abc
|
20
|
+
import functools
|
19
21
|
import os.path
|
20
22
|
import typing as ta
|
21
23
|
|
@@ -24,6 +26,8 @@ from omlish.lite.json import json_dumps_pretty
|
|
24
26
|
from omlish.lite.strings import strip_with_newline
|
25
27
|
from omlish.os.paths import is_path_in_dir
|
26
28
|
from omlish.os.paths import relative_symlink
|
29
|
+
from omserv.nginx.configs import NginxConfigItems
|
30
|
+
from omserv.nginx.configs import render_nginx_config_str
|
27
31
|
|
28
32
|
from ....configs import render_ini_config
|
29
33
|
from ..paths.paths import DeployPath
|
@@ -37,19 +41,70 @@ from .specs import DeployAppConfLink
|
|
37
41
|
from .specs import DeployAppConfSpec
|
38
42
|
from .specs import IniDeployAppConfContent
|
39
43
|
from .specs import JsonDeployAppConfContent
|
44
|
+
from .specs import NginxDeployAppConfContent
|
40
45
|
from .specs import RawDeployAppConfContent
|
41
46
|
|
42
47
|
|
48
|
+
T = ta.TypeVar('T')
|
49
|
+
|
50
|
+
|
51
|
+
##
|
52
|
+
|
53
|
+
|
43
54
|
class DeployConfManager:
|
44
|
-
def
|
55
|
+
def _process_conf_content(
|
56
|
+
self,
|
57
|
+
content: T,
|
58
|
+
*,
|
59
|
+
str_processor: ta.Optional[ta.Callable[[str], str]] = None,
|
60
|
+
) -> T:
|
61
|
+
def rec(o):
|
62
|
+
if isinstance(o, str):
|
63
|
+
if str_processor is not None:
|
64
|
+
return type(o)(str_processor(o))
|
65
|
+
|
66
|
+
elif isinstance(o, collections.abc.Mapping):
|
67
|
+
return type(o)([ # type: ignore
|
68
|
+
(rec(k), rec(v))
|
69
|
+
for k, v in o.items()
|
70
|
+
])
|
71
|
+
|
72
|
+
elif isinstance(o, collections.abc.Iterable):
|
73
|
+
return type(o)([ # type: ignore
|
74
|
+
rec(e) for e in o
|
75
|
+
])
|
76
|
+
|
77
|
+
return o
|
78
|
+
|
79
|
+
return rec(content)
|
80
|
+
|
81
|
+
#
|
82
|
+
|
83
|
+
def _render_app_conf_content(
|
84
|
+
self,
|
85
|
+
ac: DeployAppConfContent,
|
86
|
+
*,
|
87
|
+
str_processor: ta.Optional[ta.Callable[[str], str]] = None,
|
88
|
+
) -> str:
|
89
|
+
pcc = functools.partial(
|
90
|
+
self._process_conf_content,
|
91
|
+
str_processor=str_processor,
|
92
|
+
)
|
93
|
+
|
45
94
|
if isinstance(ac, RawDeployAppConfContent):
|
46
|
-
return ac.body
|
95
|
+
return pcc(ac.body)
|
47
96
|
|
48
97
|
elif isinstance(ac, JsonDeployAppConfContent):
|
49
|
-
|
98
|
+
json_obj = pcc(ac.obj)
|
99
|
+
return strip_with_newline(json_dumps_pretty(json_obj))
|
50
100
|
|
51
101
|
elif isinstance(ac, IniDeployAppConfContent):
|
52
|
-
|
102
|
+
ini_sections = pcc(ac.sections)
|
103
|
+
return strip_with_newline(render_ini_config(ini_sections))
|
104
|
+
|
105
|
+
elif isinstance(ac, NginxDeployAppConfContent):
|
106
|
+
nginx_items = NginxConfigItems.of(pcc(ac.items))
|
107
|
+
return strip_with_newline(render_nginx_config_str(nginx_items))
|
53
108
|
|
54
109
|
else:
|
55
110
|
raise TypeError(ac)
|
@@ -58,17 +113,37 @@ class DeployConfManager:
|
|
58
113
|
self,
|
59
114
|
acf: DeployAppConfFile,
|
60
115
|
app_conf_dir: str,
|
116
|
+
*,
|
117
|
+
str_processor: ta.Optional[ta.Callable[[str], str]] = None,
|
61
118
|
) -> None:
|
62
119
|
conf_file = os.path.join(app_conf_dir, acf.path)
|
63
120
|
check.arg(is_path_in_dir(app_conf_dir, conf_file))
|
64
121
|
|
65
|
-
body = self._render_app_conf_content(
|
122
|
+
body = self._render_app_conf_content(
|
123
|
+
acf.content,
|
124
|
+
str_processor=str_processor,
|
125
|
+
)
|
66
126
|
|
67
127
|
os.makedirs(os.path.dirname(conf_file), exist_ok=True)
|
68
128
|
|
69
129
|
with open(conf_file, 'w') as f: # noqa
|
70
130
|
f.write(body)
|
71
131
|
|
132
|
+
async def write_app_conf(
|
133
|
+
self,
|
134
|
+
spec: DeployAppConfSpec,
|
135
|
+
app_conf_dir: str,
|
136
|
+
) -> None:
|
137
|
+
def process_str(s: str) -> str:
|
138
|
+
return s
|
139
|
+
|
140
|
+
for acf in spec.files or []:
|
141
|
+
await self._write_app_conf_file(
|
142
|
+
acf,
|
143
|
+
app_conf_dir,
|
144
|
+
str_processor=process_str,
|
145
|
+
)
|
146
|
+
|
72
147
|
#
|
73
148
|
|
74
149
|
class _ComputedConfLink(ta.NamedTuple):
|
@@ -178,23 +253,13 @@ class DeployConfManager:
|
|
178
253
|
make_dirs=True,
|
179
254
|
)
|
180
255
|
|
181
|
-
|
182
|
-
|
183
|
-
async def write_app_conf(
|
256
|
+
async def link_app_conf(
|
184
257
|
self,
|
185
258
|
spec: DeployAppConfSpec,
|
186
259
|
tags: DeployTagMap,
|
187
260
|
app_conf_dir: str,
|
188
261
|
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
|
-
|
262
|
+
):
|
198
263
|
for link in spec.links or []:
|
199
264
|
await self._make_app_conf_link(
|
200
265
|
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
|
|