From 80770b57d8f00cfab9bb2ebb9e6d8820c91d77ee Mon Sep 17 00:00:00 2001 From: Taras Shapovalov Date: Sat, 7 Sep 2024 19:29:11 +0400 Subject: [PATCH] Allow swm-coreto work in a release container --- priv/container/release/Dockerfile | 25 ++-- priv/container/release/supervisord.conf | 2 + priv/setup/skyport.config | 4 - scripts/build-release-container.sh | 2 + scripts/setup-skyport.sh | 11 +- scripts/setup-swm-core.py | 22 +++- scripts/skyport-container-prompt.py | 148 +++++++++++++++++------- scripts/start-debug-container.sh | 45 ++++--- scripts/start-release-container.sh | 53 +++++++-- src/lib/wm_topology.erl | 2 + src/lib/wm_utils.erl | 5 +- src/net/wm_tcp_client.erl | 36 +++--- src/srv/cloud/wm_cloud.erl | 11 +- src/srv/cloud/wm_gate.erl | 17 ++- src/srv/cloud/wm_virtres_handler.erl | 6 +- 15 files changed, 279 insertions(+), 110 deletions(-) diff --git a/priv/container/release/Dockerfile b/priv/container/release/Dockerfile index e6f8f9b..1de1612 100644 --- a/priv/container/release/Dockerfile +++ b/priv/container/release/Dockerfile @@ -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 @@ -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/ @@ -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"] diff --git a/priv/container/release/supervisord.conf b/priv/container/release/supervisord.conf index c122477..65a42a8 100644 --- a/priv/container/release/supervisord.conf +++ b/priv/container/release/supervisord.conf @@ -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 diff --git a/priv/setup/skyport.config b/priv/setup/skyport.config index 83ff17e..3814d12 100644 --- a/priv/setup/skyport.config +++ b/priv/setup/skyport.config @@ -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"}, diff --git a/scripts/build-release-container.sh b/scripts/build-release-container.sh index 07a059e..d041e2a 100755 --- a/scripts/build-release-container.sh +++ b/scripts/build-release-container.sh @@ -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} \ diff --git a/scripts/setup-skyport.sh b/scripts/setup-skyport.sh index f22e491..0f44122 100755 --- a/scripts/setup-skyport.sh +++ b/scripts/setup-skyport.sh @@ -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 @@ -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" diff --git a/scripts/setup-swm-core.py b/scripts/setup-swm-core.py index 7d4fc96..7c68fd2 100755 --- a/scripts/setup-swm-core.py +++ b/scripts/setup-swm-core.py @@ -42,6 +42,7 @@ import socket import time import uuid +import pwd from subprocess import Popen from subprocess import PIPE @@ -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 @@ -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") @@ -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}") diff --git a/scripts/skyport-container-prompt.py b/scripts/skyport-container-prompt.py index b2431b4..7cf702f 100755 --- a/scripts/skyport-container-prompt.py +++ b/scripts/skyport-container-prompt.py @@ -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, @@ -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", @@ -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) @@ -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: @@ -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__": diff --git a/scripts/start-debug-container.sh b/scripts/start-debug-container.sh index 78a1b09..4095237 100755 --- a/scripts/start-debug-container.sh +++ b/scripts/start-debug-container.sh @@ -1,4 +1,32 @@ #/bin/bash +# +# SPDX-FileCopyrightText: © 2021 Taras Shapovalov +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. set -x @@ -6,17 +34,13 @@ DOCKER=docker IMAGE_NAME=swm-build:24.2 DOCKER_SOCKET=/var/run/docker.sock X11_SOCKET=/tmp/.X11-unix -CONTAINER_NAME=swm-dev -BRIDGE=docker0 -HOST_IP=$(ip addr list ${BRIDGE} |grep "inet " |cut -d' ' -f6|cut -d/ -f1) +CONTAINER_NAME=skyport-dev case "$(uname -s)" in Linux*) ;; Darwin*) USER=root;; esac -#JUPUTER_HUB_API_PORT=8081 -#JUPUTER_HUB_PORT=8000 RUNNING=$(${DOCKER} inspect -f '{{.State.Running}}' ${CONTAINER_NAME}) if [ "$?" = "1" ]; then ${DOCKER} run\ @@ -29,20 +53,15 @@ if [ "$?" = "1" ]; then -v ${X11_SOCKET}:${X11_SOCKET}\ -e DISPLAY=${DISPLAY}\ --name ${CONTAINER_NAME}\ - --hostname $(hostname)\ - --domainname=openworkload.org\ - --add-host host:${HOST_IP}\ + --hostname ${CONTAINER_NAME}.openworkload.org\ + --domainname openworkload.org\ --workdir ${PWD}\ --tty\ --interactive\ --net host\ ${IMAGE_NAME}\ runuser -u ${USER} /bin/bash - #-p 10000:10000\ - #-p 10011:10011\ - #-p 8443:8443\ - #-p $JUPUTER_HUB_PORT:$JUPUTER_HUB_PORT\ - #-p $JUPUTER_HUB_API_PORT:$JUPUTER_HUB_API_PORT\ + else if [ ${RUNNING} = "false" ]; then ${DOCKER} start ${CONTAINER_NAME} diff --git a/scripts/start-release-container.sh b/scripts/start-release-container.sh index 07c5707..9efcbfc 100755 --- a/scripts/start-release-container.sh +++ b/scripts/start-release-container.sh @@ -1,31 +1,60 @@ #!/usr/bin/env bash # -# This script is used for running a new container with swm-core inside. +# SPDX-FileCopyrightText: © 2021 Taras Shapovalov +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This script is used for running Sky Port containers -SWM_API_PORT=10001 -SWM_HTTP_PORT=8443 CONTAINER_NAME=skyport IMAGE_NAME=skyport:latest -DOCKER_SOCKET=/var/run/docker.sock +DOMAIN=openworkload.org +DOCKER_SOCKET=/var/run/docker.sock # for local jobs RUNNING=$(docker inspect -f '{{.State.Running}}' ${CONTAINER_NAME} 2>/dev/null) NOT_RUNNING=$? if [ "$NOT_RUNNING" != "0" ]; then docker run\ - -v $HOME/.swm\ - -v $HOME/.cache\ - -v ${DOCKER_SOCKET}:${DOCKER_SOCKET}\ + --volume $HOME/.ssh:$HOME/.ssh\ + --volume $HOME/.swm:$HOME/.swm\ + --volume $HOME/.cache/swm:/root/.cache/swm\ + --volume ${DOCKER_SOCKET}:${DOCKER_SOCKET}\ --name ${CONTAINER_NAME}\ - --hostname $(hostname)\ - --domainname=openworkload.org\ + --hostname $(hostname).$DOMAIN\ + --domainname $DOMAIN\ --workdir ${PWD}\ --tty\ --interactive\ - --net bridge\ - -p $SWM_HTTP_PORT:$SWM_HTTP_PORT\ - -p $SWM_API_PORT:$SWM_API_PORT\ + --net host\ + -e SKYPORT_USER=$(id -u -n)\ + -e SKYPORT_USER_ID=$(id -u)\ ${IMAGE_NAME} + elif [[ ${RUNNING} = "false" ]]; then docker start ${CONTAINER_NAME} fi diff --git a/src/lib/wm_topology.erl b/src/lib/wm_topology.erl index abe905d..06dabf0 100644 --- a/src/lib/wm_topology.erl +++ b/src/lib/wm_topology.erl @@ -776,6 +776,8 @@ find_rh_path(FromNodeId, ToNodeId, RH) -> %% @doc Returns sub-tree of RH of a node (with children and neightbour nodes included if needed) -spec get_node_rh(node_id(), map(), boolean()) -> map(). +get_node_rh(_, undefined, _) -> + #{}; get_node_rh(NodeId, RH, Scope) -> [RootKey] = maps:keys(RH), % RH should have only one root RootRH = maps:get(RootKey, RH), diff --git a/src/lib/wm_utils.erl b/src/lib/wm_utils.erl index 132d7b0..5c5cccc 100644 --- a/src/lib/wm_utils.erl +++ b/src/lib/wm_utils.erl @@ -98,9 +98,9 @@ uuid(v4) -> wake_up_after(MilliSeconds, WakeUpMessage) -> case wm_utils:get_calling_module_name() of noproc -> - ?LOG_DEBUG("Wake me after ~p with message ~p", [MilliSeconds, WakeUpMessage]); + ?LOG_DEBUG("Wake me after ~p with message: ~p", [MilliSeconds, WakeUpMessage]); Mod -> - ?LOG_DEBUG("Wake ~p after ~p with message ~p", [Mod, MilliSeconds, WakeUpMessage]) + ?LOG_DEBUG("Wake ~p after ~p with message: ~p", [Mod, MilliSeconds, WakeUpMessage]) end, S = case MilliSeconds of X when X < 0 -> @@ -148,7 +148,6 @@ protected_call(Mod, Msg, Default) -> -spec protected_call(atom() | pid(), term()) -> term() | {error, any()}. protected_call(Mod, Msg) -> Ms = wm_conf:g(srv_local_call_timeout, {?CALL_TIMEOUT, integer}), - %?LOG_DEBUG("gen_server:call(~p, [...], ~p)", [Mod, Ms]), try gen_server:call(Mod, Msg, Ms) catch diff --git a/src/net/wm_tcp_client.erl b/src/net/wm_tcp_client.erl index 898d5f7..43a9cd4 100644 --- a/src/net/wm_tcp_client.erl +++ b/src/net/wm_tcp_client.erl @@ -17,18 +17,7 @@ connect(Args) -> Host = get_host(Args), Port = maps:get(port, Args, ?DEFAULT_PORT), Timeout = maps:get(timeout, Args, ?DEFAULT_CONNECT_TIMEOUT), - Home = wm_utils:get_env("HOME"), - UserCert = filename:join([Home, ".swm", "cert.pem"]), - UserKey = filename:join([Home, ".swm", "key.pem"]), - {Cert, Key} = - case {filelib:is_file(UserCert), filelib:is_file(UserKey)} of - {true, true} -> - {UserCert, UserKey}; - _ -> - {maps:get(cert, Args, filename:absname(UserCert)), maps:get(key, Args, filename:absname(UserKey))} - end, - NativeCert = filename:nativename(Cert), - NativeKey = filename:nativename(Key), + {CertPath, KeyPath} = get_cert_key_paths(Args), Port2 = case is_list(Port) of true -> @@ -38,7 +27,7 @@ connect(Args) -> Port end, To = io_lib:format("~p:~p", [Host, Port2]), - Opts = mk_opts(NativeCert, NativeKey), + Opts = mk_opts(CertPath, KeyPath), ?LOG_DEBUG("Connect to ~s", [To]), try case ssl:connect(Host, Port2, Opts, Timeout) of @@ -117,3 +106,24 @@ get_host(Args) -> {error, einval} -> Server end. + +-spec get_cert_key_paths(map()) -> {string(), string()}. +get_cert_key_paths(Args) -> + Home = wm_utils:get_env("HOME"), + UserCert = filename:join([Home, ".swm", "cert.pem"]), + UserKey = filename:join([Home, ".swm", "key.pem"]), + {Cert, Key} = + case {filelib:is_file(UserCert), filelib:is_file(UserKey)} of + {true, true} -> + {UserCert, UserKey}; + _ -> + ArgCert = maps:get(cert, Args, filename:absname(UserCert)), + ArgKey = maps:get(key, Args, filename:absname(UserKey)), + case {filelib:is_file(ArgCert), filelib:is_file(ArgKey)} of + {true, true} -> + {ArgCert, ArgKey}; + _ -> + {"/opt/swm/spool/secure/node/cert.pem", "/opt/swm/spool/secure/node/key.pem"} + end + end, + {filename:nativename(Cert), filename:nativename(Key)}. diff --git a/src/srv/cloud/wm_cloud.erl b/src/srv/cloud/wm_cloud.erl index 3520860..9ef6384 100644 --- a/src/srv/cloud/wm_cloud.erl +++ b/src/srv/cloud/wm_cloud.erl @@ -236,10 +236,17 @@ handle_retrieved_flavors(FlavorNodes, RemoteId) -> wm_entity:set({default_flavor_id, DefaultId}, Remote)); _ -> ok - end + end, + wm_topology:reload() end; {error, not_found} -> - [ok = wm_conf:delete(Node) || Node <- TemplateNodes] + case length(TemplateNodes) of + 0 -> + ok; + _ -> + [ok = wm_conf:delete(Node) || Node <- TemplateNodes], + wm_topology:reload() + end end. -spec merge_partition_node_ids([node_id()], [#node{}]) -> [node_id()]. diff --git a/src/srv/cloud/wm_gate.erl b/src/srv/cloud/wm_gate.erl index 64fa64e..7f5efb1 100644 --- a/src/srv/cloud/wm_gate.erl +++ b/src/srv/cloud/wm_gate.erl @@ -510,13 +510,28 @@ fetch_partition(Remote, Creds, PartExtIdOrName, #mstate{spool = Spool, pem_data {error, Error} end. +-spec get_credentials_file_path() -> {ok, string()} | {error, string()}. +get_credentials_file_path() -> + case os:getenv("SWM_CLOUD_CREDENTIALS_FILE") of + false -> + case os:getenv("HOME") of + false -> + {error, "User home is not set"}; + HomeDir -> + {ok, HomeDir ++ "/" ++ ?CREDENTIALS_FILE} + end; + CredentialsFile -> + {ok, CredentialsFile} + end. + -spec read_credentials_from_file(#remote{}) -> {ok, [{binary(), binary()}]} | {error, string()}. read_credentials_from_file(Remote) -> case wm_entity:get(kind, Remote) of localhost -> {ok, []}; RemoteKind -> - FilePath = os:getenv("HOME") ++ "/" ++ ?CREDENTIALS_FILE, + {ok, FilePath} = get_credentials_file_path(), + ?LOG_DEBUG("Use credentials file path: ~p", [FilePath]), AbsPath = filename:absname(FilePath), case wm_utils:read_file(AbsPath, [binary]) of {ok, CredsBin} -> diff --git a/src/srv/cloud/wm_virtres_handler.erl b/src/srv/cloud/wm_virtres_handler.erl index cf74158..7819393 100644 --- a/src/srv/cloud/wm_virtres_handler.erl +++ b/src/srv/cloud/wm_virtres_handler.erl @@ -85,8 +85,7 @@ upload_swm_worker(RemoteNodeId, SshUserDir) -> {ok, MyNode} = wm_self:get_node(), {ToAddr, _} = wm_conf:get_relative_address(ToNode, MyNode), RemoteFile = "/opt/swm/swm-worker.tar.gz", - Version = wm_utils:get_env("SWM_VERSION"), - DefaultWorkerPath = io_lib:format("/opt/swm/~p/packages/swm-~p-worker.tar.gz", [Version, Version]), + DefaultWorkerPath = "/opt/swm/swm-worker.tar.gz", DefaultWorkerPathFromEnv = os:getenv("SWM_WORKER_LOCAL_PATH", DefaultWorkerPath), Port = wm_conf:g(ssh_prov_listen_port, {?DEFAULT_SSH_PROVISION_PORT, integer}), wm_file_transfer:upload_file_sftp_sync(ToAddr, Port, DefaultWorkerPathFromEnv, RemoteFile, SshUserDir). @@ -197,7 +196,8 @@ get_resource_value_property(Tab, Name, Job, Remote, FunGetDefault) -> EntityName; {error, not_found} -> JobId = wm_entity:get(id, Job), - throw(io_lib:format("Entity ~p ~p (job ~p) is unknown", [Tab, EntityName, JobId])) + throw(lists:flatten( + io_lib:format("Entity ~p ~p (job ~p) is unknown", [Tab, EntityName, JobId]))) end end end.