From cb154f3a54c90000eae9fd582304872eec9db54e Mon Sep 17 00:00:00 2001 From: Luis Rascao Date: Mon, 5 Sep 2016 22:20:50 +0100 Subject: Fix upgrade/downgrade/install usage The second argument is actually the version and not the package name. --- priv/templates/extended_bin | 5 ++--- priv/templates/extended_bin_windows | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'priv') diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin index 6eee7a5..2941083 100755 --- a/priv/templates/extended_bin +++ b/priv/templates/extended_bin @@ -314,9 +314,8 @@ case "$1" in upgrade|downgrade|install) if [ -z "$2" ]; then - echo "Missing package argument" - echo "Usage: $REL_NAME $1 {package base name}" - echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" + echo "Missing version argument" + echo "Usage: $REL_NAME $1 {version}" exit 1 fi diff --git a/priv/templates/extended_bin_windows b/priv/templates/extended_bin_windows index d892ea6..a4cc42c 100644 --- a/priv/templates/extended_bin_windows +++ b/priv/templates/extended_bin_windows @@ -175,9 +175,8 @@ set description=Erlang node %node_name% in %rootdir% :: Relup and reldown :relup @if "" == "%2" ( - echo Missing package argument - echo Usage: %rel_name% %1 {package base name} - echo NOTE {package base name} MUST NOT include the .tar.gz suffix + echo Missing version argument + echo Usage: %rel_name% %1 {version} set ERRORLEVEL=1 exit /b %ERRORLEVEL% ) -- cgit v1.2.3 From a3bffcaf8eaddc7b316ba2669177f9d40979b254 Mon Sep 17 00:00:00 2001 From: Luis Rascao Date: Mon, 5 Sep 2016 22:24:40 +0100 Subject: Allow for a more flexible relup package location Instead of forcing the user to put the tarball package with the expected name (.tar.gz)and in the expected location (releases/) symlink this fixed file name to a tarball existing in one of three different places (releases/, releases/, releases//.tar.gz). Refactor the install/upgrade escript to make it more dynamic, it now runs commands that are passed from the start script while accepting a variable number of arguments. Add a `versions` command to the extended start script that prints out the currently installed versions and their status. --- priv/templates/extended_bin | 19 ++-- priv/templates/install_upgrade_escript | 199 ++++++++++++++++++++++++--------- 2 files changed, 155 insertions(+), 63 deletions(-) (limited to 'priv') diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin index 2941083..d133570 100755 --- a/priv/templates/extended_bin +++ b/priv/templates/extended_bin @@ -312,13 +312,15 @@ case "$1" in relx_rem_sh ;; - upgrade|downgrade|install) + upgrade|downgrade|install|unpack) if [ -z "$2" ]; then echo "Missing version argument" echo "Usage: $REL_NAME $1 {version}" exit 1 fi + COMMAND="$1"; shift + # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then echo "Node is not running!" @@ -326,25 +328,20 @@ case "$1" in fi exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ - "install" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2" + "$COMMAND" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" ;; - unpack) - if [ -z "$2" ]; then - echo "Missing package argument" - echo "Usage: $REL_NAME $1 {package base name}" - echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" - exit 1 - fi - + versions) # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then echo "Node is not running!" exit 1 fi + COMMAND="$1"; shift + exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ - "unpack" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2" + "versions" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" ;; console|console_clean|console_boot) diff --git a/priv/templates/install_upgrade_escript b/priv/templates/install_upgrade_escript index fe4e5e1..6777c78 100644 --- a/priv/templates/install_upgrade_escript +++ b/priv/templates/install_upgrade_escript @@ -2,58 +2,59 @@ %%! -noshell -noinput %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ft=erlang ts=4 sw=4 et +%% the following is so we have access to ?MODULE +-mode(compile). + +-export([install/2, + unpack/2, + upgrade/2, + downgrade/2, + versions/2]). -define(TIMEOUT, 300000). -define(INFO(Fmt,Args), io:format(Fmt,Args)). -%% Unpack or upgrade to a new tar.gz release -main(["unpack", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) -> +main([Command0, DistInfoStr | CommandArgs]) -> + %% convert the distribution info arguments string to an erlang term + {ok, Tokens, _} = erl_scan:string(DistInfoStr ++ "."), + {ok, DistInfo} = erl_parse:parse_term(Tokens), + Command = list_to_atom(Command0), + %% invoke the command passed as argument + erlang:apply(?MODULE, Command, [DistInfo, CommandArgs]); +main(Args) -> + ?INFO("unknown args: ~p\n", [Args]), + erlang:halt(1). + +unpack({RelName, NameTypeArg, NodeName, Cookie}, [VersionArg]) -> TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), - WhichReleases = which_releases(TargetNode), Version = parse_version(VersionArg), - case proplists:get_value(Version, WhichReleases) of - undefined -> - %% not installed, so unpack tarball: - ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]), - ReleasePackage = Version ++ "/" ++ RelName, - case rpc:call(TargetNode, release_handler, unpack_release, - [ReleasePackage], ?TIMEOUT) of - {ok, Vsn} -> - ?INFO("Unpacked successfully: ~p~n", [Vsn]); - {error, UnpackReason} -> - print_existing_versions(TargetNode), - ?INFO("Unpack failed: ~p~n",[UnpackReason]), - erlang:halt(2) - end; + case unpack_release(RelName, TargetNode, Version) of + {ok, Vsn} -> + ?INFO("Unpacked successfully: ~p~n", [Vsn]); old -> %% no need to unpack, has been installed previously - ?INFO("Release ~s is marked old, switching to it.~n",[Version]); + ?INFO("Release ~s is marked old.~n",[Version]); unpacked -> - ?INFO("Release ~s is already unpacked, now installing.~n",[Version]); + ?INFO("Release ~s is already unpacked.~n",[Version]); current -> - ?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]); + ?INFO("Release ~s is already installed and current.~n",[Version]); permanent -> - ?INFO("Release ~s is already installed, and set permanent.~n",[Version]) + ?INFO("Release ~s is already installed and set permanent.~n",[Version]); + {error, Reason} -> + ?INFO("Unpack failed: ~p~n",[Reason]), + print_existing_versions(TargetNode), + erlang:halt(2) end; -main(["install", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) -> +install(_, Args) -> + ?INFO("unpack: unknown args ~p\n", [Args]). + +install({RelName, NameTypeArg, NodeName, Cookie}, [VersionArg]) -> TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), - WhichReleases = which_releases(TargetNode), Version = parse_version(VersionArg), - case proplists:get_value(Version, WhichReleases) of - undefined -> - %% not installed, so unpack tarball: - ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]), - ReleasePackage = Version ++ "/" ++ RelName, - case rpc:call(TargetNode, release_handler, unpack_release, - [ReleasePackage], ?TIMEOUT) of - {ok, Vsn} -> - ?INFO("Unpacked successfully: ~p~n", [Vsn]), - install_and_permafy(TargetNode, RelName, Vsn); - {error, UnpackReason} -> - print_existing_versions(TargetNode), - ?INFO("Unpack failed: ~p~n",[UnpackReason]), - erlang:halt(2) - end; + case unpack_release(RelName, TargetNode, Version) of + {ok, Vsn} -> + ?INFO("Unpacked successfully: ~p~n", [Vsn]), + install_and_permafy(TargetNode, RelName, Vsn); old -> %% no need to unpack, has been installed previously ?INFO("Release ~s is marked old, switching to it.~n",[Version]), @@ -61,20 +62,114 @@ main(["install", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) -> unpacked -> ?INFO("Release ~s is already unpacked, now installing.~n",[Version]), install_and_permafy(TargetNode, RelName, Version); - current -> %% installed and in-use, just needs to be permanent - ?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]), + current -> + ?INFO("Release ~s is already installed and current, making permanent.~n",[Version]), permafy(TargetNode, RelName, Version); permanent -> - ?INFO("Release ~s is already installed, and set permanent.~n",[Version]) + ?INFO("Release ~s is already installed and set permanent.~n",[Version]); + {error, Reason} -> + ?INFO("Unpack failed: ~p~n",[Reason]), + print_existing_versions(TargetNode), + erlang:halt(2) end; -main(_) -> - erlang:halt(1). +install(_, Args) -> + ?INFO("install: unknown args ~p\n", [Args]). + +upgrade(DistInfo, Args) -> + install(DistInfo, Args). + +downgrade(DistInfo, Args) -> + install(DistInfo, Args). + +versions({_RelName, NameTypeArg, NodeName, Cookie}, []) -> + TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), + print_existing_versions(TargetNode). + +unpack_release(RelName, TargetNode, Version) -> + WhichReleases = which_releases(TargetNode), + case proplists:get_value(Version, WhichReleases) of + undefined -> + %% not installed, so unpack tarball: + %% look for a release package with the intended version in the following order: + %% releases/-.tar.gz + %% releases//-.tar.gz + %% releases//.tar.gz + case find_and_link_release_package(Version, RelName) of + {_, undefined} -> + {error, release_package_not_found}; + {ReleasePackage, ReleasePackageLink} -> + ?INFO("Release ~s not found, attempting to unpack ~s~n", + [Version, ReleasePackage]), + case rpc:call(TargetNode, release_handler, unpack_release, + [ReleasePackageLink], ?TIMEOUT) of + {ok, Vsn} -> {ok, Vsn}; + {error, _} = Error -> Error + end + end; + Other -> Other + end. + +%% 1. look for a release package tarball with the provided version in the following order: +%% releases/-.tar.gz +%% releases//-.tar.gz +%% releases//.tar.gz +%% 2. create a symlink from a fixed location (ie. releases//.tar.gz) +%% to the release package tarball found in 1. +%% 3. return a tuple with the paths to the release package and +%% to the symlink that is to be provided to release handler +find_and_link_release_package(Version, RelName) -> + RelNameStr = atom_to_list(RelName), + %% regardless of the location of the release package, we'll + %% always give release handler the same path which is the symlink + %% the path to the package link is relative to "releases/" because + %% that's what release handler is expecting + ReleaseHandlerPackageLink = filename:join(Version, RelNameStr), + %% this is the symlink name we'll create once + %% we've found where the actual release package is located + ReleaseLink = filename:join(["releases", Version, + RelNameStr ++ ".tar.gz"]), + case first_value(fun filelib:is_file/1, + [filename:join(["releases", + RelNameStr ++ "-" ++ Version ++ ".tar.gz"]), + filename:join(["releases", Version, + RelNameStr ++ "-" ++ Version ++ ".tar.gz"]), + filename:join(["releases", Version, + RelNameStr ++ ".tar.gz"])]) of + no_value -> + {undefined, undefined}; + %% no need to create the link since the release package we + %% found is located in the same place as the link would be + {ok, Filename} when is_list(Filename) andalso + Filename =:= ReleaseLink -> + {Filename, ReleaseHandlerPackageLink}; + {ok, Filename} when is_list(Filename) -> + %% we now have the location of the release package, however + %% release handler expects a fixed nomenclature (.tar.gz) + %% so give it just that by creating a symlink to the tarball + %% we found. + %% make sure that the dir where we're creating the link in exists + ok = filelib:ensure_dir(filename:join([filename:dirname(ReleaseLink), "dummy"])), + %% create the symlink pointing to the full path name of the + %% release package we found + ok = file:make_symlink(filename:absname(Filename), ReleaseLink), + {Filename, ReleaseHandlerPackageLink} + end. + +first_value(_Fun, []) -> no_value; +first_value(Fun, [Value | Rest]) -> + case Fun(Value) of + false -> + first_value(Fun, Rest); + true -> + {ok, Value} + end. parse_version(V) when is_list(V) -> hd(string:tokens(V,"/")). install_and_permafy(TargetNode, RelName, Vsn) -> - case rpc:call(TargetNode, release_handler, check_install_release, [Vsn], ?TIMEOUT) of + case rpc:call(TargetNode, release_handler, + check_install_release, [Vsn], ?TIMEOUT) of {ok, _OtherVsn, _Desc} -> ok; {error, Reason} -> @@ -108,9 +203,10 @@ install_and_permafy(TargetNode, RelName, Vsn) -> end. permafy(TargetNode, RelName, Vsn) -> - ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT), - file:copy(filename:join(["bin", RelName++"-"++Vsn]), - filename:join(["bin", RelName])), + ok = rpc:call(TargetNode, release_handler, + make_permanent, [Vsn], ?TIMEOUT), + file:copy(filename:join(["bin", atom_to_list(RelName)++"-"++Vsn]), + filename:join(["bin", atom_to_list(RelName)])), ?INFO("Made release permanent: ~p~n", [Vsn]), ok. @@ -124,11 +220,10 @@ print_existing_versions(TargetNode) -> || {V,S} <- which_releases(TargetNode) ]), ?INFO("Installed versions:~n~s", [VerList]). -start_distribution(NodeName, NameTypeArg, Cookie) -> - MyNode = make_script_node(NodeName), +start_distribution(TargetNode, NameTypeArg, Cookie) -> + MyNode = make_script_node(TargetNode), {ok, _Pid} = net_kernel:start([MyNode, get_name_type(NameTypeArg)]), - erlang:set_cookie(node(), list_to_atom(Cookie)), - TargetNode = list_to_atom(NodeName), + erlang:set_cookie(node(), Cookie), case {net_kernel:connect_node(TargetNode), net_adm:ping(TargetNode)} of {true, pong} -> @@ -142,7 +237,7 @@ start_distribution(NodeName, NameTypeArg, Cookie) -> TargetNode. make_script_node(Node) -> - [Name, Host] = string:tokens(Node, "@"), + [Name, Host] = string:tokens(atom_to_list(Node), "@"), list_to_atom(lists:concat([Name, "_upgrader_", os:getpid(), "@", Host])). %% get name type from arg -- cgit v1.2.3