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