xref: /openbmc/openbmc-test-automation/lib/bmc_network_utils.robot (revision a15a1839e76b5c36f07271811b13e975af519589)
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    ${active_channel_config}=  Get Active Channel Config
24    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
25
26    Should Not Be Empty  ${mac_address}
27    Open Connection And Log In
28    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
29    ...  cat /sys/class/net/${ethernet_interface}/address
30    IF  '${mac_address.lower()}' != '${bmc_mac_addr.lower()}'
31        Set MAC Address
32    END
33
34
35Set MAC Address
36    [Documentation]  Update eth0 with input MAC address.
37    [Arguments]  ${mac_address}=${MAC_ADDRESS}
38
39    # Description of argument(s):
40    # mac_address  The mac address (e.g. 00:01:6c:80:02:28).
41
42    ${active_channel_config}=  Get Active Channel Config
43    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
44
45    Write  fw_setenv ethaddr ${mac_address}
46    OBMC Reboot (off)
47
48    # Take SSH session post BMC reboot.
49    Open Connection And Log In
50    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
51    ...  cat /sys/class/net/${ethernet_interface}/address
52    Should Be Equal  ${bmc_mac_addr}  ${mac_address}  ignore_case=True
53
54
55Get BMC IP Info
56    [Documentation]  Get system IP address and prefix length.
57
58
59    # Get system IP address and prefix length details using "ip addr"
60    # Sample Output of "ip addr":
61    # 1: eth0: <BROADCAST,MULTIAST> mtu 1500 qdisc mq state UP qlen 1000
62    #     link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
63    #     inet xx.xx.xx.xx/24 brd xx.xx.xx.xx scope global eth0
64
65    ${active_channel_config}=  Get Active Channel Config
66    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
67    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
68    ...  /sbin/ip addr | grep ${ethernet_interface}
69
70    # Get line having IP address details.
71    ${lines}=  Get Lines Containing String  ${cmd_output}  inet
72
73    # List IP address details.
74    @{ip_components}=  Split To Lines  ${lines}
75
76    @{ip_data}=  Create List
77
78    # Get all IP addresses and prefix lengths on system.
79    FOR  ${ip_component}  IN  @{ip_components}
80      @{if_info}=  Split String  ${ip_component}
81      ${ip_n_prefix}=  Get From List  ${if_info}  1
82      Append To List  ${ip_data}  ${ip_n_prefix}
83    END
84
85    RETURN  ${ip_data}
86
87Get BMC Route Info
88    [Documentation]  Get system route info.
89
90    # Sample output of "ip route":
91    # default via xx.xx.xx.x dev eth0
92    # xx.xx.xx.0/23 dev eth0  src xx.xx.xx.xx
93    # xx.xx.xx.0/24 dev eth0  src xx.xx.xx.xx
94
95    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
96    ...  /sbin/ip route
97
98    RETURN  ${cmd_output}
99
100Get BMC MAC Address
101    [Documentation]  Get system MAC address.
102
103    # Sample output of "ip addr | grep ether":
104    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
105
106    ${active_channel_config}=  Get Active Channel Config
107    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
108
109    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
110    ...  /sbin/ip addr | grep ${ethernet_interface} -A 1 | grep ether
111
112    # Split the line and return MAC address.
113    # Split list data:
114    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
115
116    @{words}=  Split String  ${cmd_output}
117
118    RETURN  ${words[1]}
119
120
121Get BMC MAC Address List
122    [Documentation]  Get system MAC address
123
124    # Sample output of "ip addr | grep ether":
125    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
126
127    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
128    ...  /sbin/ip addr | grep ether
129
130    # Split the line and return MAC address.
131    # Split list data:
132    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
133    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
134
135    ${mac_list}=  Create List
136    @{lines}=  Split To Lines  ${cmd_output}
137    FOR  ${line}  IN  @{lines}
138      @{words}=  Split String  ${line}
139      Append To List  ${mac_list}  ${words[1]}
140    END
141
142    RETURN  ${mac_list}
143
144Get BMC Hostname
145    [Documentation]  Get BMC hostname.
146
147    # Sample output of  "hostname":
148    # test_hostname
149
150    ${output}  ${stderr}  ${rc}=  BMC Execute Command  hostname
151
152    RETURN  ${output}
153
154Get FW_Env MAC Address
155    [Documentation]  Get FW_Env MAC address.
156
157    # Sample output of "fw_printenv | grep ethaddr"
158    # ethaddr=xx:xx:xx:xx:xx:xx:xx
159
160    ${active_channel_config}=  Get Active Channel Config
161    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
162
163    ${ethernet_interface}=  Set Variable If
164    ...  "${ethernet_interface}"=="eth0"  ethaddr  eth1addr
165
166    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command  /sbin/fw_printenv | grep ${ethernet_interface}
167
168    # Split the line and return MAC address.
169    # Split list data:
170    # ethaddr | xx:xx:xx:xx:xx:xx:xx
171
172    @{words}=  Split String  ${cmd_output}  =
173
174    RETURN  ${words[1]}
175
176
177Get List Of IP Address Via REST
178    [Documentation]  Get list of IP address via REST.
179    [Arguments]  @{ip_uri_list}
180
181    # Description of argument(s):
182    # ip_uri_list  List of IP objects.
183    # Example:
184    #   "data": [
185    #     "/xyz/openbmc_project/network/eth0/ipv4/e9767624",
186    #     "/xyz/openbmc_project/network/eth0/ipv4/31f4ce8b"
187    #   ],
188
189    ${ip_list}=  Create List
190
191    FOR  ${ip_uri}  IN  @{ip_uri_list}
192      ${ip_addr}=  Read Attribute  ${ip_uri}  Address
193      Append To List  ${ip_list}  ${ip_addr}
194    END
195
196    RETURN  @{ip_list}
197
198Delete IP And Object
199    [Documentation]  Delete IP and object.
200    [Arguments]  ${ip_addr}  @{ip_uri_list}
201
202    # Description of argument(s):
203    # ip_addr      IP address to be deleted.
204    # ip_uri_list  List of IP object URIs.
205
206    # Find IP object having this IP address.
207
208     FOR  ${ip_uri}  IN  @{ip_uri_list}
209       ${ip_addr1}=  Read Attribute  ${ip_uri}  Address
210       IF  '${ip_addr}' == '${ip_addr1}'
211          Exit For Loop
212       END
213     END
214
215    # If the given IP address is not configured, return.
216    # Otherwise, delete the IP and object.
217
218    Run Keyword And Return If  '${ip_addr}' != '${ip_addr1}'
219    ...  Pass Execution  IP address to be deleted is not configured.
220
221    Run Keyword And Ignore Error  OpenBMC Delete Request  ${ip_uri}
222
223    # After any modification on network interface, BMC restarts network
224    # module, wait until it is reachable. Then wait 15 seconds for new
225    # configuration to be updated on BMC.
226
227    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
228    ...  ${NETWORK_RETRY_TIME}
229    Sleep  15s
230
231    # Verify whether deleted IP address is removed from BMC system.
232
233    ${ip_data}=  Get BMC IP Info
234    Should Not Contain Match  ${ip_data}  ${ip_addr}*
235    ...  msg=IP address not deleted.
236
237Get First Non Pingable IP From Subnet
238    [Documentation]  Find first non-pingable IP from the subnet and return it.
239    [Arguments]  ${host}=${OPENBMC_HOST}
240
241    # Description of argument(s):
242    # host  Any valid host name or IP address
243    #       (e.g. "machine1" or "9.xx.xx.31").
244
245    # Non-pingable IP is unused IP address in the subnet.
246    ${host_name}  ${ip_addr}=  Get Host Name IP  ${host}
247
248    # Split IP address into network part and host part.
249    # IP address will have 4 octets xx.xx.xx.xx.
250    # Sample output after split:
251    # split_ip  [xx.xx.xx, xx]
252
253    ${split_ip}=  Split String From Right  ${ip_addr}  .  1
254    # First element in list is Network part.
255    ${network_part}=  Get From List  ${split_ip}  0
256
257    FOR  ${octet4}  IN RANGE  1  255
258      ${new_ip}=  Catenate  ${network_part}.${octet4}
259      ${status}=  Run Keyword And Return Status  Ping Host  ${new_ip}
260      # If IP is non-pingable, return it.
261      Return From Keyword If  '${status}' == 'False'  ${new_ip}
262    END
263
264    Fail  msg=No non-pingable IP could be found in subnet ${network_part}.
265
266
267Validate MAC On BMC
268    [Documentation]  Validate MAC on BMC.
269    [Arguments]  ${mac_addr}
270
271    # Description of argument(s):
272    # mac_addr  MAC address of the BMC.
273
274    ${system_mac}=  Get BMC MAC Address
275    ${mac_new_addr}=  Truncate MAC Address  ${system_mac}  ${mac_addr}
276
277    ${status}=  Compare MAC Address  ${system_mac}  ${mac_new_addr}
278    Should Be True  ${status}
279    ...  msg=MAC address ${system_mac} does not match ${mac_new_addr}.
280
281Validate MAC On FW_Env
282    [Documentation]  Validate MAC on FW_Env.
283    [Arguments]  ${mac_addr}
284
285    # Description of argument(s):
286    # mac_addr  MAC address of the BMC.
287
288    ${fw_env_addr}=  Get FW_Env MAC Address
289    ${mac_new_addr}=  Truncate MAC Address  ${fw_env_addr}  ${mac_addr}
290
291    ${status}=  Compare MAC Address  ${fw_env_addr}  ${mac_new_addr}
292    Should Be True  ${status}
293    ...  msg=MAC address ${fw_env_addr} does not match ${mac_new_addr}.
294
295Truncate MAC Address
296    [Documentation]  Truncates and returns user provided MAC address.
297    [Arguments]    ${sys_mac_addr}  ${user_mac_addr}
298
299    # Description of argument(s):
300    # sys_mac_addr  MAC address of the BMC.
301    # user_mac_addr user provided MAC address.
302
303    ${mac_byte}=  Set Variable  ${0}
304    @{user_mac_list}=  Split String  ${user_mac_addr}  :
305    @{sys_mac_list}=  Split String  ${sys_mac_addr}  :
306    ${user_new_mac_list}  Create List
307
308    # Truncate extra bytes and bits from MAC address
309    FOR  ${mac_item}  IN  @{sys_mac_list}
310        ${invalid_mac_byte} =  Get Regexp Matches  ${user_mac_list}[${mac_byte}]  [^A-Za-z0-9]+
311        Return From Keyword If  ${invalid_mac_byte}  ${user_mac_addr}
312        ${mac_int} =    Convert To Integer      ${user_mac_list}[${mac_byte}]   16
313        ${user_mac_len} =  Get Length  ${user_mac_list}
314        IF  ${mac_int} >= ${256}
315            ${user_mac_byte}=  Truncate MAC Bits  ${user_mac_list}[${mac_byte}]
316        ELSE
317            ${user_mac_byte}=   Set Variable  ${user_mac_list}[${mac_byte}]
318        END
319        Append To List  ${user_new_mac_list}  ${user_mac_byte}
320        ${mac_byte} =    Set Variable    ${mac_byte + 1}
321        Exit For Loop If  '${mac_byte}' == '${user_mac_len}'
322
323    END
324    ${user_new_mac_string}=   Evaluate  ":".join(${user_new_mac_list})
325    RETURN  ${user_new_mac_string}
326
327Truncate MAC Bits
328    [Documentation]  Truncates user provided MAC address byte to bits.
329    [Arguments]    ${user_mac_addr_byte}
330
331    # Description of argument(s):
332    # user_mac_addr_byte user provided MAC address byte to truncate bits
333
334    ${user_mac_addr_int}=   Convert To List  ${user_mac_addr_byte}
335    ${user_mac_addr_byte}=  Get Slice From List  ${user_mac_addr_int}  0  2
336    ${user_mac_addr_byte_string}=  Evaluate  "".join(${user_mac_addr_byte})
337    RETURN  ${user_mac_addr_byte_string}
338
339
340Run Build Net
341    [Documentation]  Run build_net to preconfigure the ethernet interfaces.
342
343    OS Execute Command  build_net help y y
344    # Run pingum to check if the "build_net" was run correctly done.
345    ${output}  ${stderr}  ${rc}=  OS Execute Command  pingum
346    Should Contain  ${output}  All networks ping Ok
347
348
349Configure Hostname
350    [Documentation]  Configure hostname on BMC via Redfish.
351    [Arguments]  ${hostname}  ${status_code}=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
352
353    # Description of argument(s):
354    # hostname      A hostname value which is to be configured on BMC.
355    # status_codes  Expected return code from patch operation
356    #               (e.g. "200").  See prolog of rest_request
357    #               method in redfish_plus.py for details.
358
359    ${active_channel_config}=  Get Active Channel Config
360    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
361
362    ${data}=  Create Dictionary  HostName=${hostname}
363    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
364    ...  valid_status_codes=${status_code}
365
366
367Verify IP On BMC
368    [Documentation]  Verify IP on BMC.
369    [Arguments]  ${ip}
370
371    # Description of argument(s):
372    # ip  IP address to be verified (e.g. "10.7.7.7").
373
374    # Get IP address details on BMC using IP command.
375    @{ip_data}=  Get BMC IP Info
376    Should Contain Match  ${ip_data}  ${ip}/*
377    ...  msg=IP address does not exist.
378
379
380Verify Gateway On BMC
381    [Documentation]  Verify gateway on BMC.
382    [Arguments]  ${gateway_ip}=0.0.0.0
383
384    # Description of argument(s):
385    # gateway_ip  Gateway IP address.
386
387    ${route_info}=  Get BMC Route Info
388
389    # If gateway IP is empty or 0.0.0.0 it will not have route entry.
390
391    IF  '${gateway_ip}' == '0.0.0.0'
392        Pass Execution  Gateway IP is "0.0.0.0".
393    ELSE
394        Should Contain  ${route_info}  ${gateway_ip}  msg=Gateway IP address not matching.
395    END
396
397
398Get BMC DNS Info
399    [Documentation]  Get system DNS info.
400
401
402    # Sample output of "resolv.conf":
403    # ### Generated manually via dbus settings ###
404    # nameserver 8.8.8.8
405
406    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
407    ...  cat /etc/resolv.conf
408
409    RETURN  ${cmd_output}
410
411
412CLI Get Nameservers
413    [Documentation]  Get the nameserver IPs from /etc/resolv.conf and return as a list.
414
415    # Example of /etc/resolv.conf data:
416    # nameserver x.x.x.x
417    # nameserver y.y.y.y
418
419    ${stdout}  ${stderr}  ${rc}=  BMC Execute Command
420    ...  egrep nameserver /etc/resolv.conf | cut -f2- -d ' '
421    ${nameservers}=  Split String  ${stdout}
422
423    RETURN  ${nameservers}
424
425CLI Get and Verify Name Servers
426    [Documentation]    Get and Verify the nameserver IPs from /etc/resolv.conf
427    ...  and compare with redfish nameserver.
428    [Arguments]     ${static_name_servers}
429    ...  ${valid_status_codes}=[${HTTP_OK},${HTTP_NO_CONTENT}]
430
431    # Description of Argument(s):
432    # static_name_servers    Address for static name server
433    # valid_status_codes     Expected return code from patch operation
434    #                        (e.g. "200").  See prolog of rest_request
435    #                        method in redfish_plus.py for details.
436
437    ${cli_nameservers}=  CLI Get Nameservers
438    ${cmd_status}=  Run Keyword And Return Status
439    ...  List Should Contain Sub List  ${cli_nameservers}  ${static_name_servers}
440
441    IF  ${valid_status_codes} == [${HTTP_OK},${HTTP_NO_CONTENT}]
442        Should Be True  ${cmd_status}
443    ELSE
444         Should Not Be True  ${cmd_status}
445    END
446
447Get Network Configuration
448    [Documentation]  Get network configuration.
449    # Sample output:
450    #{
451    #  "@odata.context": "/redfish/v1/$metadata#EthernetInterface.EthernetInterface",
452    #  "@odata.id": "/redfish/v1/Managers/${MANAGER_ID}/EthernetInterfaces/eth0",
453    #  "@odata.type": "#EthernetInterface.v1_2_0.EthernetInterface",
454    #  "Description": "Management Network Interface",
455    #  "IPv4Addresses": [
456    #    {
457    #      "Address": "169.254.xx.xx",
458    #      "AddressOrigin": "IPv4LinkLocal",
459    #      "Gateway": "0.0.0.0",
460    #      "SubnetMask": "255.255.0.0"
461    #    },
462    #    {
463    #      "Address": "xx.xx.xx.xx",
464    #      "AddressOrigin": "Static",
465    #      "Gateway": "xx.xx.xx.1",
466    #      "SubnetMask": "xx.xx.xx.xx"
467    #    }
468    #  ],
469    #  "Id": "eth0",
470    #  "MACAddress": "xx:xx:xx:xx:xx:xx",
471    #  "Name": "Manager Ethernet Interface",
472    #  "SpeedMbps": 0,
473    #  "VLAN": {
474    #    "VLANEnable": false,
475    #    "VLANId": 0
476    #  }
477    [Arguments]  ${network_active_channel}=${CHANNEL_NUMBER}
478
479    # Description of argument(s):
480    # network_active_channel   Ethernet channel number (eg. 1 or 2)
481
482    ${active_channel_config}=  Get Active Channel Config
483    ${resp}=  Redfish.Get
484    ...  ${REDFISH_NW_ETH_IFACE}${active_channel_config['${network_active_channel}']['name']}
485
486    @{network_configurations}=  Get From Dictionary  ${resp.dict}  IPv4StaticAddresses
487    RETURN  @{network_configurations}
488
489
490Add IP Address
491    [Documentation]  Add IP Address To BMC.
492    [Arguments]  ${ip}  ${subnet_mask}  ${gateway}
493    ...  ${valid_status_codes}=${HTTP_OK}
494
495    # Description of argument(s):
496    # ip                  IP address to be added (e.g. "10.7.7.7").
497    # subnet_mask         Subnet mask for the IP to be added
498    #                     (e.g. "255.255.0.0").
499    # gateway             Gateway for the IP to be added (e.g. "10.7.7.1").
500    # valid_status_codes  Expected return code from patch operation
501    #                     (e.g. "200").  See prolog of rest_request
502    #                     method in redfish_plus.py for details.
503
504    ${empty_dict}=  Create Dictionary
505    ${ip_data}=  Create Dictionary  Address=${ip}
506    ...  SubnetMask=${subnet_mask}  Gateway=${gateway}
507
508    ${patch_list}=  Create List
509    ${network_configurations}=  Get Network Configuration
510    ${num_entries}=  Get Length  ${network_configurations}
511
512    FOR  ${INDEX}  IN RANGE  0  ${num_entries}
513      Append To List  ${patch_list}  ${empty_dict}
514    END
515
516    ${valid_status_codes}=  Set Variable If  '${valid_status_codes}' == '${HTTP_OK}'
517    ...   ${HTTP_OK},${HTTP_NO_CONTENT}   ${valid_status_codes}
518
519    # We need not check for existence of IP on BMC while adding.
520    Append To List  ${patch_list}  ${ip_data}
521    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
522
523    ${active_channel_config}=  Get Active Channel Config
524    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
525
526    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
527    ...  valid_status_codes=[${valid_status_codes}]
528
529    Return From Keyword If  '${valid_status_codes}' != '${HTTP_OK},${HTTP_NO_CONTENT}'
530
531    # Note: Network restart takes around 15-18s after patch request processing.
532    Sleep  ${NETWORK_TIMEOUT}s
533    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
534
535    Verify IP On BMC  ${ip}
536    Validate Network Config On BMC
537
538
539Delete IP Address
540    [Documentation]  Delete IP Address Of BMC.
541    [Arguments]  ${ip}  ${valid_status_codes}=[${HTTP_OK},${HTTP_ACCEPTED},${HTTP_NO_CONTENT}]
542
543    # Description of argument(s):
544    # ip                  IP address to be deleted (e.g. "10.7.7.7").
545    # valid_status_codes  Expected return code from patch operation
546    #                     (e.g. "200").  See prolog of rest_request
547    #                     method in redfish_plus.py for details.
548
549    ${empty_dict}=  Create Dictionary
550    ${patch_list}=  Create List
551
552    @{network_configurations}=  Get Network Configuration
553    FOR  ${network_configuration}  IN  @{network_configurations}
554        IF  '${network_configuration['Address']}' == '${ip}'
555            Append To List  ${patch_list}  ${null}
556        ELSE
557            Append To List  ${patch_list}  ${empty_dict}
558        END
559    END
560
561    ${ip_found}=  Run Keyword And Return Status  List Should Contain Value
562    ...  ${patch_list}  ${null}  msg=${ip} does not exist on BMC
563    Pass Execution If  ${ip_found} == ${False}  ${ip} does not exist on BMC
564
565    # Run patch command only if given IP is found on BMC
566    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
567
568    ${active_channel_config}=  Get Active Channel Config
569    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
570
571    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
572    ...  valid_status_codes=${valid_status_codes}
573
574    # Note: Network restart takes around 15-18s after patch request processing
575    Sleep  ${NETWORK_TIMEOUT}s
576    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
577
578    ${delete_status}=  Run Keyword And Return Status  Verify IP On BMC  ${ip}
579    IF  '${valid_status_codes}' == '[${HTTP_OK},${HTTP_ACCEPTED},${HTTP_NO_CONTENT}]'
580        Should Be True  '${delete_status}' == '${False}'
581    ELSE
582        Should Be True  '${delete_status}' == '${True}'
583    END
584
585    Validate Network Config On BMC
586
587
588Validate Network Config On BMC
589    [Documentation]  Check that network info obtained via redfish matches info
590    ...              obtained via CLI.
591
592    @{network_configurations}=  Get Network Configuration
593    ${ip_data}=  Get BMC IP Info
594    FOR  ${network_configuration}  IN  @{network_configurations}
595      Should Contain Match  ${ip_data}  ${network_configuration['Address']}/*
596      ...  msg=IP address does not exist.
597    END
598
599
600Create VLAN
601    [Documentation]  Create a VLAN.
602    [Arguments]  ${id}  ${interface}=eth0  ${expected_result}=valid
603
604    # Description of argument(s):
605    # id               The VLAN ID (e.g. '53').
606    # interface        The physical interface for the VLAN(e.g. 'eth0').
607    # expected_result  Expected status of VLAN configuration.
608
609    @{data_vlan_id}=  Create List  ${interface}  ${id}
610    ${data}=  Create Dictionary   data=@{data_vlan_id}
611    ${resp}=  OpenBMC Post Request  ${vlan_resource}  data=${data}
612    ${resp.status_code}=  Convert To String  ${resp.status_code}
613    ${status}=  Run Keyword And Return Status
614    ...  Valid Value  resp.status_code  ["${HTTP_OK}"]
615
616    IF  '${expected_result}' == 'error'
617        Should Be Equal  ${status}  ${False}  msg=Configuration of an invalid VLAN ID Failed.
618    ELSE
619         Should Be Equal  ${status}  ${True}  msg=Configuration of a valid VLAN ID Failed.
620    END
621
622    Sleep  ${NETWORK_TIMEOUT}s
623
624
625Configure Network Settings On VLAN
626    [Documentation]  Configure network settings.
627    [Arguments]  ${id}  ${ip_addr}  ${prefix_len}  ${gateway_ip}=${gateway}
628    ...  ${expected_result}=valid  ${interface}=eth0
629
630    # Description of argument(s):
631    # id               The VLAN ID (e.g. '53').
632    # ip_addr          IP address of VLAN Interface.
633    # prefix_len       Prefix length of VLAN Interface.
634    # gateway_ip       Gateway IP address of VLAN Interface.
635    # expected_result  Expected status of network setting configuration.
636    # interface        Physical Interface on which the VLAN is defined.
637
638    @{ip_parm_list}=  Create List  ${network_resource}
639    ...  ${ip_addr}  ${prefix_len}  ${gateway_ip}
640
641    ${data}=  Create Dictionary  data=@{ip_parm_list}
642
643    Run Keyword And Ignore Error  OpenBMC Post Request
644    ...  ${NETWORK_MANAGER}${interface}_${id}/action/IP  data=${data}
645
646    # After any modification on network interface, BMC restarts network
647    # module, wait until it is reachable. Then wait 15 seconds for new
648    # configuration to be updated on BMC.
649
650    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
651    ...  ${NETWORK_RETRY_TIME}
652    Sleep  ${NETWORK_TIMEOUT}s
653
654    # Verify whether new IP address is populated on BMC system.
655    # It should not allow to configure invalid settings.
656    ${status}=  Run Keyword And Return Status
657    ...  Verify IP On BMC  ${ip_addr}
658
659    IF  '${expected_result}' == 'error'
660       Should Be Equal  ${status}  ${False}  msg=Configuration of invalid IP Failed.
661    ELSE
662       Should Be Equal  ${status}  ${True}  msg=Configuration of valid IP Failed.
663    END
664
665
666Get BMC Default Gateway
667    [Documentation]  Get system default gateway.
668    [Arguments]  ${channel_number}=${CHANNEL_NUMBER}
669
670    # Description of argument(s):
671    # channel_number        Channel number: 1 for eth0, 2 for eth1.
672
673    ${route_info}=  Get BMC Route Info
674
675    ${lines}=  Get Lines Containing String  ${route_info}  default via
676
677    ${active_channel_config}=  Get Active Channel Config
678    ${ethernet_interface}=  Set Variable  ${active_channel_config['${channel_number}']['name']}
679
680    # Extract the corresponding default gateway for eth0 and eth1
681    ${default_gw_line}=  Get Lines Containing String  ${lines}  ${ethernet_interface}
682    ${default_gw}=  Split String  ${default_gw_line}
683
684    # Example of the output
685    # default_gw:
686    #   [0]:   default
687    #   [1]:   via
688    #   [2]:   xx.xx.xx.1
689    #   [3]:   dev
690    #   [4]:   eth1
691
692    RETURN  ${default_gw[2]}
693
694
695Validate Hostname On BMC
696    [Documentation]  Verify that the hostname read via Redfish is the same as the
697    ...  hostname configured on system.
698    [Arguments]  ${hostname}
699
700    # Description of argument(s):
701    # hostname  A hostname value which is to be compared to the hostname
702    #           configured on system.
703
704    ${sys_hostname}=  Get BMC Hostname
705    Should Be Equal  ${sys_hostname}  ${hostname}
706    ...  ignore_case=True  msg=Hostname does not exist.
707
708Get Channel Number For All Interface
709    [Documentation]  Gets the Interface name and returns the channel number for the given interface.
710
711    ${valid_channel_number_interface_names}=  Get Channel Config
712
713    ${valid_channel_number_interface_names}=  Convert To Dictionary  ${valid_channel_number_interface_names}
714
715    RETURN  ${valid_channel_number_interface_names}
716
717Get Valid Channel Number
718    [Documentation]  Get Valid Channel Number.
719    [Arguments]  ${valid_channel_number_interface_names}
720
721    # Description of argument(s):
722    # valid_channel_number_interface_names   Contains channel names in dict.
723
724    &{valid_channel_number_interface_name}=  Create Dictionary
725
726    FOR  ${key}  ${values}  IN  &{valid_channel_number_interface_names}
727      IF  '${values['is_valid']}' == 'True'
728          Set To Dictionary  ${valid_channel_number_interface_name}  ${key}  ${values}
729      END
730    END
731
732    RETURN  ${valid_channel_number_interface_name}
733
734Get Invalid Channel Number List
735    [Documentation]  Get Invalid Channel and return as list.
736
737    ${available_channels}=  Get Channel Number For All Interface
738    # Get the channel which medium_type as 'reserved' and append it to a list.
739    @{invalid_channel_number_list}=  Create List
740
741    FOR  ${channel_number}  ${values}  IN  &{available_channels}
742       IF  '${values['channel_info']['medium_type']}' == 'reserved'
743           Append To List  ${invalid_channel_number_list}  ${channel_number}
744       END
745    END
746
747    RETURN  ${invalid_channel_number_list}
748
749
750Get Channel Number For Valid Ethernet Interface
751    [Documentation]  Get channel number for all ethernet interface.
752    [Arguments]  ${valid_channel_number_interface_name}
753
754    # Description of argument(s):
755    # channel_number_list  Contains channel names in list.
756
757    @{channel_number_list}=  Create List
758
759    FOR  ${channel_number}  ${values}  IN  &{valid_channel_number_interface_name}
760      ${usb_interface_status}=  Run Keyword And Return Status  Should Not Contain  ${values['name']}  usb
761      Continue For Loop IF  ${usb_interface_status} == False
762      IF  '${values['channel_info']['medium_type']}' == 'lan-802.3'
763          Append To List  ${channel_number_list}  ${channel_number}
764      END
765    END
766
767    RETURN  ${channel_number_list}
768
769
770Get Current Channel Name List
771    [Documentation]  Get Current Channel name and append it to active channel list.
772    [Arguments]  ${channel_list}  ${channel_config_json}
773
774    # Description of Arguments
775    # ${channel_list}        - list Contains all available active channels.
776    # ${channel_config_json} - output of /usr/share/ipmi-providers/channel_config.json file.
777
778    FOR  ${channel_number}  ${values}  IN  &{channel_config_json}
779        IF  '${values['name']}' == 'SELF'
780            Append To List  ${channel_list}  ${channel_number}
781        END
782    END
783
784    RETURN  ${channel_list}
785
786
787Get Active Ethernet Channel List
788    [Documentation]  Get Available channels from channel_config.json file and return as list.
789    [Arguments]  ${current_channel}=${0}
790
791    # Description of Arguments
792    # ${current_channel}        Current channel number.
793
794    ${valid_channel_number_interface_names}=  Get Channel Number For All Interface
795
796    ${valid_channel_number_interface_name}=  Get Valid Channel Number  ${valid_channel_number_interface_names}
797
798    ${channel_number_list}=  Get Channel Number For Valid Ethernet Interface
799    ...  ${valid_channel_number_interface_name}
800
801    Return From Keyword If  ${current_channel} == 0  ${channel_number_list}
802    ${channel_number_list}=  Get Current Channel Name List
803    ...  ${channel_number_list}  ${valid_channel_number_interface_names}
804
805    RETURN  ${channel_number_list}
806
807Update IP Address
808    [Documentation]  Update and verify IP address of BMC.
809    [Arguments]  ${ip}  ${new_ip}  ${netmask}  ${gw_ip}
810    ...  ${valid_status_codes}=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
811
812    # Description of argument(s):
813    # ip                  IP address to be replaced (e.g. "10.7.7.7").
814    # new_ip              New IP address to be configured.
815    # netmask             Netmask value.
816    # gw_ip               Gateway IP address.
817    # valid_status_codes  Expected return code from patch operation
818    #                     (e.g. "200").  See prolog of rest_request
819    #                     method in redfish_plus.py for details.
820
821    ${empty_dict}=  Create Dictionary
822    ${patch_list}=  Create List
823    ${ip_data}=  Create Dictionary
824    ...  Address=${new_ip}  SubnetMask=${netmask}  Gateway=${gw_ip}
825
826    # Find the position of IP address to be modified.
827    @{network_configurations}=  Get Network Configuration
828    FOR  ${network_configuration}  IN  @{network_configurations}
829      IF  '${network_configuration['Address']}' == '${ip}'
830          Append To List  ${patch_list}  ${ip_data}
831      ELSE
832          Append To List  ${patch_list}  ${empty_dict}
833      END
834    END
835
836    # Modify the IP address only if given IP is found
837    ${ip_found}=  Run Keyword And Return Status  List Should Contain Value
838    ...  ${patch_list}  ${ip_data}  msg=${ip} does not exist on BMC
839    Pass Execution If  ${ip_found} == ${False}  ${ip} does not exist on BMC
840
841    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
842
843    ${active_channel_config}=  Get Active Channel Config
844    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
845
846    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}
847    ...  body=&{data}  valid_status_codes=${valid_status_codes}
848
849    # Note: Network restart takes around 15-18s after patch request processing.
850    Sleep  ${NETWORK_TIMEOUT}s
851    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
852
853    Verify IP On BMC  ${new_ip}
854    Validate Network Config On BMC
855
856Get IPv4 DHCP Enabled Status
857    [Documentation]  Return IPv4 DHCP enabled status from redfish URI.
858    [Arguments]  ${channel_number}=${1}
859
860    # Description of argument(s):
861    # channel_number   Ethernet channel number, 1 is for eth0 and 2 is for eth1 (e.g. "1").
862
863    ${active_channel_config}=  Get Active Channel Config
864    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
865    ${resp}=  Redfish.Get Attribute  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  DHCPv4
866    Return From Keyword  ${resp['DHCPEnabled']}
867
868Get DHCP IP Info
869    [Documentation]  Return DHCP IP address, gateway and subnetmask from redfish URI.
870
871    ${active_channel_config}=  Get Active Channel Config
872    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
873    ${resp_list}=  Redfish.Get Attribute  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  IPv4Addresses
874    FOR  ${resp}  IN  @{resp_list}
875        Continue For Loop If  '${resp['AddressOrigin']}' != 'DHCP'
876        ${ip_addr}=  Set Variable  ${resp['Address']}
877        ${gateway}=  Set Variable  ${resp['Gateway']}
878        ${subnetmask}=  Set Variable  ${resp['SubnetMask']}
879        Return From Keyword  ${ip_addr}  ${gateway}  ${subnetmask}
880    END
881
882
883DNS Test Setup Execution
884    [Documentation]  Do DNS test setup execution.
885
886    Redfish.Login
887
888    ${active_channel_config}=  Get Active Channel Config
889    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
890
891    ${original_nameservers}=  Redfish.Get Attribute
892    ...  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  StaticNameServers
893
894    Rprint Vars  original_nameservers
895    # Set suite variables to trigger restoration during teardown.
896    Set Suite Variable  ${original_nameservers}
897
898
899Delete Static Name Servers
900    [Documentation]  Delete static name servers.
901
902    DNS Test Setup Execution
903    Configure Static Name Servers  static_name_servers=@{EMPTY}
904
905    # Check if all name servers deleted on BMC.
906    ${nameservers}=  CLI Get Nameservers
907    Should Not Contain  ${nameservers}  ${original_nameservers}
908
909    DNS Test Setup Execution
910
911    Should Be Empty  ${original_nameservers}
912
913
914Configure Static Name Servers
915    [Documentation]  Configure DNS server on BMC.
916    [Arguments]  ${static_name_servers}=${original_nameservers}
917     ...  ${valid_status_codes}=[${HTTP_OK},${HTTP_NO_CONTENT}]
918
919    # Description of the argument(s):
920    # static_name_servers  A list of static name server IPs to be
921    #                      configured on the BMC.
922    # valid_status_codes  Expected return code from patch operation
923    #                     (e.g. "200").  See prolog of rest_request
924    #                     method in redfish_plus.py for details.
925
926    ${active_channel_config}=  Get Active Channel Config
927    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
928
929    ${type} =  Evaluate  type($static_name_servers).__name__
930    ${static_name_servers}=  Set Variable If  '${type}'=='str'
931    ...  '${static_name_servers}'  ${static_name_servers}
932
933    # Currently BMC is sending 500 response code instead of 400 for invalid scenarios.
934    Redfish.Patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}
935    ...  body={'StaticNameServers': ${static_name_servers}}
936    ...  valid_status_codes=[${HTTP_OK}, ${HTTP_NO_CONTENT}, ${HTTP_INTERNAL_SERVER_ERROR}]
937
938    # Patch operation takes 1 to 3 seconds to set new value.
939    Sleep  5s
940
941    # Check if newly added DNS server is configured on BMC.
942    CLI Get and Verify Name Servers  ${static_name_servers}  ${valid_status_codes}
943
944Configure MAC Settings
945    [Documentation]  Configure MAC settings via Redfish.
946    [Arguments]  ${mac_address}  ${valid_status_code}=${HTTP_OK}
947
948    # Description of argument(s):
949    # mac_address         MAC address of BMC.
950    # valid_status_code   Expected response code, default is ${HTTP_OK}.
951
952    ${active_channel_config}=  Get Active Channel Config
953    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
954
955    Redfish.Login
956    ${payload}=  Create Dictionary  MACAddress=${mac_address}
957
958    Redfish.Patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{payload}
959    ...  valid_status_codes=[${valid_status_code},${HTTP_NO_CONTENT},${HTTP_INTERNAL_SERVER_ERROR}]
960
961    # After any modification on network interface, BMC restarts network
962    # Note: Network restart takes around 15-18s after patch request processing.
963    Sleep  ${NETWORK_TIMEOUT}s
964
965    Redfish.Get  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}
966
967    # Verify whether new MAC address is populated on BMC system.
968    # It should not allow to configure invalid settings.
969    ${status}=  Run Keyword And Return Status
970    ...  Validate MAC On BMC  ${mac_address}
971
972    IF  ${valid_status_code} == ${HTTP_BAD_REQUEST}
973        Should Be Equal  ${status}  ${False}
974        ...  msg=Allowing the configuration of an invalid MAC.
975    ELSE
976        Should Be Equal  ${status}  ${True}
977        ...  msg=Not allowing the configuration of a valid MAC.
978    END
979
980    Verify MAC Address Via FW_Env  ${mac_address}  ${valid_status_code}
981
982Verify MAC Address Via FW_Env
983    [Documentation]  Verify MAC address on FW_Env.
984    [Arguments]  ${mac_address}  ${valid_status_code}=${HTTP_OK}
985
986    # Description of argument(s):
987    # mac_address         MAC address of BMC.
988    # valid_status_code   Expected response code, default is ${HTTP_OK}.
989
990    ${status}=  Run Keyword And Return Status
991    ...  Validate MAC On FW_Env  ${mac_address}
992
993    IF  ${valid_status_code} == ${HTTP_BAD_REQUEST}
994        Should Be Equal  ${status}  ${False}
995        ...  msg=Allowing the configuration of an invalid MAC.
996    ELSE
997        Should Be Equal  ${status}  ${True}
998        ...  msg=Not allowing the configuration of a valid MAC.
999    END
1000
1001
1002Set DHCPEnabled To Enable Or Disable
1003    [Documentation]  Enable or Disable DHCP on the interface.
1004    [Arguments]  ${dhcp_enabled}=${False}  ${interface}=${ethernet_interface}
1005    ...          ${valid_status_code}=[${HTTP_OK},${HTTP_ACCEPTED},${HTTP_NO_CONTENT}]
1006
1007    # Description of argument(s):
1008    # dhcp_enabled        False for disabling DHCP and True for Enabling DHCP.
1009    # interface           eth0 or eth1. Default is eth1.
1010    # valid_status_code   Expected valid status code from Patch request.
1011    #                     Default is HTTP_OK.
1012
1013    ${data}=  Set Variable If  ${dhcp_enabled} == ${False}  ${DISABLE_DHCP}  ${ENABLE_DHCP}
1014    ${resp}=  Redfish.Patch
1015    ...  /redfish/v1/Managers/${MANAGER_ID}/EthernetInterfaces/${interface}
1016    ...  body=${data}  valid_status_codes=${valid_status_code}
1017