Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 1 | import json |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 2 | import time |
Jon Hall | e1a3b75 | 2015-07-22 13:02:46 -0700 | [diff] [blame] | 3 | |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 4 | class HA(): |
Jon Hall | 57b5043 | 2015-10-22 10:20:10 -0700 | [diff] [blame] | 5 | |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 6 | def __init__( self ): |
| 7 | self.default = '' |
Jon Hall | 57b5043 | 2015-10-22 10:20:10 -0700 | [diff] [blame] | 8 | |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 9 | def consistentCheck( self ): |
| 10 | """ |
| 11 | Checks that TestON counters are consistent across all nodes. |
Jon Hall | e1a3b75 | 2015-07-22 13:02:46 -0700 | [diff] [blame] | 12 | |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 13 | Returns the tuple (onosCounters, consistent) |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 14 | - onosCounters is the parsed json output of the counters command on |
| 15 | all nodes |
| 16 | - consistent is main.TRUE if all "TestON" counters are consitent across |
| 17 | all nodes or main.FALSE |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 18 | """ |
Jon Hall | e1a3b75 | 2015-07-22 13:02:46 -0700 | [diff] [blame] | 19 | try: |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 20 | # Get onos counters results |
| 21 | onosCountersRaw = [] |
| 22 | threads = [] |
| 23 | for i in main.activeNodes: |
| 24 | t = main.Thread( target=utilities.retry, |
| 25 | name="counters-" + str( i ), |
| 26 | args=[ main.CLIs[i].counters, [ None ] ], |
| 27 | kwargs= { 'sleep': 5, 'attempts': 5, |
| 28 | 'randomTime': True } ) |
| 29 | threads.append( t ) |
| 30 | t.start() |
| 31 | for t in threads: |
| 32 | t.join() |
| 33 | onosCountersRaw.append( t.result ) |
| 34 | onosCounters = [] |
| 35 | for i in range( len( main.activeNodes ) ): |
| 36 | try: |
| 37 | onosCounters.append( json.loads( onosCountersRaw[i] ) ) |
| 38 | except ( ValueError, TypeError ): |
| 39 | main.log.error( "Could not parse counters response from ONOS" + |
| 40 | str( main.activeNodes[i] + 1 ) ) |
| 41 | main.log.warn( repr( onosCountersRaw[ i ] ) ) |
| 42 | onosCounters.append( [] ) |
| 43 | |
| 44 | testCounters = {} |
| 45 | # make a list of all the "TestON-*" counters in ONOS |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 46 | # lookes like a dict whose keys are the name of the ONOS node and |
| 47 | # values are a list of the counters. I.E. |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 48 | # { "ONOS1": [ { "name":"TestON-Partitions","value":56} ] |
| 49 | # } |
| 50 | # NOTE: There is an assumtion that all nodes are active |
| 51 | # based on the above for loops |
| 52 | for controller in enumerate( onosCounters ): |
| 53 | for key, value in controller[1].iteritems(): |
| 54 | if 'TestON' in key: |
| 55 | node = 'ONOS' + str( controller[0] + 1 ) |
| 56 | try: |
| 57 | testCounters[node].append( { key: value } ) |
| 58 | except KeyError: |
| 59 | testCounters[node] = [ { key: value } ] |
| 60 | # compare the counters on each node |
| 61 | firstV = testCounters.values()[0] |
| 62 | tmp = [ v == firstV for k, v in testCounters.iteritems() ] |
| 63 | if all( tmp ): |
| 64 | consistent = main.TRUE |
| 65 | else: |
| 66 | consistent = main.FALSE |
| 67 | main.log.error( "ONOS nodes have different values for counters:\n" + |
| 68 | testCounters ) |
| 69 | return ( onosCounters, consistent ) |
| 70 | except Exception: |
| 71 | main.log.exception( "" ) |
| 72 | main.cleanup() |
| 73 | main.exit() |
| 74 | |
| 75 | def counterCheck( self, counterName, counterValue ): |
| 76 | """ |
| 77 | Checks that TestON counters are consistent across all nodes and that |
| 78 | specified counter is in ONOS with the given value |
| 79 | """ |
| 80 | try: |
| 81 | correctResults = main.TRUE |
| 82 | # Get onos counters results and consistentCheck |
| 83 | onosCounters, consistent = self.consistentCheck() |
| 84 | # Check for correct values |
| 85 | for i in range( len( main.activeNodes ) ): |
| 86 | current = onosCounters[i] |
| 87 | onosValue = None |
| 88 | try: |
| 89 | onosValue = current.get( counterName ) |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 90 | except AttributeError: |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 91 | node = str( main.activeNodes[i] + 1 ) |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 92 | main.log.exception( "ONOS" + node + " counters result " + |
| 93 | "is not as expected" ) |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 94 | correctResults = main.FALSE |
| 95 | if onosValue == counterValue: |
| 96 | main.log.info( counterName + " counter value is correct" ) |
| 97 | else: |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 98 | main.log.error( counterName + |
| 99 | " counter value is incorrect," + |
| 100 | " expected value: " + str( counterValue ) + |
| 101 | " current value: " + str( onosValue ) ) |
Jon Hall | a440e87 | 2016-03-31 15:15:50 -0700 | [diff] [blame] | 102 | correctResults = main.FALSE |
| 103 | return consistent and correctResults |
| 104 | except Exception: |
| 105 | main.log.exception( "" ) |
| 106 | main.cleanup() |
| 107 | main.exit() |
Jon Hall | 41d39f1 | 2016-04-11 22:54:35 -0700 | [diff] [blame] | 108 | |
| 109 | def consistentLeaderboards( self, nodes ): |
| 110 | TOPIC = 'org.onosproject.election' |
| 111 | # FIXME: use threads |
| 112 | #FIXME: should we retry outside the function? |
| 113 | for n in range( 5 ): # Retry in case election is still happening |
| 114 | leaderList = [] |
| 115 | # Get all leaderboards |
| 116 | for cli in nodes: |
| 117 | leaderList.append( cli.specificLeaderCandidate( TOPIC ) ) |
| 118 | # Compare leaderboards |
| 119 | result = all( i == leaderList[0] for i in leaderList ) and\ |
| 120 | leaderList is not None |
| 121 | main.log.debug( leaderList ) |
| 122 | main.log.warn( result ) |
| 123 | if result: |
| 124 | return ( result, leaderList ) |
| 125 | time.sleep(5) # TODO: paramerterize |
| 126 | main.log.error( "Inconsistent leaderboards:" + str( leaderList ) ) |
| 127 | return ( result, leaderList ) |
| 128 | |
| 129 | def nodesCheck( self, nodes ): |
| 130 | nodesOutput = [] |
| 131 | results = True |
| 132 | threads = [] |
| 133 | for i in nodes: |
| 134 | t = main.Thread( target=main.CLIs[i].nodes, |
| 135 | name="nodes-" + str( i ), |
| 136 | args=[ ] ) |
| 137 | threads.append( t ) |
| 138 | t.start() |
| 139 | |
| 140 | for t in threads: |
| 141 | t.join() |
| 142 | nodesOutput.append( t.result ) |
| 143 | ips = [ main.nodes[node].ip_address for node in nodes ] |
| 144 | ips.sort() |
| 145 | for i in nodesOutput: |
| 146 | try: |
| 147 | current = json.loads( i ) |
| 148 | activeIps = [] |
| 149 | currentResult = False |
| 150 | for node in current: |
| 151 | if node['state'] == 'READY': |
| 152 | activeIps.append( node['ip'] ) |
| 153 | activeIps.sort() |
| 154 | if ips == activeIps: |
| 155 | currentResult = True |
| 156 | except ( ValueError, TypeError ): |
| 157 | main.log.error( "Error parsing nodes output" ) |
| 158 | main.log.warn( repr( i ) ) |
| 159 | currentResult = False |
| 160 | results = results and currentResult |
| 161 | return results |