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