File 3922-ssh-Save-info-of-test-machine-s-installed-ssh.patch of Package erlang

From eeafe675b791931e91c6a7121dd5840bc0ba90ec Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Mon, 20 Dec 2021 11:28:49 +0100
Subject: [PATCH 2/3] ssh: Save info of test machine's installed ssh

The output is saved in <collect_host_info>/ssh_info/<hostname>.data
where <collect_host_info> is a common_test configuration variable.

Examples:
    {collect_host_info, "/my/local/dir"}.
    {collect_host_info, "hostname:/its/local/dir"}.
    {collect_host_info, "user@hostname:/their/local/dir"}.
---
 lib/ssh/test/Makefile                         |   1 +
 .../ssh_collect_labmachine_info_SUITE.erl     | 250 ++++++++++++++++++
 lib/ssh/test/ssh_compat_SUITE.erl             |  48 ++++
 3 files changed, 299 insertions(+)
 create mode 100644 lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl

diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index a3db492f0f..9f31dc92aa 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -32,6 +32,7 @@ MODULES= \
 	ssh_basic_SUITE \
 	ssh_bench_SUITE \
 	ssh_chan_behaviours_SUITE \
+	ssh_collect_labmachine_info_SUITE \
 	ssh_compat_SUITE \
 	ssh_connection_SUITE \
 	ssh_agent_mock_server \
diff --git a/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl b/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl
new file mode 100644
index 0000000000..02b11bde1d
--- /dev/null
+++ b/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl
@@ -0,0 +1,250 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2021. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_collect_labmachine_info_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([save_ssh_data/3]).
+
+-export([
+         suite/0,
+         all/0,
+         init_per_suite/1,
+         end_per_suite/1,
+         ssh_info_lib/1
+        ]).
+
+
+-define(DAYS_TO_KEEP, 5).
+
+save_ssh_data(Host, Data, Config0) ->
+    case init_data_transfer(Host, Config0) of
+        Config1 when is_list(Config1) ->
+            Config =
+                case Data of
+                    [[_|_]|_] ->
+                        lists:foldl(fun save_data/2, Config1, Data);
+                    _ ->
+                        save_data(Data, Config1)
+                end,
+            end_data_transfer(Config);
+
+        Skip ->
+            Skip
+    end.
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() -> [{timetrap,{seconds,40}}].
+
+all() -> [ssh_info_lib].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+    case os:find_executable("ssh") of
+        false ->
+            {skip, "No ssh found"};
+
+        _Path ->
+            init_data_transfer(hostname(), Config)
+    end.
+
+end_per_suite(Config) ->
+    end_data_transfer(Config).
+
+%%--------------------------------------------------------------------
+ssh_info_lib(Config) ->
+    NewEntry = new_entry(),
+    ct:pal("New entry:~n~p",[NewEntry]),
+    save_data(NewEntry, Config).
+
+new_entry() ->
+    [{hostname,           hostname()},
+     {type,               host},
+     {date,               date()},
+     {time,               time()},
+     {os_type,            os:type()},
+     {os_version,         os:version()},
+     {full_ssh_version,   ssh_info()}
+    ].
+
+ssh_info() ->
+    try os:cmd("ssh -V") of
+        Version when is_list(Version) -> Version--"\n";
+        _ -> "?"
+    catch
+        _:_ -> "??"
+    end.
+
+%%--------------------------------------------------------------------
+hostname() ->
+    case inet:gethostname() of
+	{ok,Name} -> string:to_lower(Name);
+	_ -> "undefined"
+    end.
+	    
+priv_dir(Config) -> proplists:get_value(priv_dir, Config).
+
+priv_file(Config, Name) -> filename:join(priv_dir(Config), Name).
+
+remove_drive_letter(FileName) ->
+    ssh_test_lib:winpath_to_linuxpath(FileName).
+
+usable_file(FileName) ->
+    case file:open(FileName, [append]) of
+        {ok,D} ->
+            ok == file:close(D);
+        _ ->
+            false
+    end.
+
+%%%----------------------------------------------------------------
+wsl_ify(Cmnd) ->
+    case os:getenv("WSLENV") of
+        false -> Cmnd;
+        _ -> "wsl " ++ Cmnd
+    end.
+
+%%%================================================================
+save_data(NewEntry, Config) ->
+    LocalFile = proplists:get_value(local_file, Config),
+
+    YoungEntries =
+        case file:consult(LocalFile) of
+            {ok, Consulted} when is_list(Consulted) ->
+                lists:filter(fun(E) -> is_young(E) end,
+                             Consulted);
+            Other ->
+                ct:log("Strange result of consult:~n~p", [Other]),
+                ct:fail("Consult failed")
+        end,
+
+    {ok,D} = file:open(LocalFile, [write]),
+    lists:foreach(fun(E) ->
+                          io:format(D, '~p.~n', [E])
+                  end, lists:usort([NewEntry|YoungEntries])),
+    file:close(D),
+    Config.
+
+
+is_young(E) ->
+    try
+        Days = days_ago(proplists:get_value(date, E)),
+        Days >= 0 andalso Days =< ?DAYS_TO_KEEP
+    catch
+        _:_ -> false                     % No or illegal date property
+    end.
+
+
+days_ago(D={_,_,_})->
+     calendar:date_to_gregorian_days(date()) - calendar:date_to_gregorian_days(D).
+
+%%%----------------------------------------------------------------
+init_data_transfer(Host, Config) ->
+    case ct:get_config(collect_host_info) of
+        undefined ->
+            {skip, "No 'collect_host_info' path configured"};
+
+        Root when is_list(Root) ->
+            RemoteFile = filename:join([Root, "ssh_info", Host++".data"]),
+            init_data_transfer_cont(Host, Config, RemoteFile)
+    end.
+
+init_data_transfer_cont(Host, Config, RemoteFile) ->
+    LocalFile = priv_file(Config, Host++".sshdata"),
+
+    case usable_file(LocalFile) of
+        false -> ct:fail(no_local_file);
+        true -> ok
+    end,
+
+    TransferType =
+        case {path_type(RemoteFile), os:type()} of
+            {local, {unix,_}} ->
+                case usable_file(RemoteFile) of
+                    true -> filesystem;
+                    false -> ssh
+                end;
+            _ ->
+                ssh
+        end,
+
+    case TransferType of
+        filesystem ->
+            %% 'filesystem' was concluded since it was possible
+            %% to open the file in append mode
+            {ok,B} = file:read_file(RemoteFile),
+            ok = file:write_file(LocalFile, B);
+        ssh ->
+            SCP = wsl_ify("scp "++RemoteFile++" "++remove_drive_letter(LocalFile)),
+            ct:pal("Run command: \"~s\"", [SCP]),
+            Result = os:cmd(SCP),
+            ct:pal("Command result: \"~s\"",[Result])
+    end,
+
+    [{transfer_type, TransferType},
+     {local_file,LocalFile},
+     {remote_file,RemoteFile} | Config].
+
+%%%----------------------------------------------------------------
+end_data_transfer(Config) ->
+    LocalFile = proplists:get_value(local_file,Config),
+    RemoteFile = proplists:get_value(remote_file,Config),
+    case proplists:get_value(transfer_type,Config) of
+        filesystem ->
+            {ok,B} = file:read_file(LocalFile),
+            ok = file:write_file(RemoteFile, B);
+        ssh ->
+            SCP = wsl_ify("scp "++remove_drive_letter(LocalFile)++" "++RemoteFile),
+            ct:pal("Run command: \"~s\"", [SCP]),
+            Result = os:cmd(SCP),
+            ct:pal("Command result: \"~s\"",[Result])
+    end,
+    file:delete(LocalFile).
+
+path_type(Path) ->
+    case string:lexemes(Path, ":") of
+        [_] ->
+            local;
+        [Host | _] ->
+            case string:find(Host, "/") of
+                nomatch -> remote;
+                _ -> local
+            end
+    end.
+
+
+
+
+
+
+
+
+
+
+
+
+
+    
diff --git a/lib/ssh/test/ssh_compat_SUITE.erl b/lib/ssh/test/ssh_compat_SUITE.erl
index bb46653657..a8f6b71488 100644
--- a/lib/ssh/test/ssh_compat_SUITE.erl
+++ b/lib/ssh/test/ssh_compat_SUITE.erl
@@ -98,6 +98,7 @@ init_per_suite(Config) ->
                {skip, "No docker"};
            _ ->
                ssh:start(),
