ominfra 0.0.0.dev138__py3-none-any.whl → 0.0.0.dev139__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/manage/__init__.py +13 -0
- ominfra/manage/{new/main.py → main.py} +6 -6
- ominfra/{manage/new/_manage.py → scripts/manage.py} +13 -13
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/RECORD +12 -41
- ominfra/manage/deploy/_executor.py +0 -1415
- ominfra/manage/deploy/configs.py +0 -19
- ominfra/manage/deploy/executor/__init__.py +0 -1
- ominfra/manage/deploy/executor/base.py +0 -115
- ominfra/manage/deploy/executor/concerns/__init__.py +0 -0
- ominfra/manage/deploy/executor/concerns/dirs.py +0 -28
- ominfra/manage/deploy/executor/concerns/nginx.py +0 -47
- ominfra/manage/deploy/executor/concerns/repo.py +0 -17
- ominfra/manage/deploy/executor/concerns/supervisor.py +0 -46
- ominfra/manage/deploy/executor/concerns/systemd.py +0 -88
- ominfra/manage/deploy/executor/concerns/user.py +0 -25
- ominfra/manage/deploy/executor/concerns/venv.py +0 -22
- ominfra/manage/deploy/executor/main.py +0 -119
- ominfra/manage/deploy/poly/__init__.py +0 -1
- ominfra/manage/deploy/poly/_main.py +0 -975
- ominfra/manage/deploy/poly/base.py +0 -178
- ominfra/manage/deploy/poly/configs.py +0 -38
- ominfra/manage/deploy/poly/deploy.py +0 -25
- ominfra/manage/deploy/poly/main.py +0 -18
- ominfra/manage/deploy/poly/nginx.py +0 -60
- ominfra/manage/deploy/poly/repo.py +0 -41
- ominfra/manage/deploy/poly/runtime.py +0 -39
- ominfra/manage/deploy/poly/site.py +0 -11
- ominfra/manage/deploy/poly/supervisor.py +0 -64
- ominfra/manage/deploy/poly/venv.py +0 -52
- ominfra/manage/deploy/remote.py +0 -91
- ominfra/manage/manage.py +0 -12
- ominfra/manage/new/__init__.py +0 -1
- ominfra/manage/new/commands/__init__.py +0 -0
- /ominfra/manage/{deploy → commands}/__init__.py +0 -0
- /ominfra/manage/{new/commands → commands}/base.py +0 -0
- /ominfra/manage/{new/commands → commands}/subprocess.py +0 -0
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev139.dist-info}/top_level.txt +0 -0
ominfra/manage/deploy/configs.py
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
import dataclasses as dc
|
2
|
-
|
3
|
-
|
4
|
-
@dc.dataclass(frozen=True)
|
5
|
-
class DeployConfig:
|
6
|
-
python_bin: str
|
7
|
-
app_name: str
|
8
|
-
repo_url: str
|
9
|
-
revision: str
|
10
|
-
requirements_txt: str
|
11
|
-
entrypoint: str
|
12
|
-
|
13
|
-
|
14
|
-
@dc.dataclass(frozen=True)
|
15
|
-
class HostConfig:
|
16
|
-
username: str = 'deploy'
|
17
|
-
|
18
|
-
global_supervisor_conf_file_path: str = '/etc/supervisor/conf.d/supervisord.conf'
|
19
|
-
global_nginx_conf_file_path: str = '/etc/nginx/sites-enabled/deploy.conf'
|
@@ -1 +0,0 @@
|
|
1
|
-
# @omlish-lite
|
@@ -1,115 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP006
|
2
|
-
import abc
|
3
|
-
import dataclasses as dc
|
4
|
-
import enum
|
5
|
-
import os.path
|
6
|
-
import shlex
|
7
|
-
import typing as ta
|
8
|
-
|
9
|
-
from omlish.lite.cached import cached_nullary
|
10
|
-
from omlish.lite.logs import log
|
11
|
-
from omlish.lite.subprocesses import subprocess_check_call
|
12
|
-
|
13
|
-
from ..configs import DeployConfig
|
14
|
-
from ..configs import HostConfig
|
15
|
-
|
16
|
-
|
17
|
-
##
|
18
|
-
|
19
|
-
|
20
|
-
class Phase(enum.Enum):
|
21
|
-
HOST = enum.auto()
|
22
|
-
ENV = enum.auto()
|
23
|
-
BACKEND = enum.auto()
|
24
|
-
FRONTEND = enum.auto()
|
25
|
-
START_BACKEND = enum.auto()
|
26
|
-
START_FRONTEND = enum.auto()
|
27
|
-
|
28
|
-
|
29
|
-
def run_in_phase(*ps: Phase):
|
30
|
-
def inner(fn):
|
31
|
-
fn.__deployment_phases__ = ps
|
32
|
-
return fn
|
33
|
-
return inner
|
34
|
-
|
35
|
-
|
36
|
-
class Concern(abc.ABC):
|
37
|
-
def __init__(self, d: 'Deployment') -> None:
|
38
|
-
super().__init__()
|
39
|
-
self._d = d
|
40
|
-
|
41
|
-
_phase_fns: ta.ClassVar[ta.Mapping[Phase, ta.Sequence[ta.Callable]]]
|
42
|
-
|
43
|
-
def __init_subclass__(cls, **kwargs):
|
44
|
-
super().__init_subclass__(**kwargs)
|
45
|
-
dct: ta.Dict[Phase, ta.List[ta.Callable]] = {}
|
46
|
-
for fn, ps in [
|
47
|
-
(v, ps)
|
48
|
-
for a in dir(cls)
|
49
|
-
if not (a.startswith('__') and a.endswith('__'))
|
50
|
-
for v in [getattr(cls, a, None)]
|
51
|
-
for ps in [getattr(v, '__deployment_phases__', None)]
|
52
|
-
if ps
|
53
|
-
]:
|
54
|
-
dct.update({p: [*dct.get(p, []), fn] for p in ps})
|
55
|
-
cls._phase_fns = dct
|
56
|
-
|
57
|
-
@dc.dataclass(frozen=True)
|
58
|
-
class Output(abc.ABC):
|
59
|
-
path: str
|
60
|
-
is_file: bool
|
61
|
-
|
62
|
-
def outputs(self) -> ta.Sequence[Output]:
|
63
|
-
return ()
|
64
|
-
|
65
|
-
def run_phase(self, p: Phase) -> None:
|
66
|
-
for fn in self._phase_fns.get(p, ()):
|
67
|
-
fn.__get__(self, type(self))()
|
68
|
-
|
69
|
-
|
70
|
-
##
|
71
|
-
|
72
|
-
|
73
|
-
class Deployment:
|
74
|
-
|
75
|
-
def __init__(
|
76
|
-
self,
|
77
|
-
cfg: DeployConfig,
|
78
|
-
concern_cls_list: ta.List[ta.Type[Concern]],
|
79
|
-
host_cfg: HostConfig = HostConfig(),
|
80
|
-
) -> None:
|
81
|
-
super().__init__()
|
82
|
-
self._cfg = cfg
|
83
|
-
self._host_cfg = host_cfg
|
84
|
-
|
85
|
-
self._concerns: ta.List[Concern] = [cls(self) for cls in concern_cls_list]
|
86
|
-
|
87
|
-
@property
|
88
|
-
def cfg(self) -> DeployConfig:
|
89
|
-
return self._cfg
|
90
|
-
|
91
|
-
@property
|
92
|
-
def host_cfg(self) -> HostConfig:
|
93
|
-
return self._host_cfg
|
94
|
-
|
95
|
-
def sh(self, *ss: str) -> None:
|
96
|
-
s = ' && '.join(ss)
|
97
|
-
log.info('Executing: %s', s)
|
98
|
-
subprocess_check_call(s, shell=True)
|
99
|
-
|
100
|
-
def ush(self, *ss: str) -> None:
|
101
|
-
s = ' && '.join(ss)
|
102
|
-
self.sh(f'su - {self._host_cfg.username} -c {shlex.quote(s)}')
|
103
|
-
|
104
|
-
@cached_nullary
|
105
|
-
def home_dir(self) -> str:
|
106
|
-
return os.path.expanduser(f'~{self._host_cfg.username}')
|
107
|
-
|
108
|
-
@cached_nullary
|
109
|
-
def deploy(self) -> None:
|
110
|
-
for p in Phase:
|
111
|
-
log.info('Phase %s', p.name)
|
112
|
-
for c in self._concerns:
|
113
|
-
c.run_phase(p)
|
114
|
-
|
115
|
-
log.info('Shitty deploy complete!')
|
File without changes
|
@@ -1,28 +0,0 @@
|
|
1
|
-
import os.path
|
2
|
-
import pwd
|
3
|
-
|
4
|
-
from omlish.lite.logs import log
|
5
|
-
|
6
|
-
from ..base import Concern
|
7
|
-
from ..base import Phase
|
8
|
-
from ..base import run_in_phase
|
9
|
-
|
10
|
-
|
11
|
-
class DirsConcern(Concern):
|
12
|
-
@run_in_phase(Phase.HOST)
|
13
|
-
def create_dirs(self) -> None:
|
14
|
-
pwn = pwd.getpwnam(self._d.host_cfg.username)
|
15
|
-
|
16
|
-
for dn in [
|
17
|
-
'app',
|
18
|
-
'conf',
|
19
|
-
'conf/env',
|
20
|
-
'conf/nginx',
|
21
|
-
'conf/supervisor',
|
22
|
-
'venv',
|
23
|
-
]:
|
24
|
-
fp = os.path.join(self._d.home_dir(), dn)
|
25
|
-
if not os.path.exists(fp):
|
26
|
-
log.info('Creating directory: %s', fp)
|
27
|
-
os.mkdir(fp)
|
28
|
-
os.chown(fp, pwn.pw_uid, pwn.pw_gid)
|
@@ -1,47 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
TODO:
|
3
|
-
- https://stackoverflow.com/questions/3011067/restart-nginx-without-sudo
|
4
|
-
"""
|
5
|
-
import os.path
|
6
|
-
import textwrap
|
7
|
-
|
8
|
-
from omlish.lite.logs import log
|
9
|
-
|
10
|
-
from ..base import Concern
|
11
|
-
from ..base import Phase
|
12
|
-
from ..base import run_in_phase
|
13
|
-
|
14
|
-
|
15
|
-
class GlobalNginxConcern(Concern):
|
16
|
-
@run_in_phase(Phase.HOST)
|
17
|
-
def create_global_nginx_conf(self) -> None:
|
18
|
-
nginx_conf_dir = os.path.join(self._d.home_dir(), 'conf/nginx')
|
19
|
-
if not os.path.isfile(self._d.host_cfg.global_nginx_conf_file_path):
|
20
|
-
log.info('Writing global nginx conf at %s', self._d.host_cfg.global_nginx_conf_file_path)
|
21
|
-
with open(self._d.host_cfg.global_nginx_conf_file_path, 'w') as f:
|
22
|
-
f.write(f'include {nginx_conf_dir}/*.conf;\n')
|
23
|
-
|
24
|
-
|
25
|
-
class NginxConcern(Concern):
|
26
|
-
@run_in_phase(Phase.FRONTEND)
|
27
|
-
def create_nginx_conf(self) -> None:
|
28
|
-
nginx_conf = textwrap.dedent(f"""
|
29
|
-
server {{
|
30
|
-
listen 80;
|
31
|
-
location / {{
|
32
|
-
proxy_pass http://127.0.0.1:8000/;
|
33
|
-
}}
|
34
|
-
}}
|
35
|
-
""")
|
36
|
-
nginx_conf_file = os.path.join(self._d.home_dir(), f'conf/nginx/{self._d.cfg.app_name}.conf')
|
37
|
-
log.info('Writing nginx conf to %s', nginx_conf_file)
|
38
|
-
with open(nginx_conf_file, 'w') as f:
|
39
|
-
f.write(nginx_conf)
|
40
|
-
|
41
|
-
@run_in_phase(Phase.START_FRONTEND)
|
42
|
-
def poke_nginx(self) -> None:
|
43
|
-
log.info('Starting nginx')
|
44
|
-
self._d.sh('service nginx start')
|
45
|
-
|
46
|
-
log.info('Poking nginx')
|
47
|
-
self._d.sh('nginx -s reload')
|
@@ -1,17 +0,0 @@
|
|
1
|
-
from ..base import Concern
|
2
|
-
from ..base import Phase
|
3
|
-
from ..base import run_in_phase
|
4
|
-
|
5
|
-
|
6
|
-
class RepoConcern(Concern):
|
7
|
-
@run_in_phase(Phase.ENV)
|
8
|
-
def clone_repo(self) -> None:
|
9
|
-
clone_submodules = False
|
10
|
-
self._d.ush(
|
11
|
-
'cd ~/app',
|
12
|
-
f'git clone --depth 1 {self._d.cfg.repo_url} {self._d.cfg.app_name}',
|
13
|
-
*([
|
14
|
-
f'cd {self._d.cfg.app_name}',
|
15
|
-
'git submodule update --init',
|
16
|
-
] if clone_submodules else []),
|
17
|
-
)
|
@@ -1,46 +0,0 @@
|
|
1
|
-
import os.path
|
2
|
-
import textwrap
|
3
|
-
|
4
|
-
from omlish.lite.logs import log
|
5
|
-
|
6
|
-
from ..base import Concern
|
7
|
-
from ..base import Phase
|
8
|
-
from ..base import run_in_phase
|
9
|
-
|
10
|
-
|
11
|
-
class GlobalSupervisorConcern(Concern):
|
12
|
-
@run_in_phase(Phase.HOST)
|
13
|
-
def create_global_supervisor_conf(self) -> None:
|
14
|
-
sup_conf_dir = os.path.join(self._d.home_dir(), 'conf/supervisor')
|
15
|
-
with open(self._d.host_cfg.global_supervisor_conf_file_path) as f:
|
16
|
-
glo_sup_conf = f.read()
|
17
|
-
if sup_conf_dir not in glo_sup_conf:
|
18
|
-
log.info('Updating global supervisor conf at %s', self._d.host_cfg.global_supervisor_conf_file_path) # noqa
|
19
|
-
glo_sup_conf += textwrap.dedent(f"""
|
20
|
-
[include]
|
21
|
-
files = {self._d.home_dir()}/conf/supervisor/*.conf
|
22
|
-
""")
|
23
|
-
with open(self._d.host_cfg.global_supervisor_conf_file_path, 'w') as f:
|
24
|
-
f.write(glo_sup_conf)
|
25
|
-
|
26
|
-
|
27
|
-
class SupervisorConcern(Concern):
|
28
|
-
@run_in_phase(Phase.BACKEND)
|
29
|
-
def create_supervisor_conf(self) -> None:
|
30
|
-
sup_conf = textwrap.dedent(f"""
|
31
|
-
[program:{self._d.cfg.app_name}]
|
32
|
-
command={self._d.home_dir()}/venv/{self._d.cfg.app_name}/bin/python -m {self._d.cfg.entrypoint}
|
33
|
-
directory={self._d.home_dir()}/app/{self._d.cfg.app_name}
|
34
|
-
user={self._d.host_cfg.username}
|
35
|
-
autostart=true
|
36
|
-
autorestart=true
|
37
|
-
""")
|
38
|
-
sup_conf_file = os.path.join(self._d.home_dir(), f'conf/supervisor/{self._d.cfg.app_name}.conf')
|
39
|
-
log.info('Writing supervisor conf to %s', sup_conf_file)
|
40
|
-
with open(sup_conf_file, 'w') as f:
|
41
|
-
f.write(sup_conf)
|
42
|
-
|
43
|
-
@run_in_phase(Phase.START_BACKEND)
|
44
|
-
def poke_supervisor(self) -> None:
|
45
|
-
log.info('Poking supervisor')
|
46
|
-
self._d.sh('kill -HUP 1')
|
@@ -1,88 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
# https://serverfault.com/questions/617823/how-to-set-systemd-service-dependencies
|
3
|
-
PIDFile=/run/nginx.pid
|
4
|
-
ExecStartPre=/usr/sbin/nginx -t
|
5
|
-
ExecStart=/usr/sbin/nginx
|
6
|
-
ExecReload=/bin/kill -s HUP $MAINPID
|
7
|
-
ExecStop=/bin/kill -s QUIT $MAINPID
|
8
|
-
PrivateTmp=true
|
9
|
-
|
10
|
-
# https://gist.github.com/clemensg/7dd024169efe8ce6e7fa4a0b3caa3780
|
11
|
-
Type=forking
|
12
|
-
PIDFile=/var/run/nginx.pid
|
13
|
-
ExecStartPre=/usr/sbin/nginx -t
|
14
|
-
ExecStart=/usr/sbin/nginx
|
15
|
-
ExecReload=/usr/bin/kill -s HUP $MAINPID
|
16
|
-
ExecStop=/usr/bin/kill -s QUIT $MAINPID
|
17
|
-
# Hardening
|
18
|
-
InaccessiblePaths=/etc/gnupg /etc/shadow /etc/ssh
|
19
|
-
ProtectSystem=full
|
20
|
-
ProtectKernelTunables=yes
|
21
|
-
ProtectControlGroups=yes
|
22
|
-
SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io
|
23
|
-
MemoryDenyWriteExecute=yes
|
24
|
-
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
25
|
-
RestrictRealtime=yes
|
26
|
-
"""
|
27
|
-
import os.path
|
28
|
-
import textwrap
|
29
|
-
|
30
|
-
from omlish.lite.logs import log
|
31
|
-
|
32
|
-
from ..base import Concern
|
33
|
-
from ..base import Phase
|
34
|
-
from ..base import run_in_phase
|
35
|
-
|
36
|
-
|
37
|
-
class GlobalSystemdConcern(Concern):
|
38
|
-
@run_in_phase(Phase.HOST)
|
39
|
-
def enable_user_linger(self) -> None:
|
40
|
-
log.info('Enabling user linger')
|
41
|
-
self._d.sh(f'loginctl enable-linger {self._d.host_cfg.username}')
|
42
|
-
|
43
|
-
|
44
|
-
class SystemdConcern(Concern):
|
45
|
-
service_name: str
|
46
|
-
|
47
|
-
@run_in_phase(Phase.HOST)
|
48
|
-
def create_systemd_path(self) -> None:
|
49
|
-
sd_svc_dir = os.path.join(self._d.home_dir(), '.config/systemd/user')
|
50
|
-
if not os.path.exists(sd_svc_dir):
|
51
|
-
log.info('Creating directory: %s', sd_svc_dir)
|
52
|
-
os.makedirs(sd_svc_dir)
|
53
|
-
|
54
|
-
@run_in_phase(Phase.BACKEND)
|
55
|
-
def create_systemd_service(self) -> None:
|
56
|
-
sd_svc = textwrap.dedent(f"""
|
57
|
-
[Unit]
|
58
|
-
Description={self.service_name}
|
59
|
-
After= \
|
60
|
-
syslog.target \
|
61
|
-
network.target \
|
62
|
-
remote-fs.target \
|
63
|
-
nss-lookup.target \
|
64
|
-
network-online.target
|
65
|
-
|
66
|
-
[Service]
|
67
|
-
Type=simple
|
68
|
-
StandardOutput=journal
|
69
|
-
ExecStart={self._d.home_dir()}/venv/{self._d.cfg.app_name}/bin/python -m {self._d.cfg.entrypoint}
|
70
|
-
WorkingDirectory={self._d.home_dir()}/app/{self._d.cfg.app_name}
|
71
|
-
|
72
|
-
Restart=always
|
73
|
-
RestartSec=3
|
74
|
-
|
75
|
-
[Install]
|
76
|
-
WantedBy=multi-user.target
|
77
|
-
""")
|
78
|
-
sd_svc_file = os.path.join(self._d.home_dir(), f'.config/systemd/user/{self.service_name}.service')
|
79
|
-
log.info('Writing systemd service to %s', sd_svc_file)
|
80
|
-
with open(sd_svc_file, 'w') as f:
|
81
|
-
f.write(sd_svc)
|
82
|
-
|
83
|
-
@run_in_phase(Phase.START_BACKEND)
|
84
|
-
def poke_systemd(self) -> None:
|
85
|
-
log.info('Poking systemd')
|
86
|
-
self._d.sh('systemctl --user daemon-reload')
|
87
|
-
self._d.sh(f'systemctl --user enable {self.service_name}')
|
88
|
-
self._d.sh(f'systemctl --user restart {self.service_name}')
|
@@ -1,25 +0,0 @@
|
|
1
|
-
import pwd
|
2
|
-
|
3
|
-
from omlish.lite.logs import log
|
4
|
-
|
5
|
-
from ..base import Concern
|
6
|
-
from ..base import Phase
|
7
|
-
from ..base import run_in_phase
|
8
|
-
|
9
|
-
|
10
|
-
class UserConcern(Concern):
|
11
|
-
@run_in_phase(Phase.HOST)
|
12
|
-
def create_user(self) -> None:
|
13
|
-
try:
|
14
|
-
pwd.getpwnam(self._d.host_cfg.username)
|
15
|
-
except KeyError:
|
16
|
-
log.info('Creating user %s', self._d.host_cfg.username)
|
17
|
-
self._d.sh(' '.join([
|
18
|
-
'adduser',
|
19
|
-
'--system',
|
20
|
-
'--disabled-password',
|
21
|
-
'--group',
|
22
|
-
'--shell /bin/bash',
|
23
|
-
self._d.host_cfg.username,
|
24
|
-
]))
|
25
|
-
pwd.getpwnam(self._d.host_cfg.username)
|
@@ -1,22 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
TODO:
|
3
|
-
- use LinuxInterpResolver lol
|
4
|
-
"""
|
5
|
-
from ..base import Concern
|
6
|
-
from ..base import Phase
|
7
|
-
from ..base import run_in_phase
|
8
|
-
|
9
|
-
|
10
|
-
class VenvConcern(Concern):
|
11
|
-
@run_in_phase(Phase.ENV)
|
12
|
-
def setup_venv(self) -> None:
|
13
|
-
self._d.ush(
|
14
|
-
'cd ~/venv',
|
15
|
-
f'{self._d.cfg.python_bin} -mvenv {self._d.cfg.app_name}',
|
16
|
-
|
17
|
-
# https://stackoverflow.com/questions/77364550/attributeerror-module-pkgutil-has-no-attribute-impimporter-did-you-mean
|
18
|
-
f'{self._d.cfg.app_name}/bin/python -m ensurepip',
|
19
|
-
f'{self._d.cfg.app_name}/bin/python -mpip install --upgrade setuptools pip',
|
20
|
-
|
21
|
-
f'{self._d.cfg.app_name}/bin/python -mpip install -r ~deploy/app/{self._d.cfg.app_name}/{self._d.cfg.requirements_txt}', # noqa
|
22
|
-
)
|
@@ -1,119 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# @omlish-amalg ../_executor.py
|
3
|
-
r"""
|
4
|
-
TODO:
|
5
|
-
- flock
|
6
|
-
- interp.py
|
7
|
-
- systemd
|
8
|
-
|
9
|
-
deployment matrix
|
10
|
-
- os: ubuntu / amzn / generic
|
11
|
-
- arch: amd64 / arm64
|
12
|
-
- host: bare / docker
|
13
|
-
- init: supervisor-provided / supervisor-must-configure / systemd (/ self?)
|
14
|
-
- interp: system / pyenv / interp.py
|
15
|
-
- venv: none / yes
|
16
|
-
- nginx: no / provided / must-configure
|
17
|
-
|
18
|
-
==
|
19
|
-
|
20
|
-
~deploy
|
21
|
-
deploy.pid (flock)
|
22
|
-
/app
|
23
|
-
/<appspec> - shallow clone
|
24
|
-
/conf
|
25
|
-
/env
|
26
|
-
<appspec>.env
|
27
|
-
/nginx
|
28
|
-
<appspec>.conf
|
29
|
-
/supervisor
|
30
|
-
<appspec>.conf
|
31
|
-
/venv
|
32
|
-
/<appspec>
|
33
|
-
|
34
|
-
?
|
35
|
-
/logs
|
36
|
-
/wrmsr--omlish--<spec>
|
37
|
-
|
38
|
-
spec = <name>--<rev>--<when>
|
39
|
-
|
40
|
-
https://docs.docker.com/config/containers/multi-service_container/#use-a-process-manager
|
41
|
-
https://serverfault.com/questions/211525/supervisor-not-loading-new-configuration-files
|
42
|
-
""" # noqa
|
43
|
-
# ruff: noqa: UP007
|
44
|
-
import argparse
|
45
|
-
import json
|
46
|
-
import sys
|
47
|
-
import typing as ta
|
48
|
-
|
49
|
-
from omlish.lite.logs import configure_standard_logging
|
50
|
-
from omlish.lite.marshal import unmarshal_obj
|
51
|
-
from omlish.lite.runtime import check_runtime_version
|
52
|
-
|
53
|
-
from ..configs import DeployConfig
|
54
|
-
from .base import Deployment
|
55
|
-
from .concerns.dirs import DirsConcern
|
56
|
-
from .concerns.nginx import GlobalNginxConcern
|
57
|
-
from .concerns.nginx import NginxConcern
|
58
|
-
from .concerns.repo import RepoConcern
|
59
|
-
from .concerns.supervisor import GlobalSupervisorConcern
|
60
|
-
from .concerns.supervisor import SupervisorConcern
|
61
|
-
from .concerns.user import UserConcern
|
62
|
-
from .concerns.venv import VenvConcern
|
63
|
-
|
64
|
-
|
65
|
-
##
|
66
|
-
|
67
|
-
|
68
|
-
def _deploy_cmd(args) -> None:
|
69
|
-
dct = json.loads(args.cfg)
|
70
|
-
cfg: DeployConfig = unmarshal_obj(dct, DeployConfig)
|
71
|
-
dp = Deployment(
|
72
|
-
cfg,
|
73
|
-
[
|
74
|
-
UserConcern,
|
75
|
-
DirsConcern,
|
76
|
-
GlobalNginxConcern,
|
77
|
-
GlobalSupervisorConcern,
|
78
|
-
RepoConcern,
|
79
|
-
VenvConcern,
|
80
|
-
SupervisorConcern,
|
81
|
-
NginxConcern,
|
82
|
-
],
|
83
|
-
)
|
84
|
-
dp.deploy()
|
85
|
-
|
86
|
-
|
87
|
-
##
|
88
|
-
|
89
|
-
|
90
|
-
def _build_parser() -> argparse.ArgumentParser:
|
91
|
-
parser = argparse.ArgumentParser()
|
92
|
-
|
93
|
-
subparsers = parser.add_subparsers()
|
94
|
-
|
95
|
-
parser_resolve = subparsers.add_parser('deploy')
|
96
|
-
parser_resolve.add_argument('cfg')
|
97
|
-
parser_resolve.set_defaults(func=_deploy_cmd)
|
98
|
-
|
99
|
-
return parser
|
100
|
-
|
101
|
-
|
102
|
-
def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
103
|
-
check_runtime_version()
|
104
|
-
|
105
|
-
if getattr(sys, 'platform') != 'linux': # noqa
|
106
|
-
raise OSError('must run on linux')
|
107
|
-
|
108
|
-
configure_standard_logging()
|
109
|
-
|
110
|
-
parser = _build_parser()
|
111
|
-
args = parser.parse_args(argv)
|
112
|
-
if not getattr(args, 'func', None):
|
113
|
-
parser.print_help()
|
114
|
-
else:
|
115
|
-
args.func(args)
|
116
|
-
|
117
|
-
|
118
|
-
if __name__ == '__main__':
|
119
|
-
_main()
|
@@ -1 +0,0 @@
|
|
1
|
-
# @omlish-lite
|