1*** Settings ***
2Resource                ../lib/utils.robot
3Resource                ../lib/connection_client.robot
4Resource                ../lib/boot_utils.robot
5Library                 ../lib/gen_misc.py
6Library                 ../lib/utils.py
7Library                 ../lib/bmc_network_utils.py
8
9*** Variables ***
10# MAC input from user.
11${MAC_ADDRESS}          ${EMPTY}
12
13
14*** Keywords ***
15
16Check And Reset MAC
17    [Documentation]  Update BMC with user input MAC address.
18    [Arguments]  ${mac_address}=${MAC_ADDRESS}
19
20    # Description of argument(s):
21    # mac_address  The mac address (e.g. 00:01:6c:80:02:28).
22
23    Should Not Be Empty  ${mac_address}
24    Open Connection And Log In
25    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
26    ...  cat /sys/class/net/eth0/address
27    Run Keyword If  '${mac_address.lower()}' != '${bmc_mac_addr.lower()}'
28    ...  Set MAC Address
29
30
31Set MAC Address
32    [Documentation]  Update eth0 with input MAC address.
33    [Arguments]  ${mac_address}=${MAC_ADDRESS}
34
35    # Description of argument(s):
36    # mac_address  The mac address (e.g. 00:01:6c:80:02:28).
37
38    Write  fw_setenv ethaddr ${mac_address}
39    OBMC Reboot (off)
40
41    # Take SSH session post BMC reboot.
42    Open Connection And Log In
43    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
44    ...  cat /sys/class/net/eth0/address
45    Should Be Equal  ${bmc_mac_addr}  ${mac_address}  ignore_case=True
46
47
48Get BMC IP Info
49    [Documentation]  Get system IP address and prefix length.
50
51
52    # Get system IP address and prefix length details using "ip addr"
53    # Sample Output of "ip addr":
54    # 1: eth0: <BROADCAST,MULTIAST> mtu 1500 qdisc mq state UP qlen 1000
55    #     link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
56    #     inet xx.xx.xx.xx/24 brd xx.xx.xx.xx scope global eth0
57
58    ${active_channel_config}=  Get Active Channel Config
59    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
60    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
61    ...  /sbin/ip addr | grep ${ethernet_interface}
62
63    # Get line having IP address details.
64    ${lines}=  Get Lines Containing String  ${cmd_output}  inet
65
66    # List IP address details.
67    @{ip_components}=  Split To Lines  ${lines}
68
69    @{ip_data}=  Create List
70
71    # Get all IP addresses and prefix lengths on system.
72    FOR  ${ip_component}  IN  @{ip_components}
73      @{if_info}=  Split String  ${ip_component}
74      ${ip_n_prefix}=  Get From List  ${if_info}  1
75      Append To List  ${ip_data}  ${ip_n_prefix}
76    END
77
78    [Return]  ${ip_data}
79
80Get BMC Route Info
81    [Documentation]  Get system route info.
82
83
84    # Sample output of "ip route":
85    # default via xx.xx.xx.x dev eth0
86    # xx.xx.xx.0/23 dev eth0  src xx.xx.xx.xx
87    # xx.xx.xx.0/24 dev eth0  src xx.xx.xx.xx
88
89    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
90    ...  /sbin/ip route
91
92    [Return]  ${cmd_output}
93
94# TODO: openbmc/openbmc-test-automation#1331
95Get BMC MAC Address
96    [Documentation]  Get system MAC address.
97
98
99    # Sample output of "ip addr | grep ether":
100    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
101
102    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
103    ...  /sbin/ip addr | grep ether
104
105    # Split the line and return MAC address.
106    # Split list data:
107    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
108
109    @{words}=  Split String  ${cmd_output}
110
111    [Return]  ${words[1]}
112
113
114Get BMC MAC Address List
115    [Documentation]  Get system MAC address
116
117    # Sample output of "ip addr | grep ether":
118    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
119
120    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
121    ...  /sbin/ip addr | grep ether
122
123    # Split the line and return MAC address.
124    # Split list data:
125    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
126    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
127
128    ${mac_list}=  Create List
129    @{lines}=  Split To Lines  ${cmd_output}
130    FOR  ${line}  IN  @{lines}
131      @{words}=  Split String  ${line}
132      Append To List  ${mac_list}  ${words[1]}
133    END
134
135    [Return]  ${mac_list}
136
137Get BMC Hostname
138    [Documentation]  Get BMC hostname.
139
140    # Sample output of  "hostname":
141    # test_hostname
142
143    ${output}  ${stderr}  ${rc}=  BMC Execute Command  hostname
144
145    [Return]  ${output}
146
147Get List Of IP Address Via REST
148    [Documentation]  Get list of IP address via REST.
149    [Arguments]  @{ip_uri_list}
150
151    # Description of argument(s):
152    # ip_uri_list  List of IP objects.
153    # Example:
154    #   "data": [
155    #     "/xyz/openbmc_project/network/eth0/ipv4/e9767624",
156    #     "/xyz/openbmc_project/network/eth0/ipv4/31f4ce8b"
157    #   ],
158
159    ${ip_list}=  Create List
160
161    FOR  ${ip_uri}  IN  @{ip_uri_list}
162      ${ip_addr}=  Read Attribute  ${ip_uri}  Address
163      Append To List  ${ip_list}  ${ip_addr}
164    END
165
166    [Return]  @{ip_list}
167
168Delete IP And Object
169    [Documentation]  Delete IP and object.
170    [Arguments]  ${ip_addr}  @{ip_uri_list}
171
172    # Description of argument(s):
173    # ip_addr      IP address to be deleted.
174    # ip_uri_list  List of IP object URIs.
175
176    # Find IP object having this IP address.
177
178     FOR  ${ip_uri}  IN  @{ip_uri_list}
179       ${ip_addr1}=  Read Attribute  ${ip_uri}  Address
180       Run Keyword If  '${ip_addr}' == '${ip_addr1}'  Exit For Loop
181     END
182
183    # If the given IP address is not configured, return.
184    # Otherwise, delete the IP and object.
185
186    Run Keyword And Return If  '${ip_addr}' != '${ip_addr1}'
187    ...  Pass Execution  IP address to be deleted is not configured.
188
189    Run Keyword And Ignore Error  OpenBMC Delete Request  ${ip_uri}
190
191    # After any modification on network interface, BMC restarts network
192    # module, wait until it is reachable. Then wait 15 seconds for new
193    # configuration to be updated on BMC.
194
195    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
196    ...  ${NETWORK_RETRY_TIME}
197    Sleep  15s
198
199    # Verify whether deleted IP address is removed from BMC system.
200
201    ${ip_data}=  Get BMC IP Info
202    Should Not Contain Match  ${ip_data}  ${ip_addr}*
203    ...  msg=IP address not deleted.
204
205Get First Non Pingable IP From Subnet
206    [Documentation]  Find first non-pingable IP from the subnet and return it.
207    [Arguments]  ${host}=${OPENBMC_HOST}
208
209    # Description of argument(s):
210    # host  Any valid host name or IP address
211    #       (e.g. "machine1" or "9.xx.xx.31").
212
213    # Non-pingable IP is unused IP address in the subnet.
214    ${host_name}  ${ip_addr}=  Get Host Name IP
215
216    # Split IP address into network part and host part.
217    # IP address will have 4 octets xx.xx.xx.xx.
218    # Sample output after split:
219    # split_ip  [xx.xx.xx, xx]
220
221    ${split_ip}=  Split String From Right  ${ip_addr}  .  1
222    # First element in list is Network part.
223    ${network_part}=  Get From List  ${split_ip}  0
224
225    FOR  ${octet4}  IN RANGE  1  255
226      ${new_ip}=  Catenate  ${network_part}.${octet4}
227      ${status}=  Run Keyword And Return Status  Ping Host  ${new_ip}
228      # If IP is non-pingable, return it.
229      Return From Keyword If  '${status}' == 'False'  ${new_ip}
230    END
231
232    Fail  msg=No non-pingable IP could be found in subnet ${network_part}.
233
234
235Validate MAC On BMC
236    [Documentation]  Validate MAC on BMC.
237    [Arguments]  ${mac_addr}
238
239    # Description of argument(s):
240    # mac_addr  MAC address of the BMC.
241
242    ${system_mac}=  Get BMC MAC Address
243
244    ${status}=  Compare MAC Address  ${system_mac}  ${mac_addr}
245    Should Be True  ${status}
246    ...  msg=MAC address ${system_mac} does not match ${mac_addr}.
247
248
249Run Build Net
250    [Documentation]  Run build_net to preconfigure the ethernet interfaces.
251
252    OS Execute Command  build_net help y y
253    # Run pingum to check if the "build_net" was run correctly done.
254    ${output}  ${stderr}  ${rc}=  OS Execute Command  pingum
255    Should Contain  ${output}  All networks ping Ok
256
257
258Configure Hostname
259    [Documentation]  Configure hostname on BMC via Redfish.
260    [Arguments]  ${hostname}
261
262    # Description of argument(s):
263    # hostname  A hostname value which is to be configured on BMC.
264
265    ${data}=  Create Dictionary  HostName=${hostname}
266    Redfish.patch  ${REDFISH_NW_PROTOCOL_URI}  body=&{data}
267    ...  valid_status_codes=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
268
269
270Verify IP On BMC
271    [Documentation]  Verify IP on BMC.
272    [Arguments]  ${ip}
273
274    # Description of argument(s):
275    # ip  IP address to be verified (e.g. "10.7.7.7").
276
277    # Get IP address details on BMC using IP command.
278    @{ip_data}=  Get BMC IP Info
279    Should Contain Match  ${ip_data}  ${ip}/*
280    ...  msg=IP address does not exist.
281
282
283Verify Gateway On BMC
284    [Documentation]  Verify gateway on BMC.
285    [Arguments]  ${gateway_ip}=0.0.0.0
286
287    # Description of argument(s):
288    # gateway_ip  Gateway IP address.
289
290    ${route_info}=  Get BMC Route Info
291
292    # If gateway IP is empty or 0.0.0.0 it will not have route entry.
293
294    Run Keyword If  '${gateway_ip}' == '0.0.0.0'
295    ...      Pass Execution  Gateway IP is "0.0.0.0".
296    ...  ELSE
297    ...      Should Contain  ${route_info}  ${gateway_ip}
298    ...      msg=Gateway IP address not matching.
299
300
301Get BMC DNS Info
302    [Documentation]  Get system DNS info.
303
304
305    # Sample output of "resolv.conf":
306    # ### Generated manually via dbus settings ###
307    # nameserver 8.8.8.8
308
309    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
310    ...  cat /etc/resolv.conf
311
312    [Return]  ${cmd_output}
313
314
315CLI Get Nameservers
316    [Documentation]  Get the nameserver IPs from /etc/resolv.conf and return as a list.
317
318    # Example of /etc/resolv.conf data:
319    # nameserver x.x.x.x
320    # nameserver y.y.y.y
321
322    ${stdout}  ${stderr}  ${rc}=  BMC Execute Command  egrep nameserver /etc/resolv.conf | cut -f2- -d ' '
323    ${nameservers}=  Split String  ${stdout}
324
325    [Return]  ${nameservers}
326
327
328Get Network Configuration
329    [Documentation]  Get network configuration.
330    # Sample output:
331    #{
332    #  "@odata.context": "/redfish/v1/$metadata#EthernetInterface.EthernetInterface",
333    #  "@odata.id": "/redfish/v1/Managers/bmc/EthernetInterfaces/eth0",
334    #  "@odata.type": "#EthernetInterface.v1_2_0.EthernetInterface",
335    #  "Description": "Management Network Interface",
336    #  "IPv4Addresses": [
337    #    {
338    #      "Address": "169.254.xx.xx",
339    #      "AddressOrigin": "IPv4LinkLocal",
340    #      "Gateway": "0.0.0.0",
341    #      "SubnetMask": "255.255.0.0"
342    #    },
343    #    {
344    #      "Address": "xx.xx.xx.xx",
345    #      "AddressOrigin": "Static",
346    #      "Gateway": "xx.xx.xx.1",
347    #      "SubnetMask": "xx.xx.xx.xx"
348    #    }
349    #  ],
350    #  "Id": "eth0",
351    #  "MACAddress": "xx:xx:xx:xx:xx:xx",
352    #  "Name": "Manager Ethernet Interface",
353    #  "SpeedMbps": 0,
354    #  "VLAN": {
355    #    "VLANEnable": false,
356    #    "VLANId": 0
357    #  }
358
359
360    ${active_channel_config}=  Get Active Channel Config
361    ${resp}=  Redfish.Get  ${REDFISH_NW_ETH_IFACE}${active_channel_config['${CHANNEL_NUMBER}']['name']}
362
363    @{network_configurations}=  Get From Dictionary  ${resp.dict}  IPv4StaticAddresses
364    [Return]  @{network_configurations}
365
366
367Add IP Address
368    [Documentation]  Add IP Address To BMC.
369    [Arguments]  ${ip}  ${subnet_mask}  ${gateway}
370    ...  ${valid_status_codes}=${HTTP_OK}
371
372    # Description of argument(s):
373    # ip                  IP address to be added (e.g. "10.7.7.7").
374    # subnet_mask         Subnet mask for the IP to be added
375    #                     (e.g. "255.255.0.0").
376    # gateway             Gateway for the IP to be added (e.g. "10.7.7.1").
377    # valid_status_codes  Expected return code from patch operation
378    #                     (e.g. "200").  See prolog of rest_request
379    #                     method in redfish_plus.py for details.
380
381    ${empty_dict}=  Create Dictionary
382    ${ip_data}=  Create Dictionary  Address=${ip}
383    ...  SubnetMask=${subnet_mask}  Gateway=${gateway}
384
385    ${patch_list}=  Create List
386    ${network_configurations}=  Get Network Configuration
387    ${num_entries}=  Get Length  ${network_configurations}
388
389    FOR  ${INDEX}  IN RANGE  0  ${num_entries}
390      Append To List  ${patch_list}  ${empty_dict}
391    END
392
393    # We need not check for existence of IP on BMC while adding.
394    Append To List  ${patch_list}  ${ip_data}
395    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
396
397    ${active_channel_config}=  Get Active Channel Config
398    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
399
400    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
401    ...  valid_status_codes=[${valid_status_codes}]
402
403    Return From Keyword If  '${valid_status_codes}' != '${HTTP_OK}'
404
405    # Note: Network restart takes around 15-18s after patch request processing.
406    Sleep  ${NETWORK_TIMEOUT}s
407    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
408
409    Verify IP On BMC  ${ip}
410    Validate Network Config On BMC
411
412
413Delete IP Address
414    [Documentation]  Delete IP Address Of BMC.
415    [Arguments]  ${ip}  ${valid_status_codes}=${HTTP_OK}
416
417    # Description of argument(s):
418    # ip                  IP address to be deleted (e.g. "10.7.7.7").
419    # valid_status_codes  Expected return code from patch operation
420    #                     (e.g. "200").  See prolog of rest_request
421    #                     method in redfish_plus.py for details.
422
423    ${empty_dict}=  Create Dictionary
424    ${patch_list}=  Create List
425
426    @{network_configurations}=  Get Network Configuration
427    FOR  ${network_configuration}  IN  @{network_configurations}
428      Run Keyword If  '${network_configuration['Address']}' == '${ip}'
429      ...  Append To List  ${patch_list}  ${null}
430      ...  ELSE  Append To List  ${patch_list}  ${empty_dict}
431    END
432
433    ${ip_found}=  Run Keyword And Return Status  List Should Contain Value
434    ...  ${patch_list}  ${null}  msg=${ip} does not exist on BMC
435    Pass Execution If  ${ip_found} == ${False}  ${ip} does not exist on BMC
436
437    # Run patch command only if given IP is found on BMC
438    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
439
440    ${active_channel_config}=  Get Active Channel Config
441    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
442
443    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
444    ...  valid_status_codes=[${valid_status_codes}]
445
446    # Note: Network restart takes around 15-18s after patch request processing
447    Sleep  ${NETWORK_TIMEOUT}s
448    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
449
450    ${delete_status}=  Run Keyword And Return Status  Verify IP On BMC  ${ip}
451    Run Keyword If  '${valid_status_codes}' == '${HTTP_OK}'
452    ...  Should Be True  '${delete_status}' == '${False}'
453    ...  ELSE  Should Be True  '${delete_status}' == '${True}'
454
455    Validate Network Config On BMC
456
457
458Validate Network Config On BMC
459    [Documentation]  Check that network info obtained via redfish matches info
460    ...              obtained via CLI.
461
462    @{network_configurations}=  Get Network Configuration
463    ${ip_data}=  Get BMC IP Info
464    FOR  ${network_configuration}  IN  @{network_configurations}
465      Should Contain Match  ${ip_data}  ${network_configuration['Address']}/*
466      ...  msg=IP address does not exist.
467    END
468
469
470Create VLAN
471    [Documentation]  Create a VLAN.
472    [Arguments]  ${id}  ${interface}=eth0  ${expected_result}=valid
473
474    # Description of argument(s):
475    # id  The VLAN ID (e.g. '53').
476    # interface  The physical interface for the VLAN(e.g. 'eth0').
477    # expected_result  Expected status of VLAN configuration.
478
479    @{data_vlan_id}=  Create List  ${interface}  ${id}
480    ${data}=  Create Dictionary   data=@{data_vlan_id}
481    ${resp}=  OpenBMC Post Request  ${vlan_resource}  data=${data}
482    ${resp.status_code}=  Convert To String  ${resp.status_code}
483    ${status}=  Run Keyword And Return Status
484    ...  Valid Value  resp.status_code  ["${HTTP_OK}"]
485
486    Run Keyword If  '${expected_result}' == 'error'
487    ...      Should Be Equal  ${status}  ${False}
488    ...      msg=Configuration of an invalid VLAN ID Failed.
489    ...  ELSE
490    ...      Should Be Equal  ${status}  ${True}
491    ...      msg=Configuration of a valid VLAN ID Failed.
492
493    Sleep  ${NETWORK_TIMEOUT}s
494
495
496Configure Network Settings On VLAN
497    [Documentation]  Configure network settings.
498    [Arguments]  ${id}  ${ip_addr}  ${prefix_len}  ${gateway_ip}=${gateway}
499    ...  ${expected_result}=valid  ${interface}=eth0
500
501    # Description of argument(s):
502    # id               The VLAN ID (e.g. '53').
503    # ip_addr          IP address of VLAN Interface.
504    # prefix_len       Prefix length of VLAN Interface.
505    # gateway_ip       Gateway IP address of VLAN Interface.
506    # expected_result  Expected status of network setting configuration.
507    # interface        Physical Interface on which the VLAN is defined.
508
509    @{ip_parm_list}=  Create List  ${network_resource}
510    ...  ${ip_addr}  ${prefix_len}  ${gateway_ip}
511
512    ${data}=  Create Dictionary  data=@{ip_parm_list}
513
514    Run Keyword And Ignore Error  OpenBMC Post Request
515    ...  ${NETWORK_MANAGER}${interface}_${id}/action/IP  data=${data}
516
517    # After any modification on network interface, BMC restarts network
518    # module, wait until it is reachable. Then wait 15 seconds for new
519    # configuration to be updated on BMC.
520
521    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
522    ...  ${NETWORK_RETRY_TIME}
523    Sleep  ${NETWORK_TIMEOUT}s
524
525    # Verify whether new IP address is populated on BMC system.
526    # It should not allow to configure invalid settings.
527    ${status}=  Run Keyword And Return Status
528    ...  Verify IP On BMC  ${ip_addr}
529
530    Run Keyword If  '${expected_result}' == 'error'
531    ...      Should Be Equal  ${status}  ${False}
532    ...      msg=Configuration of invalid IP Failed.
533    ...  ELSE
534    ...      Should Be Equal  ${status}  ${True}
535    ...      msg=Configuration of valid IP Failed.
536
537
538Get BMC Default Gateway
539    [Documentation]  Get system default gateway.
540
541    ${route_info}=  Get BMC Route Info
542
543    ${lines}=  Get Lines Containing String  ${route_info}  default via
544    @{gateway_list}=  Split To Lines  ${lines}
545
546    # Extract first default gateway and return.
547    @{default_gw}=  Split String  ${gateway_list[0]}
548
549    [Return]  ${default_gw[2]}
550