+               log_image_versions(ssh_image_versions(), Config),
                ct:log("Crypto info: ~p",[crypto:info_lib()]),
                ct:log("ssh image versions: ~p",[ssh_image_versions()]),
                Config
@@ -1460,3 +1461,50 @@ renegotiate_test(Kex1, ConnectionRef) ->
             %% ct:log("Renegotiate test passed!",[]),
             ok
     end.
+
+%%%----------------------------------------------------------------
+%% ImageVersions = ['dropbearv2016.72',
+%%                  'openssh4.4p1-openssl0.9.8c',
+%%                  ...
+%%                  'openssh8.8p1-openssl1.1.1l']
+
+log_image_versions(ImageVersions, Config) ->
+    case true == (catch
+                      lists:member({save_ssh_data,3},
+                                   ssh_collect_labmachine_info_SUITE:module_info(exports)))
+    of
+        true ->
+            HostPfx = hostname()++"_docker",
+            {_Imax, Entries} = lists:foldl(fix_entry(HostPfx), {0,[]}, ImageVersions),
+            ssh_collect_labmachine_info_SUITE:save_ssh_data(HostPfx, Entries, Config);
+        false ->
+            Config
+    end.
+
+
+fix_entry(HostPfx) ->
+    fun(E, {I,Acc}) ->
+            Entry =
+                [{hostname,           lists:flatten(io_lib:format("~s:~2..0w",[HostPfx,I]))},
+                 {type,               compat_test},
+                 {date,               date()},
+                 {time,               time()},
+                 {os_type,            os:type()},
+                 {os_version,         os:version()},
+                 {full_ssh_version,   fix_version(E)}
+                ],
+            {I+1, [Entry|Acc]}
+    end.
+
+fix_version(E) ->
+    case string:tokens(atom_to_list(E), "-") of
+        ["openssh"++Vs, "openssl"++Vc ] -> lists:concat(["OpenSSH_",Vs," OpenSSL ",Vc]);
+        ["openssh"++Vs, "libressl"++Vc] -> lists:concat(["OpenSSH_",Vs," LibreSSL ",Vc]);
+        _ -> atom_to_list(E)
+    end.
+
+hostname() ->
+    case inet:gethostname() of
+	{ok,Name} -> string:to_lower(Name);
+	_ -> "undefined"
+    end.
-- 
2.35.3

openSUSE Build Service is sponsored by