Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Multiple security groups #38

Closed
wants to merge 7 commits into from

2 participants

@andreyavramchikov

Added opportunity to specify more than one security groups
and support of argparse for python2.7 and higher(optparse is deprecated since python2.7)

Examples :
python >= 2.7 :
-g group1 group2 group3

python <= 2.6 :
multiple security groups : -g 'group1,group2,group3'
one security group: -g group1 or -g 'group1'

@cosmin
Collaborator

+1 on supporting multiple security groups, although maintaining both optparse and argparse is not ideal. I also don't like the idea of pushing implementation details of Python 2.6 vs 2.7+ onto the user

@cosmin cosmin closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 7, 2012
  1. @andreyavramchikov
  2. @andreyavramchikov
Commits on Sep 10, 2012
  1. @andreyavramchikov
Commits on Sep 11, 2012
  1. @andreyavramchikov

    refactoring

    andreyavramchikov authored
Commits on Sep 12, 2012
  1. @andreyavramchikov
Commits on Sep 14, 2012
  1. @andreyavramchikov

    refactoring

    andreyavramchikov authored
  2. @andreyavramchikov

    code cleanups

    andreyavramchikov authored
This page is out of date. Refresh to see the latest.
Showing with 138 additions and 73 deletions.
  1. +2 −2 beeswithmachineguns/bees.py
  2. +136 −71 beeswithmachineguns/main.py
