Resurrect exceptions library
[integration/test.git] / csit / libraries / SSHKeywords.robot
1 *** Settings ***
2 Documentation       Resource enhancing SSHLibrary with Keywords used in multiple suites.
3 ...
4 ...                 Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
5 ...
6 ...                 This program and the accompanying materials are made available under the
7 ...                 terms of the Eclipse Public License v1.0 which accompanies this distribution,
8 ...                 and is available at http://www.eclipse.org/legal/epl-v10.html
9 ...
10 ...
11 ...                 Some suites evolved utility Keywords re-usable with other suites.
12 ...                 When the Keywords assume a SSH session is active,
13 ...                 and if the Keywords do not fit into a more specific Resource,
14 ...                 you can place them here.
15
16 Library             SSHLibrary
17 Resource            ${CURDIR}/Utils.robot
18 Resource            ../variables/Variables.robot
19
20
21 *** Variables ***
22 ${SSHKeywords__current_remote_working_directory}    .
23 ${SSHKeywords__current_venv_path}                   /tmp/defaultvenv
24 ${NETSTAT_COMMAND}                                  netstat -punta
25
26
27 *** Keywords ***
28 Open_Connection_To_ODL_System
29     [Documentation]    Open a connection to the ODL system at ${ip_address} and return its identifier.
30     [Arguments]    ${ip_address}=${ODL_SYSTEM_IP}    ${timeout}=10s
31     ${odl_connection} =    SSHLibrary.Open_Connection
32     ...    ${ip_address}
33     ...    prompt=${ODL_SYSTEM_PROMPT}
34     ...    timeout=${timeout}
35     Flexible_Controller_Login
36     RETURN    ${odl_connection}
37
38 Open_Connection_To_Tools_System
39     [Documentation]    Open a connection to the tools system at ${ip_address} and return its identifier.
40     [Arguments]    ${ip_address}=${TOOLS_SYSTEM_IP}    ${timeout}=10s    ${prompt}=${TOOLS_SYSTEM_PROMPT}
41     ${tools_connection} =    SSHLibrary.Open_Connection    ${ip_address}    prompt=${prompt}    timeout=${timeout}
42     Flexible_Mininet_Login
43     RETURN    ${tools_connection}
44
45 Restore_Current_Ssh_Connection_From_Index
46     [Documentation]    Restore active SSH connection in SSHLibrary to given index.
47     ...
48     ...    Restore the currently active connection state in
49     ...    SSHLibrary to match the state returned by "Switch
50     ...    Connection" or "Get Connection". More specifically makes
51     ...    sure that there will be no active connection when the
52     ...    \${connection_index} reported by these means is None.
53     ...
54     ...    There is a misfeature in SSHLibrary: Invoking "SSHLibrary.Switch_Connection"
55     ...    and passing None as the "index_or_alias" argument to it has exactly the
56     ...    same effect as invoking "Close Connection".
57     ...    https://github.com/robotframework/SSHLibrary/blob/master/src/SSHLibrary/library.py#L560
58     ...
59     ...    We want to have Keyword which will "switch out" to previous
60     ...    "no connection active" state without killing the background one.
61     ...
62     ...    As some suites may hypothetically rely on non-writability of active connection,
63     ...    workaround is applied by opening and closing temporary connection.
64     ...    Unfortunately this will fail if run on Jython and there is no SSH server
65     ...    running on localhost, port 22 but there is nothing easy that can be done about it.
66     [Arguments]    ${connection_index}
67     BuiltIn.Run Keyword And Return If
68     ...    ${connection_index} is not None
69     ...    SSHLibrary.Switch Connection
70     ...    ${connection_index}
71     # The background connection is still current, bury it.
72     SSHLibrary.Open Connection    127.0.0.1
73     SSHLibrary.Close Connection
74
75 Run_Keyword_Preserve_Connection
76     [Documentation]    Store current connection index, run keyword returning its result, restore connection in teardown.
77     ...    Note that in order to avoid "got positional argument after named arguments", it is safer to use positional (not named) arguments on call.
78     [Arguments]    ${keyword_name}    @{args}    &{kwargs}
79     ${current_connection} =    SSHLibrary.Get_Connection
80     BuiltIn.Run_Keyword_And_Return    ${keyword_name}    @{args}    &{kwargs}
81     # Resource name has to be prepended, as KarafKeywords still contains a redirect.
82     [Teardown]    SSHKeywords.Restore_Current_SSH_Connection_From_Index    ${current_connection.index}
83
84 Run_Keyword_With_Ssh
85     [Documentation]    Open temporary connection to given IP address, run keyword, close connection, restore previously active connection, return result.
86     [Arguments]    ${ip_address}    ${keyword_name}    @{args}    &{kwargs}
87     Run_Keyword_Preserve_Connection
88     ...    Run_Unsafely_Keyword_Over_Temporary_Odl_Session
89     ...    ${ip_address}
90     ...    ${keyword_name}
91     ...    @{args}
92     ...    &{kwargs}
93
94 Run_Unsafely_Keyword_Over_Temporary_Odl_Session
95     [Documentation]    Open connection to given IP address, run keyword, close connection, return result.
96     ...    This is unsafe in the sense that previously active session will be switched out off, but safe in the sense only the temporary connection is closed.
97     [Arguments]    ${ip_address}    ${keyword_name}    @{args}    &{kwargs}
98     Open_Connection_To_ODL_System    ${ip_address}
99     # Not using Teardown, to avoid a call to close if the previous line fails.
100     ${status}    ${result} =    BuiltIn.Run_Keyword_And_Ignore_Error    ${keyword_name}    @{args}    &{kwargs}
101     SSHLibrary.Close_Connection
102     IF    "${status}" == "PASS"    RETURN    ${result}
103     BuiltIn.Fail    ${result}
104
105 Log_Command_Results
106     [Documentation]    Log everything returned by SSHLibrary.Execute_Command
107     [Arguments]    ${stdout}    ${stderr}    ${rc}
108     BuiltIn.Log    ${stdout}
109     BuiltIn.Log    ${stderr}
110     BuiltIn.Log    ${rc}
111
112 Execute_Command_Passes
113     [Documentation]    Execute command via the active SSH connection. For success, rc has to be zero and optionally stderr has to be empty.
114     ...    Log everything, depending on arguments and success. Return either success string or stdout.
115     ...    TODO: Do we want to support customizing return values the same way as SSHLibrary.Execute_Command does?
116     [Arguments]    ${command}    ${return_success_only}=True    ${log_on_success}=False    ${log_on_failure}=True    ${stderr_must_be_empty}=False
117     ${stdout}    ${stderr}    ${rc} =    SSHLibrary.Execute_Command
118     ...    ${command}
119     ...    return_stderr=True
120     ...    return_rc=True
121     ${emptiness_status}    ${result} =    BuiltIn.Run_Keyword_And_Ignore_Error    BuiltIn.Should_Be_Empty    ${stderr}
122     ${success} =    BuiltIn.Set_Variable_If
123     ...    (${rc} == 0) and (("${emptiness_status}" == "PASS") or not ${stderr_must_be_empty})
124     ...    True
125     ...    False
126     IF    (${log_on_success} and ${success}) or (${log_on_failure} and not ${success})
127         Log_Command_Results    ${stdout}    ${stderr}    ${rc}
128     END
129     IF    ${return_success_only}    RETURN    ${success}
130     IF    ${success}    RETURN    ${stdout}
131     BuiltIn.Fail    Got rc: ${rc} or stderr was not empty: ${stderr}
132
133 Execute_Command_Should_Pass
134     [Documentation]    A wrapper for Execute_Command_Passes with return_success_only=False
135     ...    Also, log_on_success defaults to True (but is customizable, unlike return_success_only)..
136     [Arguments]    ${command}    ${log_on_success}=True    ${log_on_failure}=True    ${stderr_must_be_empty}=False
137     BuiltIn.Run_Keyword_And_Return
138     ...    Execute_Command_Passes
139     ...    ${command}
140     ...    return_success_only=False
141     ...    log_on_success=${log_on_success}
142     ...    log_on_failure=${log_on_failure}
143     ...    stderr_must_be_empty=${stderr_must_be_empty}
144
145 Execute_Command_At_Path_Should_Pass
146     [Documentation]    A keyword similar to Execute_Command_Should_Pass which performs "cd" to ${path} before executing the ${command}.
147     ...    This is useful when rewriting bash scripts, as series of SSHLibrary.Execute_Command do not share current working directory.
148     ...    TODO: Perhaps a Keyword which sets up environment variables would be useful as well.
149     [Arguments]    ${command}    ${path}=None    ${log_on_success}=True    ${log_on_failure}=True    ${stderr_must_be_empty}=False
150     ${cd_and_command} =    BuiltIn.Set_Variable    cd '${path}' && ${command}
151     BuiltIn.Run_Keyword_And_Return
152     ...    Execute_Command_Passes
153     ...    ${cd_and_command}
154     ...    return_success_only=False
155     ...    log_on_success=${log_on_success}
156     ...    log_on_failure=${log_on_failure}
157     ...    stderr_must_be_empty=${stderr_must_be_empty}
158
159 Set_Cwd
160     [Documentation]    Set \${SSHKeywords__current_remote_working_directory} variable to ${path}. If SSH default is desired, use dot.
161     [Arguments]    ${path}
162     BuiltIn.Set_Suite_Variable    \${SSHKeywords__current_remote_working_directory}    ${path}
163
164 Execute_Command_At_Cwd_Should_Pass
165     [Documentation]    Run Execute_Command_At_Path_Should_Pass with previously set CWD as path.
166     [Arguments]    ${command}    ${log_on_success}=True    ${log_on_failure}=True    ${stderr_must_be_empty}=True
167     BuiltIn.Run_Keyword_And_Return
168     ...    Execute_Command_At_Path_Should_Pass
169     ...    command=${command}
170     ...    path=${SSHKeywords__current_remote_working_directory}
171     ...    log_on_success=${log_on_success}
172     ...    log_on_failure=${log_on_failure}
173     ...    stderr_must_be_empty=${stderr_must_be_empty}
174
175 Require_Python
176     [Documentation]    Verify current SSH connection leads to machine with python working. Fatal fail otherwise.
177     ${passed} =    Execute_Command_Passes    python3 --help
178     IF    ${passed}    RETURN
179     BuiltIn.Fatal_Error    Python 3 is not installed!
180
181 Assure_Library_Ipaddr
182     [Documentation]    Tests whether ipaddr module is present on ssh-connected machine, Puts ipaddr.py to target_dir if not.
183     [Arguments]    ${target_dir}=.
184     ${passed} =    Execute_Command_Passes    bash -c 'cd "${target_dir}" && python -c "import ipaddr"'
185     IF    ${passed}    RETURN
186     SSHLibrary.Put_File    ${CURDIR}/BGPCEP/ipaddr.py    ${target_dir}/
187
188 Assure_Library_Counter
189     [Documentation]    Tests whether Counter is present in collections on ssh-connected machine, Puts Counter.py to workspace if not.
190     [Arguments]    ${target_dir}=.
191     ${passed} =    Execute_Command_Passes
192     ...    bash -c 'cd "${target_dir}" && python -c "from collections import Counter"'
193     # TODO: Move the bash-cd wrapper to separate keyword?
194     IF    ${passed}    RETURN
195     SSHLibrary.Put_File    ${CURDIR}/Counter.py    ${target_dir}/
196
197 Count_Port_Occurences
198     [Documentation]    Run 'netstat' on the remote machine and count occurences of given port in the given state connected to process with the given name.
199     [Arguments]    ${port}    ${state}    ${name}
200     ${output} =    SSHLibrary.Execute_Command
201     ...    ${NETSTAT_COMMAND} 2> /dev/null | grep -E ":${port} .+ ${state} .+${name}" | wc -l
202     RETURN    ${output}
203
204 Virtual_Env_Set_Path
205     [Documentation]    Set \${SSHKeywords__current_venv_path} variable to ${venv_path}. Path should be absolute.
206     [Arguments]    ${venv_path}
207     BuiltIn.Set_Global_Variable    \${SSHKeywords__current_venv_path}    ${venv_path}
208
209 Virtual_Env_Create
210     [Documentation]    Creates virtual env. If not to use the default name, use Virtual_Env_Set_Path kw. Returns stdout.
211     [Arguments]    ${upgrade_pip}=True
212     Execute_Command_At_Cwd_Should_Pass    virtualenv ${SSHKeywords__current_venv_path}
213     BuiltIn.Run_Keyword_And_Return_If
214     ...    ${upgrade_pip}
215     ...    Virtual_Env_Run_Cmd_At_Cwd
216     ...    pip install --upgrade pip
217     ...    stderr_must_be_empty=False
218
219 Virtual_Env_Create_Python3
220     [Documentation]    Creates virtual env. If not to use the default name, use Virtual_Env_Set_Path kw. Returns stdout.
221     [Arguments]    ${upgrade_pip}=True
222     Execute_Command_At_Cwd_Should_Pass    python3 -m venv ${SSHKeywords__current_venv_path}
223     BuiltIn.Run_Keyword_And_Return_If
224     ...    ${upgrade_pip}
225     ...    Virtual_Env_Run_Cmd_At_Cwd
226     ...    pip install --upgrade pip
227     ...    stderr_must_be_empty=False
228
229 Virtual_Env_Delete
230     [Documentation]    Deletes a directory with virtual env.
231     Execute_Command_At_Cwd_Should_Pass    rm -rf ${SSHKeywords__current_venv_path}
232
233 Virtual_Env_Run_Cmd_At_Cwd
234     [Documentation]    Runs given command within activated virtual env and returns stdout.
235     [Arguments]    ${cmd}    ${log_on_success}=True    ${log_on_failure}=True    ${stderr_must_be_empty}=True
236     BuiltIn.Run_Keyword_And_Return
237     ...    Execute_Command_At_Cwd_Should_Pass
238     ...    source ${SSHKeywords__current_venv_path}/bin/activate; ${cmd}; deactivate
239     ...    log_on_success=${log_on_success}
240     ...    log_on_failure=${log_on_failure}
241     ...    stderr_must_be_empty=${stderr_must_be_empty}
242
243 Virtual_Env_Install_Package
244     [Documentation]    Installs python package into virtual env. Use with version if needed (e.g. exabgp==3.4.16). Returns stdout.
245     [Arguments]    ${package}
246     BuiltIn.Run_Keyword_And_Return
247     ...    Virtual_Env_Run_Cmd_At_Cwd
248     ...    pip install ${package}
249     ...    stderr_must_be_empty=False
250
251 Virtual_Env_Uninstall_Package
252     [Documentation]    Uninstalls python package from virtual env and returns stdout.
253     [Arguments]    ${package}
254     BuiltIn.Run_Keyword_And_Return
255     ...    Virtual_Env_Run_Cmd_At_Cwd
256     ...    pip uninstall -y ${package}
257     ...    stderr_must_be_empty=False
258
259 Virtual_Env_Freeze
260     [Documentation]    Shows installed packages within the returned stdout.
261     BuiltIn.Run_Keyword_And_Return    Virtual_Env_Run_Cmd_At_Cwd    pip freeze --all    stderr_must_be_empty=False
262
263 Virtual_Env_Activate_On_Current_Session
264     [Documentation]    Activates virtual environment. To run anything in the env activated this way you should use SSHLibrary.Write and Read commands.
265     [Arguments]    ${log_output}=${False}
266     SSHLibrary.Write    source ${SSHKeywords__current_venv_path}/bin/activate
267     ${output} =    SSHLibrary.Read_Until_Prompt
268     IF    ${log_output}==${True}    BuiltIn.Log    ${output}
269
270 Virtual_Env_Deactivate_On_Current_Session
271     [Documentation]    Deactivates virtual environment.
272     [Arguments]    ${log_output}=${False}
273     SSHLibrary.Write    deactivate
274     ${output} =    SSHLibrary.Read_Until_Prompt
275     IF    ${log_output}==${True}    BuiltIn.Log    ${output}
276
277 Unsafe_Copy_File_To_Remote_System
278     [Documentation]    Copy the ${source} file to the ${destination} file on the remote ${system}. The keyword opens and closes a single
279     ...    ssh connection and does not rely on any existing ssh connection that may be open.
280     [Arguments]    ${system}    ${source}    ${destination}=./    ${user}=${DEFAULT_USER}    ${password}=${DEFAULT_PASSWORD}    ${prompt}=${DEFAULT_LINUX_PROMPT}
281     ...    ${prompt_timeout}=5s
282     SSHLibrary.Open_Connection    ${system}    prompt=${prompt}    timeout=${prompt_timeout}
283     Flexible_SSH_Login    ${user}    ${password}
284     SSHLibrary.Put_File    ${source}    ${destination}
285     SSHLibrary.Close Connection
286
287 Copy_File_To_Remote_System
288     [Documentation]    Copy the ${source} file to the ${destination} file on the remote ${system}. Any pre-existing active
289     ...    ssh connection will be retained.
290     [Arguments]    ${system}    ${source}    ${destination}=./    ${user}=${DEFAULT_USER}    ${password}=${DEFAULT_PASSWORD}    ${prompt}=${DEFAULT_LINUX_PROMPT}
291     ...    ${prompt_timeout}=5s
292     SSHKeywords.Run_Keyword_Preserve_Connection
293     ...    SSHKeywords.Unsafe_Copy_File_To_Remote_System
294     ...    ${system}
295     ...    ${source}
296     ...    ${destination}
297     ...    ${user}
298     ...    ${password}
299     ...    ${prompt}
300     ...    ${prompt_timeout}
301
302 Copy_File_To_Odl_System
303     [Documentation]    Wrapper keyword to make it easier to copy a file to an ODL specific system
304     [Arguments]    ${system}    ${source}    ${destination}=./
305     SSHKeywords.Copy_File_To_Remote_System
306     ...    ${system}
307     ...    ${source}
308     ...    ${destination}
309     ...    ${ODL_SYSTEM_USER}
310     ...    ${ODL_SYSTEM_PASSWORD}
311     ...    ${ODL_SYSTEM_PROMPT}
312
313 Copy_File_To_Tools_System
314     [Documentation]    Wrapper keyword to make it easier to copy a file to an Tools specific system
315     [Arguments]    ${system}    ${source}    ${destination}=./
316     SSHKeywords.Copy_File_To_Remote_System
317     ...    ${system}
318     ...    ${source}
319     ...    ${destination}
320     ...    ${TOOLS_SYSTEM_USER}
321     ...    ${TOOLS_SYSTEM_PASSWORD}
322     ...    ${TOOLS_SYSTEM_PROMPT}
323
324 Flexible_SSH_Login
325     [Documentation]    On active SSH session: if given non-empty password, do Login, else do Login With Public Key.
326     [Arguments]    ${user}    ${password}=${EMPTY}    ${delay}=0.5s
327     ${pwd_length} =    BuiltIn.Get Length    ${password}
328     # ${pwd_length} is guaranteed to be an integer, so we are safe to evaluate it as Python expression.
329     BuiltIn.Run Keyword And Return If
330     ...    ${pwd_length} > 0
331     ...    SSHLibrary.Login
332     ...    ${user}
333     ...    ${password}
334     ...    delay=${delay}
335     BuiltIn.Run Keyword And Return
336     ...    SSHLibrary.Login With Public Key
337     ...    ${user}
338     ...    ${USER_HOME}/.ssh/${SSH_KEY}
339     ...    ${KEYFILE_PASS}
340     ...    delay=${delay}
341
342 Flexible_Mininet_Login
343     [Documentation]    Call Flexible SSH Login, but with default values suitable for Mininet machine.
344     [Arguments]    ${user}=${TOOLS_SYSTEM_USER}    ${password}=${TOOLS_SYSTEM_PASSWORD}    ${delay}=0.5s
345     BuiltIn.Run Keyword And Return    Flexible SSH Login    user=${user}    password=${password}    delay=${delay}
346
347 Flexible_Controller_Login
348     [Documentation]    Call Flexible SSH Login, but with default values suitable for Controller machine.
349     [Arguments]    ${user}=${ODL_SYSTEM_USER}    ${password}=${ODL_SYSTEM_PASSWORD}    ${delay}=0.5s
350     BuiltIn.Run Keyword And Return    Flexible SSH Login    user=${user}    password=${password}    delay=${delay}
351
352 Move_File_To_Remote_System
353     [Documentation]    Moves the ${source} file to the ${destination} file on the remote ${system}. Any pre-existing active
354     ...    ssh connection will be retained.
355     [Arguments]    ${system}    ${source}    ${destination}=./    ${user}=${DEFAULT_USER}    ${password}=${DEFAULT_PASSWORD}    ${prompt}=${DEFAULT_LINUX_PROMPT}
356     ...    ${prompt_timeout}=5s
357     SSHKeywords.Run_Keyword_Preserve_Connection
358     ...    Unsafe_Move_File_To_Remote_System
359     ...    ${system}
360     ...    ${source}
361     ...    ${destination}
362     ...    ${user}
363     ...    ${password}
364     ...    ${prompt}
365     ...    ${prompt_timeout}
366
367 Unsafe_Move_File_To_Remote_System
368     [Documentation]    Moves the ${source} file to the ${destination} file on the remote ${system}. The keyword opens and closes a single
369     ...    ssh connection and does not rely on any existing ssh connection that may be open.
370     [Arguments]    ${system}    ${source}    ${destination}=./    ${user}=${DEFAULT_USER}    ${password}=${DEFAULT_PASSWORD}    ${prompt}=${DEFAULT_LINUX_PROMPT}
371     ...    ${prompt_timeout}=5s
372     SSHLibrary.Open_Connection    ${system}    prompt=${prompt}    timeout=${prompt_timeout}
373     Flexible_SSH_Login    ${user}    ${password}
374     SSHLibrary.Put File    ${source}    ${destination}
375     OperatingSystem.Remove File    ${source}
376     SSHLibrary.Close Connection