Skip to content

Commit

Permalink
Fix #364: Configure devbox in a vm (#432)
Browse files Browse the repository at this point in the history
  • Loading branch information
e-carlin authored Jan 31, 2024
1 parent 94a75d0 commit 86f721f
Show file tree
Hide file tree
Showing 22 changed files with 404 additions and 38 deletions.
24 changes: 16 additions & 8 deletions rsconf/component/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"""
from pykern import pkcompat
from pykern import pkconfig
from pykern import pkinspect
from pykern import pkio
from pykern import pkjson
from pykern.pkcollections import PKDict
from pykern.pkdebug import pkdp, pkdc, pkdlog
import copy
import hashlib
import re
import subprocess
Expand All @@ -36,7 +38,7 @@ def __init__(self, name, buildt, module_name=None, **kwargs):
def append_root_bash(self, *line):
self._root_bash.extend(line)

def append_root_bash_with_file(self, abs_path, j2_ctx):
def append_root_bash_with_file(self, abs_path, j2_ctx=None):
"""Append lines from jinja-rendered path
Distinct from `append_root_bash_with_resource`.
Expand All @@ -45,12 +47,13 @@ def append_root_bash_with_file(self, abs_path, j2_ctx):
abs_path (py.path): absolute path of file to render
j2_ctx (PKDict): dictionary to render
"""
self._root_bash.append(self._render_file(abs_path, j2_ctx))
self._root_bash.append(self._render_file(abs_path, j2_ctx or self.j2_ctx))

def append_root_bash_with_main(self, j2_ctx):
def append_root_bash_with_main(self, j2_ctx=None):
jc = j2_ctx or self.j2_ctx
self.append_root_bash_with_resource(
"{}/main.sh".format(self.name),
j2_ctx,
jc,
"{}_main".format(self.name),
)

Expand Down Expand Up @@ -92,16 +95,16 @@ def _pass():
j2_ctx, f"{self.module_name}_ssh_passphrase.json", visibility=visibility
)
o = pkjson.load_any(s) if s.exists() else PKDict()
p = o.get(self.user_name)
p = o.get(self._user)
if p is None:
o[self.user_name] = p = db.random_string()
o[self._user] = p = db.random_string()
pkjson.dump_pretty(o, filename=s)
return p

res = PKDict()
b = db.secret_path(
j2_ctx,
f"{self.module_name}/{self.user_name}",
f"{self.module_name}/{self._user}",
visibility=visibility,
directory=True,
)
Expand Down Expand Up @@ -492,6 +495,9 @@ def _bash_append_and_dst(
self._bash_append(host_path, md5=md5)
return dst

def _is_main_instance(self):
return self.name == pkinspect.module_basename(pkinspect.caller_module())

def _j2_ctx_set(self, values, method):
def f(prefix, values, method):
for k, v in values.items():
Expand All @@ -509,8 +515,10 @@ def f(prefix, values, method):
def _render_file(self, path, j2_ctx):
from pykern import pkjinja

c = copy.copy(j2_ctx)
c.this = c[self.name]
try:
return pkjinja.render_file(path, j2_ctx, strict_undefined=True)
return pkjinja.render_file(path, c, strict_undefined=True)
except Exception as e:
pkdlog("path={} exception={}", path, e)
raise
Expand Down
53 changes: 33 additions & 20 deletions rsconf/component/devbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,30 @@ class T(component.T):
def internal_build_compile(self):
from rsconf import systemd

if "user_name" not in self:
def _create_user_instances():
for u in self.hdb.devbox.users.keys():
self.buildt.build_component(
T(
f"{self.name}_{u}",
f"{self.module_name}_{u}",
self.buildt,
user_name=u,
module_name=self.name,
_user=u,
module_name=self.module_name,
)
)

if self._is_main_instance():
_create_user_instances()
return
self.buildt.require_component("docker", "network")
jc, _ = self.j2_ctx_init()
z = jc.devbox
jc, z = self.j2_ctx_init()
z.ssh_service_port_delta = jc[self.module_name].get(
"ssh_service_port_delta", 1000
)
z.setdefault("volumes", ["jupyter", "src"])
z.host_d = systemd.unit_run_d(jc, self.name)
self._gen_secrets(jc)
for x, d in ("guest", ".ssh"), ("host", "sshd"):
z[x] = self._gen_paths(z, z[x + "_d"], d)
z.guest = self._gen_paths(z, jc[self.module_name].guest_d, ".ssh")
z.host = self._gen_paths(z, z.host_d, "sshd")
z.run_u = jc.rsconf_db.run_u
# Only additional config for the server is the sshd config.
z.run_d = systemd.docker_unit_prepare(
Expand All @@ -46,7 +51,8 @@ def internal_build_compile(self):
z.guest.ssh_d.join("sshd_config"),
),
)
u = jc.devbox.users[self.user_name]
u = self._user_cfg(jc)
z.docker_image = jc[self.module_name].docker_image
if isinstance(u, PKDict):
z.docker_image = u.get("docker_image", z.docker_image)
z.ssh_port = u.ssh_port
Expand All @@ -57,11 +63,11 @@ def internal_build_compile(self):
def internal_build_write(self):
from rsconf import systemd

if "user_name" not in self:
if self._is_main_instance():
self.append_root_bash(": user instances do all the installs")
return
jc = self.j2_ctx
z = jc.devbox
z = jc[self.name]
v = [[z.host[v], z.guest[v], "rw"] for v in z.volumes]
v.extend(
[
Expand Down Expand Up @@ -92,7 +98,7 @@ def internal_build_write(self):
)
if "jupyter" in str(d):
j = d.join("bashrc")
self._jupyter_bashrc(z, j)
self._jupyter_bashrc(jc, z, j)
self.install_access(mode="400")
self.install_resource(z.host.sshd_config, jc)
for k, v in self.secrets.items():
Expand Down Expand Up @@ -121,14 +127,18 @@ def _gen_secrets(self, jc):
s = super().gen_identity_and_host_ssh_keys(jc, "host", encrypt_identity=True)
self.secrets = PKDict({k: s[k] for k in ("host_key_f", "identity_pub_f")})

def _jupyter_bashrc(self, z, path):
def _jupyter_bashrc(self, jc, z, path):
self.install_access(mode="600")
self.install_ensure_file_exists(path)
for n in ("package_path", "sim_types"):
if n in z:
self._env(f"SIREPO_FEATURE_CONFIG_{n.upper()}", ":".join(z[n]), path)
z.service_port = z.ssh_port + z.ssh_service_port_difference
z.job_supervisor_port = z.service_port + z.ssh_service_port_difference
if n in jc[self.module_name]:
self._env(
f"SIREPO_FEATURE_CONFIG_{n.upper()}",
":".join(jc[self.module_name][n]),
path,
)
z.service_port = z.ssh_port + z.ssh_service_port_delta
z.job_supervisor_port = z.service_port + z.ssh_service_port_delta
for n in ("service_port", "job_supervisor_port"):
self._env(f"SIREPO_PKCLI_{n.upper()}", z[n], path)
for n in ("DRIVER_LOCAL", "API"):
Expand All @@ -137,15 +147,15 @@ def _jupyter_bashrc(self, z, path):
f"http://127.0.0.1:{z.job_supervisor_port}",
path,
)
self._rsiviz(z, path)
self._rsiviz(jc, z, path)

def _network(self, jc, z):
n = self.buildt.get_component("network")
z.ip = n.unchecked_public_ip() or n.ip_and_net_for_host(jc.rsconf_db.host)[0]
n.add_public_tcp_ports([str(z.ssh_port)])

def _rsiviz(self, z, path):
u = z.users[self.user_name]
def _rsiviz(self, jc, z, path):
u = self._user_cfg(jc)
if not isinstance(u, PKDict) or not "rsiviz" in u:
return
e = [
Expand All @@ -169,3 +179,6 @@ def _rsiviz(self, z, path):
str(v),
path,
)

def _user_cfg(self, jc):
return jc[self.module_name].users[self._user]
2 changes: 1 addition & 1 deletion rsconf/component/mpi_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def _find_cluster(self, jc, z):
u,
z.user,
)
self.user_name = u
self._user = u
z.update(
user=u,
hosts=hosts[:],
Expand Down
1 change: 0 additions & 1 deletion rsconf/component/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def internal_build_compile(self):
), "nat_input_dev and nat_output_dev both have to be defined"

def internal_build_write(self):
jc = self.j2_ctx
jc = self.j2_ctx
z = jc.network
# Order matters: _restricted_public_tcp_ports modifed public_tcp_ports
Expand Down
67 changes: 67 additions & 0 deletions rsconf/component/vm_devbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Development in a vm
:copyright: Copyright (c) 2023 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from pykern import pkconfig
from pykern import pkio
from pykern.pkcollections import PKDict
from pykern.pkdebug import pkdp
from rsconf import component
from rsconf import systemd


class T(component.T):
def internal_build_compile(self):
def _create_user_instances():
for u in self.hdb.vm_devbox.users:
self.buildt.build_component(
T(
f"{self.module_name}_{u}",
self.buildt,
_user=u,
module_name=self.module_name,
)
)

jc, z = self.j2_ctx_init()
if self._is_main_instance():
_create_user_instances()
return
self.buildt.require_component("network")
z.run_d = systemd.unit_run_d(jc, self.name)
z.run_u = jc.rsconf_db.run_u
z.ssh_port = jc.vm_devbox_users.spec[self._user].ssh_port
z.ssh_guest_host_key_f = "/etc/ssh/host_key"
z.ssh_guest_identity_pub_f = "/etc/ssh/identity.pub"
z.start_f = z.run_d.join("start")
z.vm_hostname = f"{self._user}.{jc[self.module_name].vm_parent_domain}"
systemd.unit_prepare(self, self.j2_ctx, watch_files=(z.start_f,))
self._network(jc, z)
self._ssh(jc, z)

def internal_build_write(self):
if self._is_main_instance():
self.append_root_bash_with_main()
return
jc = self.j2_ctx
z = jc[self.name]
self.install_access(mode="500", owner=z.run_u)
self.install_resource("vm_devbox/start.sh", host_path=z.start_f)
self.install_access(mode="444", owner=jc.rsconf_db.root_u)
self.install_resource(
"vm_devbox/vm_devbox_unit_service", jc, jc.systemd.service_f
)

def _network(self, jc, z):
self.buildt.get_component("network").add_public_tcp_ports([str(z.ssh_port)])

def _ssh(self, jc, z):
z.sshd_config_f = z.run_d.join("sshd_config")
s = self.gen_identity_and_host_ssh_keys(jc, "host", encrypt_identity=True)
z.pkupdate(
PKDict(
ssh_identity_pub_key=pkio.read_text(s.identity_pub_f),
ssh_host_key=pkio.read_text(s.host_key_f),
)
)
1 change: 1 addition & 0 deletions rsconf/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def _host_db_fconf(self, channel, host):
host_run_d="/srv",
run_u="vagrant",
root_u="root",
installer_url="https://radia.run",
).pkupdate(c)
),
)
Expand Down
6 changes: 3 additions & 3 deletions rsconf/package_data/devbox/sshd_config.jinja
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
AuthorizedKeysFile {{ devbox.guest.identity_pub_f }}
HostKey {{ devbox.guest.host_key_f }}
ListenAddress {{ devbox.ip }}:{{ devbox.ssh_port }}
AuthorizedKeysFile {{ this.guest.identity_pub_f }}
HostKey {{ this.guest.host_key_f }}
ListenAddress {{ this.ip }}:{{ this.ssh_port }}
PasswordAuthentication no
PrintLastLog no
Protocol 2
Expand Down
19 changes: 19 additions & 0 deletions rsconf/package_data/vm_devbox/main.sh.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

vm_devbox_main() {
if vagrant --version > /dev/null 2>&1; then
return
fi
declare p=kernel-devel-$(uname -r)
if ! yum list "$p" &> /dev/null; then
install_err "rpm $p not found.
Virtualbox needs the kernel-devel rpm for the host kernel to be installed.
Maybe try updating the kernel? The repos only have kernel-devel for recent versions of the kernel."
fi
rsconf_yum_install "$p"
yum-config-manager --add-repo https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo
yum makecache -y
rsconf_yum_install VirtualBox-7.0
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
rsconf_yum_install vagrant
}
Loading

0 comments on commit 86f721f

Please sign in to comment.