View
4 beeswithmachineguns/bees.py
@@ -99,7 +99,7 @@ def up(count, group, zone, image_id, username, key_name):
min_count=count,
max_count=count,
key_name=key_name,
- security_groups=[group],
+ security_groups=group,
instance_type=EC2_INSTANCE_TYPE,
placement=zone)
@@ -171,7 +171,7 @@ def down():
def _attack(params):
"""
Test the target URL with requests.
-
+
Intended for use with multiprocessing.
"""
print 'Bee %i is joining the swarm.' % params['i']
View
207 beeswithmachineguns/main.py
@@ -30,99 +30,164 @@
from optparse import OptionParser, OptionGroup
NO_TRAILING_SLASH_REGEX = re.compile(r'^.*?\.\w+$')
+PYTHON_VERSION = "%s.%s" % (sys.version_info[0], sys.version_info[1])
def parse_options():
+
"""
Handle the command line arguments for spinning up bees
- """
- command = sys,
- parser = OptionParser(usage="""
-bees COMMAND [options]
-
-Bees with Machine Guns
-
-A utility for arming (creating) many bees (small EC2 instances) to attack
-(load test) targets (web applications).
-
-commands:
- up Start a batch of load testing servers.
- attack Begin the attack on a specific url.
- down Shutdown and deactivate the load testing servers.
- report Report the status of the load testing servers.
- """)
-
- up_group = OptionGroup(parser, "up",
+ """
+ config_options_up = (
+ (('-k','--key'), {'metavar' : "KEY",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'key',
+ 'help' : 'The ssh key pair name to use to connect to the new servers.'}),
+ (('-s','--servers'), {'metavar' : "SERVERS",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'servers',
+ 'default':5,
+ 'help' :'The number of servers to start (default: 5).'}),
+ (('-g', '--group'), {'metavar' : "GROUP",
+ 'nargs' : '*' if PYTHON_VERSION >= '2.7' else 1,
+ 'action' : 'store',
+ 'dest' : 'group',
+ 'default' : 'default',
+ 'help' : 'The security group to run the instances under (default: default).'}),
+ (('-z', '--zone'), {'metavar' : "ZONE",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'zone',
+ 'default' : 'us-east-1d',
+ 'help' : 'The availability zone to start the instances in (default: us-east-1d).'}),
+ (('-i', '--instance'),{'metavar' : "INSTANCE",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'instance',
+ 'default' : 'ami-ff17fb96',
+ 'help' :'The instance-id to use for each server from (default: ami-ff17fb96).'}),
+ (('-l', '--login'), {'metavar' : "LOGIN",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'login',
+ 'default' : 'newsapps',
+ 'help' : 'The ssh username name to use to connect to the new servers (default: newsapps).'}))
+
+ config_options_attack = [
+ (('-u', '--url'), {'metavar' : "URL",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'url',
+ 'help' : 'URL of the target to attack.'}),
+ (('-n', '--number'), {'metavar' : "NUMBER",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'number',
+ 'default' : 1000,
+ 'help' : 'The number of total connections to make to the target (default: 1000).'}),
+ (('-c', '--concurrent'),{'metavar' : "CONCURRENT",
+ 'nargs' : 1,
+ 'action' : 'store',
+ 'dest' : 'concurrent',
+ 'default' : 100,
+ 'help' : 'The number of concurrent connections to make to the target (default: 100).'})]
+
+ if PYTHON_VERSION >= "2.7":
+ import argparse
+ parser = argparse.ArgumentParser(add_help=True)
+
+ subparsers = parser.add_subparsers(help='commands', dest='command')
+ up_parser = subparsers.add_parser('up')
+ attack_parser = subparsers.add_parser('attack')
+ down_parser = subparsers.add_parser('down')
+ report_parser = subparsers.add_parser('report')
+
+ [up_parser.add_argument(*config_up[0],**config_up[1]) for config_up in config_options_up]
+
+ [attack_parser.add_argument(*config_attack[0],**config_attack[1]) for config_attack in config_options_attack]
+
+ command, options = parse_opt(parser.parse_args())
+ else:
+ #if version less than 2.7
+ parser = OptionParser(usage="""
+ bees COMMAND [options]
+ Bees with Machine Guns
+ A utility for arming (creating) many bees (small EC2 instances) to attack
+ (load test) targets (web applications).
+
+ commands:
+ up Start a batch of load testing servers.
+ attack Begin the attack on a specific url.
+ down Shutdown and deactivate the load testing servers.
+ report Report the status of the load testing servers.
+ """)
+
+ up_group = OptionGroup(parser, "up",
"""In order to spin up new servers you will need to specify at least the -k command, which is the name of the EC2 keypair to use for creating and connecting to the new servers. The bees will expect to find a .pem file with this name in ~/.ssh/.""")
+
+ #up_parser.add_argument([(*config_up[0],**config_up[1]) for config_up in config_options_up])
+
+ [parser.add_option(*config_up[0],**config_up[1]) for config_up in config_options_up]
- # Required
- up_group.add_option('-k', '--key', metavar="KEY", nargs=1,
- action='store', dest='key', type='string',
- help="The ssh key pair name to use to connect to the new servers.")
-
- up_group.add_option('-s', '--servers', metavar="SERVERS", nargs=1,
- action='store', dest='servers', type='int', default=5,
- help="The number of servers to start (default: 5).")
- up_group.add_option('-g', '--group', metavar="GROUP", nargs=1,
- action='store', dest='group', type='string', default='default',
- help="The security group to run the instances under (default: default).")
- up_group.add_option('-z', '--zone', metavar="ZONE", nargs=1,
- action='store', dest='zone', type='string', default='us-east-1d',
- help="The availability zone to start the instances in (default: us-east-1d).")
- up_group.add_option('-i', '--instance', metavar="INSTANCE", nargs=1,
- action='store', dest='instance', type='string', default='ami-ff17fb96',
- help="The instance-id to use for each server from (default: ami-ff17fb96).")
- up_group.add_option('-l', '--login', metavar="LOGIN", nargs=1,
- action='store', dest='login', type='string', default='newsapps',
- help="The ssh username name to use to connect to the new servers (default: newsapps).")
-
- parser.add_option_group(up_group)
-
- attack_group = OptionGroup(parser, "attack",
- """Beginning an attack requires only that you specify the -u option with the URL you wish to target.""")
-
- # Required
- attack_group.add_option('-u', '--url', metavar="URL", nargs=1,
- action='store', dest='url', type='string',
- help="URL of the target to attack.")
-
- attack_group.add_option('-n', '--number', metavar="NUMBER", nargs=1,
- action='store', dest='number', type='int', default=1000,
- help="The number of total connections to make to the target (default: 1000).")
- attack_group.add_option('-c', '--concurrent', metavar="CONCURRENT", nargs=1,
- action='store', dest='concurrent', type='int', default=100,
- help="The number of concurrent connections to make to the target (default: 100).")
-
- parser.add_option_group(attack_group)
+ parser.add_option_group(up_group)
- (options, args) = parser.parse_args()
-
- if len(args) <= 0:
- parser.error('Please enter a command.')
+ attack_group = OptionGroup(parser, "attack",
+ """Beginning an attack requires only that you specify the -u option with the URL you wish to target.""")
- command = args[0]
+ [parser.add_option(*config_attack[0],**config_attack[1]) for config_attack in config_options_attack]
+
+ parser.add_option_group(attack_group)
+ command, options = parse_opt(parser.parse_args())
+
+
if command == 'up':
if not options.key:
parser.error('To spin up new instances you need to specify a key-pair name with -k')
-
+
if options.group == 'default':
print 'New bees will use the "default" EC2 security group. Please note that port 22 (SSH) is not normally open on this group. You will need to use to the EC2 tools to open it before you will be able to attack.'
-
bees.up(options.servers, options.group, options.zone, options.instance, options.login, options.key)
- elif command == 'attack':
+ elif command == 'attack':
if not options.url:
parser.error('To run an attack you need to specify a url with -u')
-
+
if NO_TRAILING_SLASH_REGEX.match(options.url):
parser.error('It appears your URL lacks a trailing slash, this will disorient the bees. Please try again with a trailing slash.')
-
- bees.attack(options.url, options.number, options.concurrent)
- elif command == 'down':
+
+ bees.attack(options.url,options.number,options.concurrent)
+ elif command == 'down':
bees.down()
elif command == 'report':
bees.report()
-
+
+
+def parse_opt(params):
+ if PYTHON_VERSION >= "2.7":
+ options = params
+ command = options.command
+ if command == "up":
+ options.key = options.key[0]
+ options.zone = options.zone[0]
+ options.servers = options.servers[0]
+ elif command == "attack":
+ options.url = options.url[0]
+ options.number = options.number[0]
+ options.concurrent = options.concurrent[0]
+ else:
+ options = params[0]
+ command = params[1][0]
+ if command == "up":
+ options.group = get_groups(options.group)
+
+
+ return command, options
+
+
+def get_groups (group_str):
+ return [group.strip() for group in group_str.split(',')]
def main():
parse_options()
-
+
Something went wrong with that request. Please try again.