Adds test suits for Cluster HA Leader follower failover
[integration/test.git] / csit / libraries / ClusterKeywords.robot
1 *** Settings ***
2 Library           RequestsLibrary
3 Library           Collections
4 Library           UtilLibrary.py
5 Library           ClusterStateLibrary.py
6 Library           ./HsfJson/hsf_json.py
7 Resource          Utils.robot
8
9 *** Variables ***
10 ${jolokia_conf}    /jolokia/read/org.opendaylight.controller:Category=ShardManager,name=shard-manager-config,type=DistributedConfigDatastore
11 ${jolokia_oper}    /jolokia/read/org.opendaylight.controller:Category=ShardManager,name=shard-manager-operational,type=DistributedOperationalDatastore
12 ${jolokia_read}    /jolokia/read/org.opendaylight.controller
13
14 *** Keywords ***
15 Create Controller Index List
16     [Documentation]    Reads number of controllers and returns a list with all controllers indexes.
17     ${controller_index_list}    Create List
18     ${NUM_ODL_SYSTEM}=    Convert to Integer    ${NUM_ODL_SYSTEM}
19     : FOR    ${i}    IN RANGE    ${NUM_ODL_SYSTEM}
20     \    Append To List    ${controller_index_list}    ${i+1}
21     [Return]    ${controller_index_list}
22
23 Create Controller Sessions
24     [Documentation]    Creates REST session to all controller instances.
25     ${NUM_ODL_SYSTEM}=    Convert to Integer    ${NUM_ODL_SYSTEM}
26     : FOR    ${i}    IN RANGE    ${NUM_ODL_SYSTEM}
27     \    Log    Create Session ${ODL_SYSTEM_${i+1}_IP}
28     \    RequestsLibrary.Create Session    controller${i+1}    http://${ODL_SYSTEM_${i+1}_IP}:${RESTCONFPORT}    auth=${AUTH}
29
30 Get Cluster Shard Status
31     [Arguments]    ${controller_index_list}    ${shard_type}    ${shard}
32     [Documentation]    Checks ${shard} status and returns Leader index and a list of Followers from a ${controller_index_list}.
33     ...    ${shard_type} is either config or operational.
34     ${lenght}=    Get Length    ${controller_index_list}
35     Run Keyword If    '${shard_type}' == 'config'    Set Test Variable    ${type}    DistributedConfigDatastore
36     Run Keyword If    '${shard_type}' == 'operational'    Set Test Variable    ${type}    DistributedOperationalDatastore
37     Should Not Be Empty    ${type}    Wrong type, valid values are config and operational.
38     ${leader}=    Set Variable    0
39     ${follower_list}=    Create List
40     : FOR    ${i}    IN    @{controller_index_list}
41     \    ${data}=    Utils.Get Data From URI    controller${i}    ${jolokia_read}:Category=Shards,name=member-${i}-shard-${shard}-${shard_type},type=${type}
42     \    Log    ${data}
43     \    ${json}=    RequestsLibrary.To Json    ${data}
44     \    ${status}=    Get From Dictionary    &{json}[value]    RaftState
45     \    Log    Controller ${ODL_SYSTEM_${i}_IP} is ${status} for shard ${shard}
46     \    Run Keyword If    '${status}' == 'Leader'    Set Test Variable    ${leader}    ${i}
47     \    Run Keyword If    '${status}' == 'Follower'    Append To List    ${follower_list}    ${i}
48     Should Not Be Equal    ${leader}    0    No Leader elected in shard ${shard_type} ${shard}
49     Length Should Be    ${follower_list}    ${lenght-1}    Not enough or too many Followers in shard ${shard_type} ${shard}
50     [Return]    ${leader}    ${follower_list}
51
52 Get Cluster Entity Owner
53     [Arguments]    ${controller_index_list}    ${device_type}    ${device}
54     [Documentation]    Checks Entity Owner status for a ${device} and returns owner index and list of candidates from a ${controller_index_list}.
55     ...    ${device_type} can be openflow, ovsdb, etc.
56     ${length}=    Get Length    ${controller_index_list}
57     ${candidates_list}=    Create List
58     ${data}=    Utils.Get Data From URI    controller@{controller_index_list}[0]    /restconf/operational/entity-owners:entity-owners
59     Log    ${data}
60     ${clear_data}=    Run Keyword If    '${device_type}' == 'openflow'    Extract OpenFlow Device Data    ${data}
61     ...    ELSE IF    '${device_type}' == 'ovsdb'    Extract Ovsdb Device Data    ${data}
62     ...    ELSE    Fail    Not recognized device type: ${device_type}
63     ${json}=    RequestsLibrary.To Json    ${clear_data}
64     ${entity_type_list}=    Get From Dictionary    &{json}[entity-owners]    entity-type
65     ${entity_type_index}=    Get Index From List Of Dictionaries    ${entity_type_list}    type    ${device_type}
66     Should Not Be Equal    ${entity_type_index}    -1    No Entity Owner found for ${device_type}
67     ${entity_list}=    Get From Dictionary    @{entity_type_list}[${entity_type_index}]    entity
68     ${entity_index}=    Utils.Get Index From List Of Dictionaries    ${entity_list}    id    ${device}
69     Should Not Be Equal    ${entity_index}    -1    Device ${device} not found in Entity Owner ${device_type}
70     ${entity_owner}=    Get From Dictionary    @{entity_list}[${entity_index}]    owner
71     Should Not Be Empty    ${entity_owner}    No owner found for ${device}
72     ${owner}=    Replace String    ${entity_owner}    member-    ${EMPTY}
73     ${owner}=    Convert To Integer    ${owner}
74     List Should Contain Value    ${controller_index_list}    ${owner}    Owner ${owner} not exisiting in ${controller_index_list}
75     ${entity_candidates_list}=    Get From Dictionary    @{entity_list}[${entity_index}]    candidate
76     ${list_length}=    Get Length    ${entity_candidates_list}
77     : FOR    ${entity_candidate}    IN    @{entity_candidates_list}
78     \    ${candidate}=    Replace String    &{entity_candidate}[name]    member-    ${EMPTY}
79     \    ${candidate}=    Convert To Integer    ${candidate}
80     \    Append To List    ${candidates_list}    ${candidate}
81     List Should Contain Sublist    ${candidates_list}    ${controller_index_list}    Candidates are missing in ${candidates_list}
82     Remove Values From List    ${candidates_list}    ${owner}
83     [Return]    ${owner}    ${candidates_list}
84
85 Extract OpenFlow Device Data
86     [Arguments]    ${data}
87     [Documentation]    Remove superfluous OpenFlow device data from Entity Owner printout.
88     ${clear_data}=    Replace String    ${data}    /general-entity:entity[general-entity:name='    ${EMPTY}
89     ${clear_data}=    Replace String    ${clear_data}    ']    ${EMPTY}
90     Log    ${clear_data}
91     [Return]    ${clear_data}
92
93 Extract Ovsdb Device Data
94     [Arguments]    ${data}
95     [Documentation]    Remove superfluous OVSDB device data from Entity Owner printout.
96     ${clear_data}=    Replace String    ${data}    /network-topology:network-topology/network-topology:topology[network-topology:topology-id='ovsdb:1']/network-topology:node[network-topology:node-id='    ${EMPTY}
97     ${clear_data}=    Replace String    ${clear_data}    ']    ${EMPTY}
98     Log    ${clear_data}
99     [Return]    ${clear_data}
100
101 Check Item Occurrence At URI In Cluster
102     [Arguments]    ${controller_index_list}    ${dictionary_item_occurrence}    ${uri}
103     [Documentation]    Send a GET with the supplied ${uri} to all cluster instances in ${controller_index_list}
104     ...    and check for occurrences of items expressed in a dictionary ${dictionary_item_occurrence}.
105     : FOR    ${i}    IN    @{controller_index_list}
106     \    ${data}    Utils.Get Data From URI    controller${i}    ${uri}
107     \    Log    ${data}
108     \    Utils.Check Item Occurrence    ${data}    ${dictionary_item_occurrence}
109
110 Put And Check At URI In Cluster
111     [Arguments]    ${controller_index_list}    ${controller_index}    ${uri}    ${body}
112     [Documentation]    Send a PUT with the supplied ${uri} and ${body} (json string) to a ${controller_index}
113     ...    and check the data is replicated in all instances in ${controller_index_list}.
114     ${expected_body}=    Hsf Json    ${body}
115     Log    ${body}
116     ${resp}    RequestsLibrary.Put Request    controller${controller_index}    ${uri}    data=${body}    headers=${HEADERS_YANG_JSON}
117     Log    ${resp.content}
118     Log    ${resp.status_code}
119     ${status_code}=    Convert To String    ${resp.status_code}
120     Should Match Regexp    ${status_code}    20(0|1)
121     : FOR    ${i}    IN    @{controller_index_list}
122     \    ${data}    Wait Until Keyword Succeeds    5s    1s    Get Data From URI    controller${i}
123     \    ...    ${uri}
124     \    Log    ${data}
125     \    ${received_body}    Hsf Json    ${data}
126     \    Should Be Equal    ${expected_body}    ${received_body}
127
128 Delete And Check At URI In Cluster
129     [Arguments]    ${controller_index_list}    ${controller_index}    ${uri}
130     [Documentation]    Send a DELETE with the supplied ${uri} to a ${controller_index}
131     ...    and check the data is removed from all instances in ${controller_index_list}.
132     ${resp}    RequestsLibrary.Delete Request    controller${controller_index}    ${uri}
133     Should Be Equal As Strings    ${resp.status_code}    200
134     : FOR    ${i}    IN    @{controller_index_list}
135     \    Wait Until Keyword Succeeds    5s    1s    No Content From URI    controller${i}    ${uri}
136
137 Kill Multiple Controllers
138     [Arguments]    @{controller_index_list}
139     [Documentation]    Give this keyword a scalar or list of controllers to be stopped.
140     : FOR    ${i}    IN    @{controller_index_list}
141     \    ${output}=    Utils.Run Command On Controller    ${ODL_SYSTEM_${i}_IP}    ps axf | grep karaf | grep -v grep | awk '{print \"kill -9 \" $1}' | sh
142     \    ClusterKeywords.Controller Down Check    ${ODL_SYSTEM_${i}_IP}
143
144 Start Multiple Controllers
145     [Arguments]    ${timeout}    @{controller_index_list}
146     [Documentation]    Give this keyword a scalar or list of controllers to be started.
147     : FOR    ${i}    IN    @{controller_index_list}
148     \    ${output}=    Utils.Run Command On Controller    ${ODL_SYSTEM_${i}_IP}    ${WORKSPACE}/${BUNDLEFOLDER}/bin/start
149     : FOR    ${i}    IN    @{controller_index_list}
150     \    ClusterKeywords.Wait For Controller Sync    ${timeout}    ${ODL_SYSTEM_${i}_IP}
151
152 Get Controller List
153     [Arguments]    ${exclude_controller}=${EMPTY}
154     [Documentation]    Creates a list of all controllers minus any excluded controller.
155     Log    ${exclude_controller}
156     @{searchlist}    Create List    ${ODL_SYSTEM_IP}    ${ODL_SYSTEM_2_IP}    ${ODL_SYSTEM_3_IP}
157     Remove Values From List    ${searchlist}    ${exclude_controller}
158     Log    ${searchlist}
159     [Return]    ${searchlist}
160
161 Get Leader And Verify
162     [Arguments]    ${shard_name}    ${old_leader}=${EMPTY}
163     [Documentation]    Returns the IP addr or hostname of the leader of the specified shard.
164     ...    Controllers are specifed in the pybot command line.
165     ${searchlist}    Get Controller List    ${old_leader}
166     ${leader}    GetLeader    ${shard_name}    ${3}    ${3}    ${1}    ${RESTCONFPORT}
167     ...    @{searchlist}
168     Should Not Be Equal As Strings    ${leader}    None
169     Run Keyword If    '${old_leader}'!='${EMPTY}'    Should Not Be Equal    ${old_leader}    ${leader}
170     [Return]    ${leader}
171
172 Expect No Leader
173     [Arguments]    ${shard_name}
174     [Documentation]    No leader is elected in the car shard
175     ${leader}    GetLeader    ${shard_name}    ${3}    ${1}    ${1}    ${RESTCONFPORT}
176     ...    ${CURRENT_CAR_LEADER}
177     Should Be Equal As Strings    ${leader}    None
178
179 Get All Followers
180     [Arguments]    ${shard_name}    ${exclude_controller}=${EMPTY}
181     [Documentation]    Returns the IP addresses or hostnames of all followers of the specified shard.
182     ${searchlist}    Get Controller List    ${exclude_controller}
183     ${followers}    GetFollowers    ${shard_name}    ${3}    ${3}    ${1}    ${RESTCONFPORT}
184     ...    @{searchlist}
185     Log    ${followers}
186     Should Not Be Empty    ${followers}
187     [Return]    ${followers}
188
189 Stop One Or More Controllers
190     [Arguments]    @{controllers}
191     [Documentation]    Give this keyword a scalar or list of controllers to be stopped.
192     ${cmd} =    Set Variable    ${KARAF_HOME}/bin/stop
193     : FOR    ${ip}    IN    @{controllers}
194     \    Run Command On Remote System    ${ip}    ${cmd}
195
196 Kill One Or More Controllers
197     [Arguments]    @{controllers}
198     [Documentation]    Give this keyword a scalar or list of controllers to be stopped.
199     ${cmd} =    Set Variable    ps axf | grep karaf | grep -v grep | awk '{print \"kill -9 \" $1}' | sh
200     log    ${cmd}
201     : FOR    ${ip}    IN    @{controllers}
202     \    Run Command On Remote System    ${ip}    ${cmd}
203
204 Wait For Cluster Down
205     [Arguments]    ${timeout}    @{controllers}
206     [Documentation]    Waits for one or more clustered controllers to be down.
207     : FOR    ${ip}    IN    @{controllers}
208     \    ${status}=    Run Keyword And Return Status    Wait For Controller Down    ${timeout}    ${ip}
209     \    Exit For Loop If    '${status}' == 'FAIL'
210
211 Wait For Controller Down
212     [Arguments]    ${timeout}    ${ip}
213     [Documentation]    Waits for one controllers to be down.
214     Wait Until Keyword Succeeds    ${timeout}    2s    Controller Down Check    ${ip}
215
216 Controller Down Check
217     [Arguments]    ${ip}
218     [Documentation]    Checks to see if a controller is down by verifying that the karaf process isn't present.
219     ${cmd} =    Set Variable    ps axf | grep karaf | grep -v grep | wc -l
220     ${response}    Run Command On COntroller    ${ip}    ${cmd}
221     Log    Number of controller instances running: ${response}
222     Should Start With    ${response}    0    Controller process found or there may be extra instances of karaf running on the host machine.
223
224 Start One Or More Controllers
225     [Arguments]    @{controllers}
226     [Documentation]    Give this keyword a scalar or list of controllers to be started.
227     ${cmd} =    Set Variable    ${KARAF_HOME}/bin/start
228     : FOR    ${ip}    IN    @{controllers}
229     \    Run Command On Remote System    ${ip}    ${cmd}
230
231 Wait For Cluster Sync
232     [Arguments]    ${timeout}    @{controllers}
233     [Documentation]    Waits for one or more clustered controllers to report Sync Status as true.
234     : FOR    ${ip}    IN    @{controllers}
235     \    ${status}=    Run Keyword And Return Status    Wait For Controller Sync    ${timeout}    ${ip}
236     \    Exit For Loop If    '${status}' == 'FAIL'
237
238 Wait For Controller Sync
239     [Arguments]    ${timeout}    ${ip}
240     [Documentation]    Waits for one controllers to report Sync Status as true.
241     Wait Until Keyword Succeeds    ${timeout}    2s    Controller Sync Status Should Be True    ${ip}
242
243 Controller Sync Status Should Be True
244     [Arguments]    ${ip}
245     [Documentation]    Checks if Sync Status is true.
246     ${SyncStatus}=    Get Controller Sync Status    ${ip}
247     Should Be Equal    ${SyncStatus}    ${TRUE}
248
249 Controller Sync Status Should Be False
250     [Arguments]    ${ip}
251     [Documentation]    Checks if Sync Status is false.
252     ${SyncStatus}=    Get Controller Sync Status    ${ip}
253     Should Be Equal    ${SyncStatus}    ${FALSE}
254
255 Get Controller Sync Status
256     [Arguments]    ${controller_ip}
257     [Documentation]    Return Sync Status.
258     Create_Session    session    http://${controller_ip}:${RESTCONFPORT}    headers=${HEADERS}    auth=${AUTH}
259     ${data}=    Get Data From URI    session    ${jolokia_conf}
260     Log    ${data}
261     ${json}=    To Json    ${data}
262     ${value}=    Get From Dictionary    ${json}    value
263     ${ConfSyncStatus}=    Get From Dictionary    ${value}    SyncStatus
264     Log    Configuration Sync Status: ${ConfSyncStatus}
265     ${data}=    Get Data From URI    session    ${jolokia_oper}
266     Log    ${data}
267     ${json}=    To Json    ${data}
268     ${value}=    Get From Dictionary    ${json}    value
269     ${OperSyncStatus}=    Get From Dictionary    ${value}    SyncStatus
270     Log    Operational Sync Status: ${OperSyncStatus}
271     Run Keyword If    ${OperSyncStatus} and ${ConfSyncStatus}    Set Test Variable    ${SyncStatus}    ${TRUE}
272     ...    ELSE    Set Test Variable    ${SyncStatus}    ${FALSE}
273     [Return]    ${SyncStatus}
274
275 Clean One Or More Journals
276     [Arguments]    @{controllers}
277     [Documentation]    Give this keyword a scalar or list of controllers on which to clean journals.
278     ${del_cmd} =    Set Variable    rm -rf ${KARAF_HOME}/journal
279     : FOR    ${ip}    IN    @{controllers}
280     \    Run Command On Remote System    ${ip}    ${del_cmd}
281
282 Clean One Or More Snapshots
283     [Arguments]    @{controllers}
284     [Documentation]    Give this keyword a scalar or list of controllers on which to clean snapshots.
285     ${del_cmd} =    Set Variable    rm -rf ${KARAF_HOME}/snapshots
286     : FOR    ${ip}    IN    @{controllers}
287     \    Run Command On Remote System    ${ip}    ${del_cmd}
288
289 Show Cluster Configuation Files
290     [Arguments]    @{controllers}
291     [Documentation]    Prints out the cluster configuration files for one or more controllers.
292     Log    controllers: @{controllers}
293     ${cmd} =    Set Variable    cat ${KARAF_HOME}/configuration/initial/akka.conf
294     : FOR    ${ip}    IN    @{controllers}
295     \    Run Command On Remote System    ${ip}    ${cmd}
296     ${cmd} =    Set Variable    cat ${KARAF_HOME}/configuration/initial/modules.conf
297     : FOR    ${ip}    IN    @{controllers}
298     \    Run Command On Remote System    ${ip}    ${cmd}
299     ${cmd} =    Set Variable    cat ${KARAF_HOME}/configuration/initial/module-shards.conf
300     : FOR    ${ip}    IN    @{controllers}
301     \    Run Command On Remote System    ${ip}    ${cmd}
302     ${cmd} =    Set Variable    cat ${KARAF_HOME}/configuration/initial/jolokia.xml
303     : FOR    ${ip}    IN    @{controllers}
304     \    Run Command On Remote System    ${ip}    ${cmd}
305     ${cmd} =    Set Variable    cat ${KARAF_HOME}/etc/initial/org.apache.karaf.management.cfg
306     : FOR    ${ip}    IN    @{controllers}
307     \    Run Command On Remote System    ${ip}    ${cmd}
308     ${cmd} =    Set Variable    cat ${KARAF_HOME}/etc/org.apache.karaf.features.cfg
309     : FOR    ${ip}    IN    @{controllers}
310     \    Run Command On Remote System    ${ip}    ${cmd}
311
312 Isolate a Controller From Cluster
313     [Arguments]    ${isolated controller}    @{controllers}
314     [Documentation]    Use IPTables to isolate one controller from the cluster.
315     ...    On the isolated controller it blocks IP traffic to and from each of the other controllers.
316     : FOR    ${controller}    IN    @{controllers}
317     \    ${other controller}=    Evaluate    "${isolated controller}" != "${controller}"
318     \    Run Keyword If    ${other controller}    Isolate One Controller From Another    ${isolated controller}    ${controller}
319
320 Rejoin a Controller To Cluster
321     [Arguments]    ${isolated controller}    @{controllers}
322     [Documentation]    Use IPTables to rejoin one controller to the cluster.
323     ...    On the isolated controller it unblocks IP traffic to and from each of the other controllers.
324     : FOR    ${controller}    IN    @{controllers}
325     \    ${other controller}=    Evaluate    "${isolated controller}" != "${controller}"
326     \    Run Keyword If    ${other controller}    Rejoin One Controller To Another    ${isolated controller}    ${controller}
327
328 Isolate One Controller From Another
329     [Arguments]    ${isolated controller}    ${controller}
330     [Documentation]    Inserts an IPTable rule to disconnect one controller from another controller in the cluster.
331     Modify IPTables    ${isolated controller}    ${controller}    -I
332
333 Rejoin One Controller To Another
334     [Arguments]    ${isolated controller}    ${controller}
335     [Documentation]    Deletes an IPTable rule, allowing one controller to reconnect to another controller in the cluster.
336     Modify IPTables    ${isolated controller}    ${controller}    -D
337
338 Modify IPTables
339     [Arguments]    ${isolated controller}    ${controller}    ${rule type}
340     [Documentation]    Adds a rule, usually inserting or deleting an entry between two controllers.
341     ${base string}    Set Variable    sudo iptables ${rule type} OUTPUT -p all --source
342     ${cmd string}    Catenate    ${base string}    ${isolated controller} --destination ${controller} -j DROP
343     Run Command On Remote System    ${isolated controller}    ${cmd string}
344     ${cmd string}    Catenate    ${base string}    ${controller} --destination ${isolated controller} -j DROP
345     Run Command On Remote System    ${isolated controller}    ${cmd string}
346     ${cmd string}    Set Variable    sudo iptables -L -n
347     ${return string}=    Run Command On Remote System    ${isolated controller}    ${cmd string}
348     #If inserting rules:
349     Run Keyword If    "${rule type}" == '-I'    Should Match Regexp    ${return string}    [\s\S]*DROP *all *-- *${isolated controller} *${controller}[\s\S]*
350     Run Keyword If    "${rule type}" == '-I'    Should Match Regexp    ${return string}    [\s\S]*DROP *all *-- *${controller} *${isolated controller}[\s\S]*
351     #If deleting rules:
352     Run Keyword If    "${rule type}" == '-D'    Should Match Regexp    ${return string}    (?![\s\S]*DROP *all *-- *${isolated controller} *${controller}[\s\S]*)
353     Run Keyword If    "${rule type}" == '-D'    Should Match Regexp    ${return string}    (?![\s\S]*DROP *all *-- *${controller} *${isolated controller}[\s\S]*)
354
355 Rejoin All Isolated Controllers
356     [Arguments]    @{controllers}
357     [Documentation]    Wipe all IPTables rules from all controllers, thus rejoining all controllers.
358     : FOR    ${isolated controller}    IN    @{controllers}
359     \    Flush IPTables    ${isolated controller}
360
361 Flush IPTables
362     [Arguments]    ${isolated controller}
363     [Documentation]    This keyword is generally not called from a test case but supports a complete wipe of all rules on
364     ...    all contollers.
365     ${cmd string}    Set Variable    sudo iptables -v -F
366     ${return string}=    Run Command On Remote System    ${isolated controller}    ${cmd string}
367     Log    return: ${return string}
368     Should Contain    ${return string}    Flushing chain `INPUT'
369     Should Contain    ${return string}    Flushing chain `FORWARD'
370     Should Contain    ${return string}    Flushing chain `OUTPUT'