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