4444text = f .read ()
4545env .instance_ids = text .split ('\n ' )
4646
47- print 'Read %i bees from the roster' % len (env .instance_ids )
47+ print 'Read %i bees from the roster. ' % len (env .instance_ids )
4848else :
4949env .instance_ids = []
5050
@@ -113,7 +113,7 @@ def report():
113113instances .extend (reservation .instances )
114114
115115for instance in instances :
116- print 'Bee ' + instance .id + ': ' + instance .state
116+ print 'Bee %s: %s' % ( instance .id , instance .state )
117117
118118def down ():
119119"""
@@ -155,22 +155,67 @@ def _attack(params):
155155
156156stdin , stdout , stderr = client .exec_command ('ab -r -n %(num_requests)s -c %(concurrent_requests)s -C "sessionid=NotARealSessionID" %(url)s' % params )
157157
158+ response = {}
159+
158160ab_results = stdout .read ()
159- s = re .search ('Time\ per\ request:\s+([0-9.]+)\ \[ms\]\ \(mean\)' , ab_results )
161+ ms_per_request_search = re .search ('Time\ per\ request:\s+([0-9.]+)\ \[ms\]\ \(mean\)' , ab_results )
160162
161- if not s :
163+ if not ms_per_request_search :
162164print 'Bee %i lost sight of the target (connection timed out).' % params ['i' ]
163165return None
166+
167+ requests_per_second_search = re .search ('Requests\ per\ second:\s+([0-9.]+)\ \[#\/sec\]\ \(mean\)' , ab_results )
168+ fifty_percent_search = re .search ('\s+50\%\s+([0-9]+)' , ab_results )
169+ ninety_percent_search = re .search ('\s+90\%\s+([0-9]+)' , ab_results )
164170
165- ms_per_request = float (s .group (1 ))
171+ response ['ms_per_request' ] = float (ms_per_request_search .group (1 ))
172+ response ['requests_per_second' ] = float (requests_per_second_search .group (1 ))
173+ response ['fifty_percent' ] = float (fifty_percent_search .group (1 ))
174+ response ['ninety_percent' ] = float (ninety_percent_search .group (1 ))
166175
167176print 'Bee %i is out of ammo.' % params ['i' ]
168177
169178client .close ()
170179
171- return ms_per_request
180+ return response
181+
182+ def _print_results (results ):
183+ """
184+ Print summarized load-testing results.
185+ """
186+ incomplete_results = [r for r in results if r is None ]
187+
188+ if incomplete_results :
189+ print ' Target failed to fully respond to %i bees.' % incomplete_results
172190
173- def test (url , c = 10 , n = 100 ):
191+ complete_results = [r ['requests_per_second' ] for r in results if r is not None ]
192+ mean_requests = sum (complete_results ) / len (complete_results )
193+ print ' Requests per second:\t %f [#/sec] (mean)' % mean_requests
194+
195+ complete_results = [r ['ms_per_request' ] for r in results if r is not None ]
196+ mean_response = sum (complete_results ) / len (complete_results )
197+ print ' Time per request:\t \t %f [ms] (mean)' % mean_response
198+
199+ complete_results = [r ['fifty_percent' ] for r in results if r is not None ]
200+ mean_fifty = sum (complete_results ) / len (complete_results )
201+ print ' 50%% response times:\t %f [ms] (mean)' % mean_fifty
202+
203+ complete_results = [r ['ninety_percent' ] for r in results if r is not None ]
204+ mean_ninety = sum (complete_results ) / len (complete_results )
205+ print ' 90%% response times:\t %f [ms] (mean)' % mean_ninety
206+
207+ if mean_response < 500 :
208+ print 'Mission Assessment: Target crushed bee offensive.'
209+ elif mean_response < 1000 :
210+ print 'Mission Assessment: Target successfully fended off the swarm.'
211+ elif mean_response < 1500 :
212+ print 'Mission Assessment: Target wounded, but operational.'
213+ elif mean_response < 2000 :
214+ print 'Mission Assessment: Target severely compromised.'
215+ else :
216+ print 'Mission Assessment: Swarm annihilated target.'
217+
218+ def attack (url , n = 10000 , c = 100 ):
174219"""
175220 Test the root url of this site.
176221 """
@@ -190,8 +235,12 @@ def test(url, c=10, n=100):
190235
191236for reservation in reservations :
192237instances .extend (reservation .instances )
238+
239+ instance_count = len (instances )
240+ requests_per_instance = int (n ) / instance_count
241+ connections_per_instance = int (c ) / instance_count
193242
194- print 'Each bee will make %s concurrent requests and %s total requests.' % (c , n )
243+ print 'Each of %i bees will make %s concurrent requests and %s total requests.' % (instance_count , connections_per_instance , requests_per_instance )
195244
196245params = []
197246
@@ -201,40 +250,23 @@ def test(url, c=10, n=100):
201250'instance_id' : instance .id ,
202251'instance_name' : instance .public_dns_name ,
203252'url' : url ,
204- 'concurrent_requests' : c ,
205- 'num_requests' : n ,
253+ 'concurrent_requests' : connections_per_instance ,
254+ 'num_requests' : requests_per_instance ,
206255 })
207256
208257print 'Stinging URL so it will be cached for the attack.'
209258
210259# Ping url so it will be cached for testing
211260local ('curl %s >> /dev/null' % url )
212261
213- print 'Assembling the swarm.'
262+ print 'Organizing the swarm.'
214263
215264# Spin up processes for connecting to EC2 instances
216265pool = Pool (len (params ))
217266results = pool .map (_attack , params )
218267
219- complete_results = [r for r in results if r is not None ]
220- incomplete_results = [r for r in results if r is None ]
221-
222- mean_response = sum (complete_results ) / len (complete_results )
268+ print 'Offensive complete.'
223269
224- if incomplete_results :
225- print 'Target failed to fully respond to %i bees.' % incomplete_results
226-
227- print 'Target responded to bees at an average rate of %f ms.' % mean_response
228-
229- if mean_response < 500 :
230- print 'Mission Assessment: Target crushed bee offensive.'
231- elif mean_response < 1000 :
232- print 'Mission Assessment: Target successfully fended off the swarm.'
233- elif mean_response < 1500 :
234- print 'Mission Assessment: Target wounded, but operational.'
235- elif mean_response < 2000 :
236- print 'Mission Assessment: Target severely compromised.'
237- else :
238- print 'Mission Assessment: Swarm annihilated target.'
239-
270+ _print_results (results )
271+
240272print 'The swarm is awaiting new orders.'
0 commit comments