Skip to content

Commit

Permalink
Allow swm-coreto work in a release container
Browse files Browse the repository at this point in the history
  • Loading branch information
shapovalovts committed Sep 7, 2024
1 parent c9f1abc commit 80770b5
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 110 deletions.
25 changes: 15 additions & 10 deletions priv/container/release/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get clean
RUN apt-get update
RUN apt-get update --fix-missing
RUN apt-get install openssl -y
RUN apt-get install openssh-client -y # for host certificates
RUN apt-get install python3 -y # for setup
RUN apt-get install rlwrap -y # for swmctl during setup
RUN apt-get install vim less mc -y # for debug
RUN apt-get install -y supervisor
RUN apt-get install -y openssl openssh-client # for certificate generation
RUN apt-get install -y rlwrap # for swmctl during setup
RUN apt-get install -y less mc # for debug
RUN apt-get install -y supervisor # run swm-core and swm-cloud-gate

# Install python version we currently require:
RUN apt-get install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev
Expand All @@ -38,6 +36,9 @@ RUN cd /tmp && \
# Cache invalidation threshold
ARG CACHEBUST=1

ENV SKYPORT_USER="taras"
ENV SKYPORT_USER_ID=1000

RUN mkdir -p /opt/swm

COPY $SWM_GATE_PACKAGE /opt/swm/
Expand All @@ -47,14 +48,18 @@ COPY _build/packages/swm-$SWM_VERSION.tar.gz /opt/swm/swm.tar.gz
RUN tar zfx /opt/swm/swm.tar.gz -C /opt/swm/ && ln -s /opt/swm/$SWM_VERSION /opt/swm/current

# To run multiple processes in one container:
COPY priv/container/release/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY priv/container/release/supervisord.conf /etc/supervisor/supervisord.conf.template

# swm-core to swm-core connection port:
# parent swm-core -> chald swm-core connection port:
EXPOSE 10001

# HTTP client to swm-core port:
# child swm-core -> parent swm-core connection port:
EXPOSE 10002

# HTTP client -> swm-core port:
EXPOSE 8443

VOLUME /opt/swm
# HTTP client -> swm-gate port (for debug):
EXPOSE 8444

CMD ["/opt/swm/current/scripts/skyport-container-prompt.py"]
2 changes: 2 additions & 0 deletions priv/container/release/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/swm-core.log
user={{ USERNAME }}
environment=SWM_CLOUD_CREDENTIALS_FILE="/home/{{ USERNAME }}/.swm/credentials.json",HOME="/home/{{ USERNAME }}"

