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