[program:swm-gate]
command=/usr/local/bin/python /usr/local/lib/python3.10/site-packages/swmcloudgate/start.py
Expand Down
4 changes: 0 additions & 4 deletions priv/setup/skyport.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
[
{global, [{name,node_cert}, {value, "_SWM_SPOOL_/secure/node/cert.pem"}]},
{global, [{name,node_key}, {value, "_SWM_SPOOL_/secure/node/key.pem"}]},
{global, [{name,cluster_cert}, {value, "_SWM_SPOOL_/secure/cluster/cert.pem"}]},

{cluster,
[
{id, "id-cluster1"},
Expand Down
2 changes: 2 additions & 0 deletions scripts/build-release-container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ TAG=latest
GATE_PACKAGE_NAME=swmcloudgate-${CLOUD_GATE_VERSION}-py3-none-any.whl
GATE_PACKAGE_PATH_OLD=$ROOT_DIR/../swm-cloud-gate/dist/$GATE_PACKAGE_NAME
GATE_PACKAGE_PATH_NEW=_build/packages/$GATE_PACKAGE_NAME

echo "Copy $GATE_PACKAGE_PATH_OLD to $GATE_PACKAGE_PATH_NEW"
cp -f $GATE_PACKAGE_PATH_OLD $GATE_PACKAGE_PATH_NEW

${DOCKER} build --tag ${IMAGE_NAME}:${SWM_VERSION} \
Expand Down
11 changes: 6 additions & 5 deletions scripts/setup-skyport.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ fi

export SWM_ROOT=/opt/swm
export SWM_VERSION_DIR=/opt/swm/current

source ${SWM_VERSION_DIR}/scripts/swm.env
export SWM_SPOOL=/home/$USERNAME/.swm/spool
export SWM_API_PORT=10001

source ${SWM_VERSION_DIR}/scripts/swm.env
cd $SWM_VERSION_DIR

CONFIG_BASE=${SWM_VERSION_DIR}/priv/setup/setup.config
Expand All @@ -81,9 +81,10 @@ if [ "$EXIT_CODE" != "0" ]; then
exit $EXIT_CODE
fi

chown -R ${USERNAME}:${USERNAME} /opt/swm/spool
chown -R ${USERNAME}:${USERNAME} ${SWM_VERSION_DIR}/log
chown -R ${USERNAME}:${USERNAME} ${SWM_VERSION_DIR}/releases
echo "Tune permissions"
chown -v -R ${USERNAME}:${USERNAME} /home/${USERNAME}/.swm/spool
chown -v -R ${USERNAME}:${USERNAME} ${SWM_VERSION_DIR}/log
chown -v -R ${USERNAME}:${USERNAME} ${SWM_VERSION_DIR}/releases

echo
echo "Sky Port setup finished"
Expand Down
22 changes: 18 additions & 4 deletions scripts/setup-swm-core.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import socket
import time
import uuid
import pwd

from subprocess import Popen
from subprocess import PIPE
Expand Down Expand Up @@ -202,6 +203,7 @@ def get_div_arg(opts):
div_arg = "-c"
return div_arg


def spawn_vnode(opts):
if opts["DIVISION"] not in ("grid", "cluster"):
return
Expand Down Expand Up @@ -336,10 +338,18 @@ def create_chain_cert(opts):
outfile.write(infile.read())


def get_user_home(username: str) -> str:
try:
return pwd.getpwnam(username).pw_dir
except KeyError:
LOG.error(f"User '{username}' not found")
sys.exit(1)


def install_admin_cert(opts):
home = os.environ["HOME"]
home = get_user_home(opts["SWM_USER"])
if not home:
LOG.error("$HOME is not defined")
LOG.error("User home is unknown is not defined")
sys.exit(1)
src_dir = os.path.join(opts["SWM_SPOOL"], "secure", "users", opts["SWM_ADMIN_USER"])
dst_dir = os.path.join(home, ".swm")
Expand Down Expand Up @@ -601,8 +611,12 @@ def create_archive(opts):
files.append(os.path.join(root_dir, opts["SWM_VERSION"]))
files.extend(key_dirs)

archive = f"{root_dir}/{PRODUCT}-{swm_version}-worker.tar.gz"
args = ["--transform", "'s,^.*\/swm/,,'", "-czf", archive, " ".join(files)]
archive = f"{root_dir}/{PRODUCT}-worker.tar.gz"
transform_args = [
"--transform", "'s,^.*\/swm/,,'",
"--transform", "'s,^home/" + opts["SWM_ADMIN_USER"] + "/.swm,,'",
]
args = transform_args + ["-czf", archive, " ".join(files)]

run("tar", args, os.environ)
LOG.info(f"Final worker SWM archive: {archive}")
Expand Down
148 changes: 108 additions & 40 deletions scripts/skyport-container-prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,45 @@

import os
import sys
import subprocess
import time
import pwd
import shutil
import subprocess


def get_username() -> str:
if username := os.environ.get("SKYPORT_USER"):
print(f"Username from environment: {username}")
return username
while True:
if username := input("Enter container user name: ").strip().lower():
return username


def render_supervisor_config(username: str) -> None:
template_path = "/etc/supervisor/supervisord.conf.template"
output_path = "/etc/supervisor/conf.d/supervisord.conf"

if os.path.exists(output_path):
print(f"Supervisord configuration file exists: {output_path}")
return

with open(template_path, "r") as template_file:
template_content = template_file.read()

def run_supervisord() -> None:
rendered_content = template_content.replace("{{ USERNAME }}", username)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, "w") as output_file:
output_file.write(rendered_content)

print(f"Supervisord configuration file rendered: {output_path}")


def run_supervisord(username: str = "") -> None:
if username:
render_supervisor_config(username)
command = ["supervisord", "-c", "/etc/supervisor/supervisord.conf", "-l", "/tmp/supervisord.log"]
print(f"Start supervisord for Sky Port daemons:\n {' '.join(command)}")
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
Expand All @@ -60,9 +93,12 @@ def run_supervisord() -> None:
process.wait()


def add_user() -> None:
username = input("Enter admin user name (will be VM admin): ").strip().lower()
uid = input("Enter admin user system UID: ").strip().lower()
def add_system_user(username: str) -> None:
uid = os.environ.get("SKYPORT_USER_ID")
if uid:
print(f"UID from environment: {uid}")
else:
uid = input("Enter container user system id: ").strip().lower()
try:
subprocess.run([
"useradd",
Expand All @@ -75,11 +111,10 @@ def add_user() -> None:
except subprocess.CalledProcessError as e:
print(f"Error creating user '{username}': {e}")
sys.exit(1)
return username


def ensure_symlinks(username: str) -> None:
src_path = f"/home/{username}/.swm/spool"
def ensure_symlinks(home: str) -> None:
src_path = f"{home}/.swm/spool"
dst_path = "/opt/swm/spool"
os.makedirs(src_path, exist_ok=True)
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
Expand All @@ -93,18 +128,16 @@ def ensure_symlinks(username: str) -> None:


def setup_skyport(username: str) -> None:
#command = ["/opt/swm/current/scripts/setup-skyport.sh", "-u", username]
command = "/opt/swm/current/scripts/setup-skyport.sh -u" + username
command = f"/opt/swm/current/scripts/setup-skyport.sh -u {username}"
log_file = "/var/log/setup-skyport.log"

#print(f"Running command: {' '.join(command)}")
print(f"Running command: {command}")
with open(log_file, "w") as log:
with open(log_file, "w") as log_file:
process = subprocess.Popen(
command,
shell=True,
stdout=log,
stderr=subprocess.STDOUT
stdout=log_file,
stderr=subprocess.STDOUT,
)

while process.poll() is None:
Expand All @@ -113,40 +146,75 @@ def setup_skyport(username: str) -> None:

if process.returncode == 0:
print("\n\n"
"Setup has completed successfully.\n"
"Ensure Azure is configured, see HOWTO/AZURE.md.\n"
"Then restart the container to start Sky Port.\n")
"Sky Port has been initialized.\n"
"Please ensure now that Azure is configured, see HOWTO/AZURE.md.\n"
"The container will be stopped now. Start again when Azure is ready.\n"
)
else:
print(f"Setup has failed with exit code {process.returncode},\n"
"see /var/log/setup-skyport.log for details.")
print(f"Setup has failed with exit code {process.returncode}.\n"
"See /var/log/setup-skyport.log for details.")
sys.exit(1)


def ask_clean_spool(spool_directory: str) -> None:
while True:
if not os.path.exists(spool_directory):
break
if os.listdir(spool_directory):
answer = input(f"Recreate configuration located in {spool_directory}? [N] ").strip().lower()
if answer in ["yes", "y"]:
shutil.rmtree(spool_directory)
break
elif answer in ["no", "n"] or not answer:
break
else:
break


def get_user_home(username: str) -> str:
try:
user_info = pwd.getpwnam(username)
return user_info.pw_dir
except KeyError:
pass
return f"/home/{username}"


def touch(file_path: str) -> None:
with open(file_path, 'w') as file:
pass


def main() -> None:
spool_directory = "/opt/swm/spool"
username = get_username()
if not username:
print("User name is unknown")
sys.exit(1)

skyport_initialized_file = "/skyport-initialized"
if os.path.exists(skyport_initialized_file):
run_supervisord(username)

home = get_user_home(username)
if not home:
print("User home is unknown")
sys.exit(1)

spool_directory = f"{home}/.swm/spool"
ask_clean_spool(spool_directory)

if not os.path.exists(spool_directory):
os.makedirs(spool_directory)

if not os.path.exists(spool_directory) or not os.listdir(spool_directory):
response = None
while (not response):
response = input("Sky Port needs initialization, start it? (y/n): ").strip().lower()
if response in ['n', 'no']:
print("Initialization interrupted.")
return
if response in ['y', 'yes']:
if username := add_user():
ensure_symlinks(username)
setup_skyport(username)
else:
print("Username is unknown")
sys.exit(1)
else:
print("Type Y or N")
response = None
print(f"Spool directory is not initialized: {spool_directory}")
add_system_user(username)
ensure_symlinks(home)
setup_skyport(username)
else:
print("No initialization needed. Sky Port is starting.")
import time
time.sleep(100000)
run_supervisord()
run_supervisord(username)

touch(skyport_initialized_file)


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 80770b5

Please sign in to comment.