def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    command = sys,
    parser = OptionParser(usage="""
bees COMMAND URL [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
    """)

    parser.add_option('-c', '--count', metavar="COUNT", nargs=1,
                       help="number of instance to start")
    parser.add_option('-g', '--group', metavar="GROUP", nargs=1,
                       help="the security group to run the instances under")
    parser.add_option('-z', '--zone',  metavar="ZONE",  nargs=1,
                      help="the availability zone to start the instances in")

    (options, args) = parser.parse_args()

    if not args > 0:
        parser.error("please enter a command")
    command = args[0]
    if command[0] is "attack" and len(args) == 1:
        parser.error("to run an attack you need to present a url")
    url = args[-1].split(",")

    if command == "up":
        bees.up(count=options.count, group=options.group, zone=options.zone)
    elif command == "attack":
        bees.attack(url[0], url[1], url[2])
    elif command == "down":
        bees.down()
Example #2
0
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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/."""
    )

    # 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(s) 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(
        '-t',
        '--type',
        metavar="TYPE",
        nargs=1,
        action='store',
        dest='type',
        type='string',
        default='t1.micro',
        help="The instance-type to use for each server (default: t1.micro).")
    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)."
    )
    up_group.add_option(
        '-v',
        '--subnet',
        metavar="SUBNET",
        nargs=1,
        action='store',
        dest='subnet',
        type='string',
        default=None,
        help=
        "The vpc subnet id in which the instances should be launched. (default: None)."
    )

    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(
        '-p',
        '--post-file',
        metavar="POST_FILE",
        nargs=1,
        action='store',
        dest='post_file',
        type='string',
        default=False,
        help="The POST file to deliver with the bee's payload.")
    attack_group.add_option('-m',
                            '--mime-type',
                            metavar="MIME_TYPE",
                            nargs=1,
                            action='store',
                            dest='mime_type',
                            type='string',
                            default='text/plain',
                            help="The MIME type to send with the request.")
    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',
        '--cookies',
        metavar="COOKIES",
        nargs=1,
        action='store',
        dest='cookies',
        type='string',
        default='',
        help=
        'Cookies to send during http requests. The cookies should be passed using standard cookie formatting, separated by semi-colons and assigned with equals signs.'
    )
    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)."
    )
    attack_group.add_option(
        '-H',
        '--headers',
        metavar="HEADERS",
        nargs=1,
        action='store',
        dest='headers',
        type='string',
        default='',
        help=
        "HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2"
    )
    attack_group.add_option(
        '-e',
        '--csv',
        metavar="FILENAME",
        nargs=1,
        action='store',
        dest='csv_filename',
        type='string',
        default='',
        help=
        "Store the distribution of results in a csv file for all completed bees (default: '')."
    )

    # Optional
    attack_group.add_option(
        '-T',
        '--tpr',
        metavar='TPR',
        nargs=1,
        action='store',
        dest='tpr',
        default=None,
        type='float',
        help=
        'The upper bounds for time per request. If this option is passed and the target is below the value a 1 will be returned with the report details (default: None).'
    )
    attack_group.add_option(
        '-R',
        '--rps',
        metavar='RPS',
        nargs=1,
        action='store',
        dest='rps',
        default=None,
        type='float',
        help=
        'The lower bounds for request per second. If this option is passed and the target is above the value a 1 will be returned with the report details (default: None).'
    )

    parser.add_option_group(attack_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    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.type, options.login, options.key, options.subnet)
    elif command == 'attack':
        if not options.url:
            parser.error('To run an attack you need to specify a url with -u')

        parsed = urlparse(options.url)
        if not parsed.scheme:
            parsed = urlparse("http://" + options.url)

        if not parsed.path:
            parser.error(
                'It appears your URL lacks a trailing slash, this will disorient the bees. Please try again with a trailing slash.'
            )

        additional_options = dict(cookies=options.cookies,
                                  headers=options.headers,
                                  post_file=options.post_file,
                                  mime_type=options.mime_type,
                                  csv_filename=options.csv_filename,
                                  tpr=options.tpr,
                                  rps=options.rps)

        bees.attack(options.url, options.number, options.concurrent,
                    **additional_options)

    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #3
0
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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/. Alternatively, bees can use SSH Agent for the key.""")

    # 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=None,
                        help="The security group(s) to run the instances under (default: create a temporary security group).")
    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('-t', '--type',  metavar="TYPE",  nargs=1,
                        action='store', dest='type', type='string', default='t1.micro',
                        help="The instance-type to use for each server (default: t1.micro).")
    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).")
    up_group.add_option('-v', '--subnet',  metavar="SUBNET",  nargs=1,
                        action='store', dest='subnet', type='string', default=None,
                        help="The vpc subnet id in which the instances should be launched. (default: None).")
    up_group.add_option('-b', '--bid', metavar="BID", nargs=1,
                        action='store', dest='bid', type='float', default=None,
                        help="The maximum bid price per spot instance (default: None).")

    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('-K', '--keepalive', metavar="KEEP_ALIVE", nargs=0,
                            action='store', dest='keep_alive', type='string', default=False,
                            help="Keep-Alive connection.")
    attack_group.add_option('-p', '--post-file',  metavar="POST_FILE",  nargs=1,
                            action='store', dest='post_file', type='string', default=False,
                            help="The POST file to deliver with the bee's payload.")
    attack_group.add_option('-m', '--mime-type',  metavar="MIME_TYPE",  nargs=1,
                            action='store', dest='mime_type', type='string', default='text/plain',
                            help="The MIME type to send with the request.")
    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', '--cookies', metavar="COOKIES", nargs=1, action='store', dest='cookies',
                            type='string', default='',
                            help='Cookies to send during http requests. The cookies should be passed using standard cookie formatting, separated by semi-colons and assigned with equals signs.')
    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).")
    attack_group.add_option('-H', '--headers', metavar="HEADERS", nargs=1,
                            action='store', dest='headers', type='string', default='',
                            help="HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2")
    attack_group.add_option('-e', '--csv', metavar="FILENAME", nargs=1,
                            action='store', dest='csv_filename', type='string', default='',
                            help="Store the distribution of results in a csv file for all completed bees (default: '').")

    # Optional
    attack_group.add_option('-T', '--tpr', metavar='TPR', nargs=1, action='store', dest='tpr', default=None, type='float',
                            help='The upper bounds for time per request. If this option is passed and the target is below the value a 1 will be returned with the report details (default: None).')
    attack_group.add_option('-R', '--rps', metavar='RPS', nargs=1, action='store', dest='rps', default=None, type='float',
                            help='The lower bounds for request per second. If this option is passed and the target is above the value a 1 will be returned with the report details (default: None).')
    attack_group.add_option('-A', '--basic_auth', metavar='basic_auth', nargs=1, action='store', dest='basic_auth', default='', type='string',
                            help='BASIC authentication credentials, format auth-username:password (default: None).')

    parser.add_option_group(attack_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    if command == 'up':
        if not options.key:
            parser.error('To spin up new instances you need to specify a key-pair name with -k')

        bees.up(options.servers, options.group, options.zone, options.instance, options.type, options.login, options.key, options.subnet, options.bid)
    elif command == 'attack':
        if not options.url:
            parser.error('To run an attack you need to specify a url with -u')

        parsed = urlparse(options.url)
        if "/" not in parsed.path:
            if not parsed.scheme:
                parsed = urlparse("http://" + options.url + "/")
            else:
                parsed = urlparse(options.url + "/")
        if not parsed.scheme:
                parsed = urlparse("http://" + options.url)
        additional_options = dict(
            cookies=options.cookies,
            headers=options.headers,
            post_file=options.post_file,
            keep_alive=options.keep_alive,
            mime_type=options.mime_type,
            csv_filename=options.csv_filename,
            tpr=options.tpr,
            rps=options.rps,
            basic_auth=options.basic_auth
        )

        bees.attack(options.url, options.number, options.concurrent, **additional_options)

    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #4
0
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", 
        """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/.""")

    # 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)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error("Please enter a command.")

    command = args[0]

    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":
        if not options.url:
            parser.error("To run an attack you need to specify a url with -u")
        
        bees.attack(options.url, options.number, options.concurrent)
    elif command == "down":
        bees.down()
    elif command == "report":
        bees.report()
Example #5
0
def parse_options():
    
    """
    Handle the command line arguments for spinning up bees
    """     
    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]

        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.""")

        [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':    
        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.down()
    elif command == 'report':
        bees.report()
Example #6
0
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",
        """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/.""")

    # 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-33dd7e58',
                        help="The instance-id to use for each server from (default: ami-33dd7e58).")
    up_group.add_option('-t', '--instance_type',  metavar="INSTANCE_TYPE",  nargs=1,
                        action='store', dest='instance_type', type='string', default='t2.micro',
                        help="The ec2 instance type to use for each server (default: t2.micro).")
    up_group.add_option('-l', '--login',  metavar="LOGIN",  nargs=1,
                        action='store', dest='login', type='string', default='ec2-user',
                        help="The ssh username name to use to connect to the new servers (default: ec2-user).")

    parser.add_option_group(up_group)

    attack_group = OptionGroup(parser, "attack",
            """Beginning an attack requires that you specify the URL(s) you wish to target, either using -u or -f.""")

    # 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('-f', '--url-file', metavar="URL_FILE", nargs=1,
                        action='store', dest='url_file', type='string',
                        help="file containing URLs of the targets 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).")
    attack_group.add_option('--keepalive', metavar="KEEPALIVE",
                            action='store_true', dest='keepalive', default=False,
                            help='Whether or not to use ab keepalive (default: False)')
    attack_group.add_option('--use-wideload', action='store_const', dest='engine', const='wideload',
                            help='Use wideload to generate load.')
    attack_group.add_option('--use-siege', action='store_const', dest='engine', const='siege',
                            help='Use siege to generate load.')
    attack_group.add_option('--use-ab', action='store_const', dest='engine', const='ab',
                            help='Use ab to generate load (default).')
    attack_group.add_option('-w', '--time', metavar="TIME", nargs=1,
                            action='store', dest='time', type='string',
                            help="the time to run the test 60S, 1M, 5H")

    parser.add_option_group(attack_group)

    output_group = OptionGroup(parser, "output")

    output_group.add_option('-o', '--output', metavar="OUTPUT_TYPE", nargs=1,
                        action='store', dest='output_type', type='string',
                        help="specify \'csv\' to output a csv row.  specify \'csvh\' to output csv headers prior to the csv row.")
    output_group.add_option('-v', '--verbose', metavar="VERBOSE",
                        action='store_true', dest='verbose', default=False,
                        help="whether to log verbosely to stderr.")

    parser.add_option_group(output_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    import logging
    if options.verbose:
        level=logging.DEBUG
    else:
        level=logging.INFO

    logging.basicConfig(level=level)
#    loggingobject = logging.getLogger()
#    print "Logging at", loggingobject.getEffectiveLevel()
    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.instance_type, options.login, options.key, options.keepalive)
    elif command == 'attack':

        url, url_file = None, None
        if options.url_file:
            if not options.url_file.startswith('s3://'):
                url_file = os.path.realpath(options.url_file)
                assert os.path.isfile(url_file)
            else:
                # take it as-is, gets validated later
                url_file = options.url_file
        elif options.url:
            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.')
            else:
                url = options.url
        else:
            parser.error('To run an attack you need to specify either a url with -u or a file with -f.')


        bees.attack(url, url_file, options.number, options.concurrent, options.keepalive, options.output_type, options.engine, options.time)
    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #7
0
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    parser = ArgumentParser(description="""
        Bees with Machine Guns.
        A utility for arming (creating) many bees (small EC2 instances) to attack
        (load test) targets (web applications).
        """)

    subparsers = parser.add_subparsers(title='commands', dest='command')
    up_cmd = subparsers.add_parser("up", help='Start a batch of load testing servers.', description=
        """Start a batch of load testing servers.
        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/.""")

    # Required
    up_cmd.add_argument('-k', '--key',  metavar="KEY", dest='key', required=True, help="The ssh key pair name to use to connect to the new servers.")

    up_cmd.add_argument('-s', '--servers', metavar="SERVERS", dest='servers', type=int, default=5, help="The number of servers to start (default: 5).")
    up_cmd.add_argument('-g', '--group', metavar="GROUP", dest='group', default='default', help="The security group(s) to run the instances under (default: default).")
    up_cmd.add_argument('-z', '--zone',  metavar="ZONE", dest='zone', default='us-east-1d', help="The availability zone to start the instances in (default: us-east-1d).")
    up_cmd.add_argument('-i', '--instance',  metavar="INSTANCE", dest='instance', default='ami-ff17fb96', help="The instance-id to use for each server from (default: ami-ff17fb96).")
    up_cmd.add_argument('-t', '--type',  metavar="TYPE", dest='type', default='t1.micro', help="The instance-type to use for each server (default: t1.micro).")
    up_cmd.add_argument('-l', '--login',  metavar="LOGIN", dest='login', default='newsapps', help="The ssh username name to use to connect to the new servers (default: newsapps).")
    up_cmd.add_argument('-v', '--subnet',  metavar="SUBNET", dest='subnet', default=None, help="The vpc subnet id in which the instances should be launched. (default: None).")

    attack_cmd = subparsers.add_parser("attack", help='Begin the attack on a specific url.', description=
        """Begin the attack on a specific url.
        Beginning an attack requires only that you specify the -u option with the URL you wish to target.""")

    # Required
    attack_cmd.add_argument('-u', '--url', metavar="URL", dest='urls', action='append', required=True, help="URL(s) of the target to attack.")

    attack_cmd.add_argument('-p', '--post-file',  metavar="POST_FILE", dest='post_files', action='append', help="The POST file(s) to deliver with the bee's payload.")
    attack_cmd.add_argument('-m', '--mime-type',  metavar="MIME_TYPE", dest='mime_type', default='text/plain', help="The MIME type to send with the request.")
    attack_cmd.add_argument('-n', '--number', metavar="NUMBER", dest='number', type=int, default=1000, help="The number of total connections to make to the target (default: 1000).")
    attack_cmd.add_argument('-c', '--concurrent', metavar="CONCURRENT", dest='concurrent', type=int, default=100, help="The number of concurrent connections to make to the target (default: 100).")
    attack_cmd.add_argument('-H', '--headers', metavar="HEADERS", dest='headers', default='',
                        help="HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2")
    attack_cmd.add_argument('-e', '--csv', metavar="FILENAME", dest='csv_filename', default='', help="Store the distribution of results in a csv file for all completed bees (default: '').")
    attack_cmd.add_argument('-g', '--gnuplot', metavar="FILENAME", dest='gnuplot_filename', default='', help="Write all measured values out as a 'gnuplot' or TSV (Tab separate values) file (default: '').")
    attack_cmd.add_argument('-t', '--timelimit', metavar="TIMELIMIT", dest='timelimit', type=int, default=0,
                        help="Maximum number of seconds to spend for benchmarking. This implies a -n 50000 internally. Use this to benchmark the server within a fixed total amount of time (default: no limit).")
    attack_cmd.add_argument('--stats-file', metavar="FILENAME", dest='stats_filename', default='',
                        help="Store detailed graph ready stats across multiple tests in a csv file. Will create gnuplot files even if the -g/--gnuplot wasn't specified (default: '').")
    attack_cmd.add_argument('--testname', metavar="NAME", dest='testname', default='unnamed', help="Name of current test. To be used in conjunction with --stats-file (default: 'unnamed').")
    attack_cmd.add_argument('--non-200-is-failure', dest='non_200_is_failure', action='store_true', default=False, help="Treat non-200 responses as failures (treated as success by default).")

    down_cmd = subparsers.add_parser("down", help='Shutdown and deactivate the load testing servers.', description='Shutdown and deactivate the load testing servers.')
    report_cmd = subparsers.add_parser("report", help='Report the status of the load testing servers.', description='Report the status of the load testing servers.')

    options = parser.parse_args()

    command = options.command

    if command == 'up':
        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.type, options.login, options.key, options.subnet)
    elif command == 'attack':
        for url in options.urls:
            parsed = urlparse(url)
            if not parsed.scheme:
                parsed = urlparse("http://" + url)

            if not parsed.path:
                parser.error('It appears your URL lacks a trailing slash, this will disorient the bees. Please try again with a trailing slash.')

        additional_options = dict(
            headers=options.headers,
            post_files=options.post_files,
            mime_type=options.mime_type,
            csv_filename=options.csv_filename,
            gnuplot_filename=options.gnuplot_filename,
            stats_filename=options.stats_filename,
            testname=options.testname,
            non_200_is_failure=options.non_200_is_failure,
        )

        bees.attack(options.urls, options.number, options.concurrent, options.timelimit, **additional_options)

    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #8
0
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",
        """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/.""")

    # 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('-t', '--instance_type',  metavar="INSTANCE_TYPE",  nargs=1,
                        action='store', dest='instance_type', type='string', default='t1.micro',
                        help="The ec2 instance type to use for each server (default: t1.micro).")
    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 that you specify the URL(s) you wish to target, either using -u or -f.""")

    # 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('-f', '--url-file', metavar="URL_FILE", nargs=1,
                        action='store', dest='url_file', type='string',
                        help="file containing URLs of the targets 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).")
    attack_group.add_option('--keepalive', metavar="KEEPALIVE",
                            action='store_true', dest='keepalive', default=False,
                            help='Whether or not to use ab keepalive (default: False)')
    attack_group.add_option('--use-wideload', action='store_const', dest='engine', const='wideload',
                            help='Use wideload to generate load.')
    attack_group.add_option('--use-siege', action='store_const', dest='engine', const='siege',
                            help='Use siege to generate load.')
    attack_group.add_option('--use-ab', action='store_const', dest='engine', const='ab',
                            help='Use ab to generate load (default).')

    parser.add_option_group(attack_group)

    output_group = OptionGroup(parser, "output")
    
    output_group.add_option('-o', '--output', metavar="OUTPUT_TYPE", nargs=1,
                        action='store', dest='output_type', type='string',
                        help="specify \'csv\' to output a csv row.  specify \'csvh\' to output csv headers prior to the csv row.")
    output_group.add_option('-v', '--verbose', metavar="VERBOSE", 
                        action='store_true', dest='verbose', default=False,
                        help="whether to log verbosely to stderr.")

    parser.add_option_group(output_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]
    
    import logging
    if options.verbose:
        level=logging.DEBUG
    else:
        level=logging.WARNING
    logging.basicConfig(level=level)

    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.instance_type, options.login, options.key, options.keepalive)
    elif command == 'attack':
        
        url, url_file = None, None
        if options.url_file:
            if not options.url_file.startswith('s3://'):
                url_file = os.path.realpath(options.url_file)
                assert os.path.isfile(url_file)
            else:
                # take it as-is, gets validated later
                url_file = options.url_file
        elif options.url:
            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.')
            else:
                url = options.url
        else:
            parser.error('To run an attack you need to specify either a url with -u or a file with -f.')


        bees.attack(url, url_file, options.number, options.concurrent, options.keepalive, options.output_type, options.engine)
    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #9
0
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",
        """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/.""",
    )

    # 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)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error("Please enter a command.")

    command = args[0]

    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":
        if not options.url:
            parser.error("To run an attack you need to specify a url with -u")

        # Not sure why this is necessary, disabling
        # 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.down()
    elif command == "report":
        bees.report()
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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
        ]

        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."""
        )

        [
            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':
        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.down()
    elif command == 'report':
        bees.report()
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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/.""")

    # 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='ap-southeast-2a',
                        help="The availability zone to start the instances in (default: ap-southeast-2a).")
    up_group.add_option('-i', '--instance',  metavar="INSTANCE",  nargs=1,
                        action='store', dest='instance', type='string', default='ami-bd990e87',
                        help="The instance-id to use for each server from (default: ami-bd990e87).")
    up_group.add_option('-t', '--type',  metavar="TYPE",  nargs=1,
                        action='store', dest='type', type='string', default='t1.micro',
                        help="The instance-type to use for each server (default: t1.micro).")
    up_group.add_option('-l', '--login',  metavar="LOGIN",  nargs=1,
                        action='store', dest='login', type='string', default='ec2-user',
                        help="The ssh username name to use to connect to the new servers (default: ec2-user).")

    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).")
    attack_group.add_option('-H', '--headers', metavar="HEADER", nargs=1,
                        action='store', dest='headers', type='string', default="",
                        help="HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2")
    attack_group.add_option('-p', '--proxy', metavar="proxy", action='store_true', dest='proxy',
                        help="Whether or not to use an ssh proxy for connecting to your bees (default: false).")



    parser.add_option_group(attack_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    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.type, options.login, options.key)
    elif command == 'attack':
        if not options.url:
            parser.error('To run an attack you need to specify a url with -u')

        parsed = urlparse(options.url)
        if not parsed.scheme:
            parsed = urlparse("http://" + options.url)

        if not parsed.path:
            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, options.headers, options.proxy)
    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #12
0
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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/.""",
    )

    # 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(s) 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-11869178",
        help="The instance-id to use for each server from (default: ami-11869178).",
    )
    up_group.add_option(
        "-t",
        "--type",
        metavar="TYPE",
        nargs=1,
        action="store",
        dest="type",
        type="string",
        default="t1.micro",
        help="The instance-type to use for each server (default: t1.micro).",
    )
    up_group.add_option(
        "-l",
        "--login",
        metavar="LOGIN",
        nargs=1,
        action="store",
        dest="login",
        type="string",
        default="admin",
        help="The ssh username name to use to connect to the new servers (default: admin).",
    )
    up_group.add_option(
        "-v",
        "--subnet",
        metavar="SUBNET",
        nargs=1,
        action="store",
        dest="subnet",
        type="string",
        default=None,
        help="The vpc subnet id in which the instances should be launched. (default: None).",
    )

    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(
        "-p",
        "--post-file",
        metavar="POST_FILE",
        nargs=1,
        action="store",
        dest="post_file",
        type="string",
        default=False,
        help="The POST file to deliver with the bee's payload.",
    )
    attack_group.add_option(
        "-m",
        "--mime-type",
        metavar="MIME_TYPE",
        nargs=1,
        action="store",
        dest="mime_type",
        type="string",
        default="text/plain",
        help="The MIME type to send with the request.",
    )
    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",
        "--cookies",
        metavar="COOKIES",
        nargs=1,
        action="store",
        dest="cookies",
        type="string",
        default="",
        help="Cookies to send during http requests. The cookies should be passed using standard cookie formatting, separated by semi-colons and assigned with equals signs.",
    )
    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).",
    )
    attack_group.add_option(
        "-H",
        "--headers",
        metavar="HEADERS",
        nargs=1,
        action="store",
        dest="headers",
        type="string",
        default="",
        help="HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2",
    )
    attack_group.add_option(
        "-e",
        "--csv",
        metavar="FILENAME",
        nargs=1,
        action="store",
        dest="csv_filename",
        type="string",
        default="",
        help="Store the distribution of results in a csv file for all completed bees (default: '').",
    )

    # Optional
    attack_group.add_option(
        "-T",
        "--tpr",
        metavar="TPR",
        nargs=1,
        action="store",
        dest="tpr",
        default=None,
        type="float",
        help="The upper bounds for time per request. If this option is passed and the target is below the value a 1 will be returned with the report details (default: None).",
    )
    attack_group.add_option(
        "-R",
        "--rps",
        metavar="RPS",
        nargs=1,
        action="store",
        dest="rps",
        default=None,
        type="float",
        help="The lower bounds for request per second. If this option is passed and the target is above the value a 1 will be returned with the report details (default: None).",
    )

    parser.add_option_group(attack_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error("Please enter a command.")

    command = args[0]

    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.type,
            options.login,
            options.key,
            options.subnet,
        )
    elif command == "attack":
        if not options.url:
            parser.error("To run an attack you need to specify a url with -u")

        parsed = urlparse(options.url)
        if not parsed.scheme:
            parsed = urlparse("http://" + options.url)

        if not parsed.path:
            parser.error(
                "It appears your URL lacks a trailing slash, this will disorient the bees. Please try again with a trailing slash."
            )

        additional_options = dict(
            cookies=options.cookies,
            headers=options.headers,
            post_file=options.post_file,
            mime_type=options.mime_type,
            csv_filename=options.csv_filename,
            tpr=options.tpr,
            rps=options.rps,
        )

        bees.attack(options.url, options.number, options.concurrent, **additional_options)

    elif command == "down":
        bees.down()
    elif command == "report":
        bees.report()
Example #13
0
def parse_arguments():
    """
    Handle the command line arguments for spinning up bees
    """
    parser = ArgumentParser(
        description="Bees with Machine Guns: A utility for arming "
        "(creating) many bees (small EC2 instances) to attack (load "
        "test) targets (web applications).")

    subparsers = parser.add_subparsers(dest='subparser_name',
        help='Bee commands')

    up_subparser = subparsers.add_parser(
        "up",
        help="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_subparser.add_argument(
        '-k', '--key', metavar="KEY",
        action='store', dest='key', type=str,
        help="The ssh key pair name to use to connect to the new servers.")
    up_subparser.add_argument(
        '-s', '--servers', metavar="SERVERS",
        action='store', dest='servers', type=int, default=5,
        help="The number of servers to start (default: 5).")
    up_subparser.add_argument(
        '-g', '--group', metavar="GROUP",
        action='store', dest='group', type=str, default='default',
        help="The security group to run the instances under "
        "(default: default).")
    up_subparser.add_argument(
        '-z', '--zone',  metavar="ZONE",
        action='store', dest='zone', type=str, default='us-east-1d',
        help="The availability zone to start the instances "
        "in (default: us-east-1d).")
    up_subparser.add_argument(
        '-i', '--instance',  metavar="INSTANCE",
        action='store', dest='instance', type=str, default='ami-ff17fb96',
        help="The instance-id to use for each server from "
        "(default: ami-ff17fb96).")
    up_subparser.add_argument(
        '-l', '--login',  metavar="LOGIN",
        action='store', dest='login', type=str, default='newsapps',
        help="The ssh username name to use to connect to the "
        "new servers (default: newsapps).")

    attack_subparser = subparsers.add_parser(
        "attack",
        help="Beginning an attack requires only that you specify the "
        "-u option with the URL you wish to target.")

    attack_subparser.add_argument(
        '-u', '--url', metavar="URL",
        action='store', dest='url', type=str,
        help="URL of the target to attack.")
    attack_subparser.add_argument(
        '-n', '--number', metavar="NUMBER",
        action='store', dest='number', type=int, default=1000,
        help="The number of total connections to make to "
        "the target (default: 1000).")
    attack_subparser.add_argument(
        '-c', '--concurrent', metavar="CONCURRENT",
        action='store', dest='concurrent', type=int, default=100,
        help="The number of concurrent connections to make "
        "to the target (default: 100).")
    attack_subparser.add_argument(
        '-H', '--headers', metavar='HEADERS', nargs='*',
        action=HeadersAction, dest='headers', type=str,
        help="Send arbitray header line(s) along with the attack, "
        "eg. 'Host: www.chicagotribune.com'; Inserted after all normal "
        "header lines. (repeatable)",
        default=''
    )
    attack_subparser.add_argument(
        '-C', '--cookies', metavar='COOKIES', nargs='*',
        action=CookiesAction, dest='cookies', type=str,
        help="Add cookie, eg. 'Apache=1234'. (repeatable)",
        default=''
    )

    down_subparser = subparsers.add_parser(
        "down",
        help="Call off the swarm")

    report_subparser = subparsers.add_parser(
        "report",
        help="Print the active bees' status")


    options = parser.parse_args()

    if options.subparser_name == '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 options.subparser_name == '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,
            options.headers, options.cookies)
    elif options.subparser_name == 'down':
        bees.down()
    elif options.subparser_name == 'report':
        bees.report()
Example #14
0
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", 
        """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/.""")

    # 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).")
    attack_group.add_option('-p', '--post-file', metavar="POSTFILE", nargs=1,
                        action='store', dest='postfile', type='string', default=None,
                        help="The file containing data to post.  Remember to also set -T")
    attack_group.add_option('-t', '--content-type', metavar="CONTENTTYPE", nargs=1,
                        action='store', dest='contenttype', type='string', default="text/plain",
                        help="Content-type header to use for POST/PUT data, eg. application/x-www-form-urlencoded.  Default: text/plain.")

    parser.add_option_group(attack_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    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':
        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.')
        
        username, key_name, instance_ids = bees._read_server_list()
        requests_per_instance = options.number / len(instance_ids)
        concurrent_requests_per_instance = options.concurrent / len(instance_ids)
        if requests_per_instance < concurrent_requests_per_instance:
            parser.error("The total number of concurrent requests per instance (" + str(concurrent_requests_per_instance) + ") is greater than the total number of requests per instance (" + str(requests_per_instance) +")")

        bees.attack(options.url, options.number, options.concurrent, options.postfile, options.contenttype)
    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #15
0
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.
  shell   Run a command on each bee.
    """)
    
    general_group = OptionGroup(parser, "general", """General options for all commands""")
    
    general_group.add_option('-f', '--file',  metavar="STATE_FILE",  nargs=1,
                        action='store', dest='statefile', type='string', default=bees.STATE_FILENAME,
                        help="The state file to use (default: ~/.bees). Note that if you use this option, you have to set it for attack, down, and report.")

    parser.add_option_group(general_group)

    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/.""")

    # 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)
    
    shell_group = OptionGroup(parser, "shell", """Run a command on each bee""")
    
    shell_group.add_option('-e', '--execute',  metavar="COMMAND",  nargs=1,
                        action='store', dest='command', type='string',
                        help="The command to run")

    parser.add_option_group(shell_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    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, options.statefile)
    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, options.statefile)
    elif command == 'down':
        bees.down(options.statefile)
    elif command == 'report':
        bees.report(options.statefile)
    elif command == 'shell':
        if not options.command:
            parser.error('You must specify a shell command with -e')
        
        bees.shell(options.command, options.statefile)
Example #16
0
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",
        """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/."""
    )

    # 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)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error("Please enter a command.")

    command = args[0]

    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":
        if not options.url:
            parser.error("To run an attack you need to specify a url with -u")

        bees.attack(options.url, options.number, options.concurrent)
    elif command == "down":
        bees.down()
    elif command == "report":
        bees.report()
Example #17
0
def parse_options():
    """
    Handle the command line arguments for spinning up bees
    """
    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/.""")

    # 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(s) to run the instances under (default: default).")
    up_group.add_option('-z', '--zone',  metavar="ZONE",  nargs=1,
                        action='store', dest='zone', type='string', default='ap-northeast-1a',
                        help="The availability zone to start the instances in (default: ap-northeast-1a).")
    up_group.add_option('-i', '--instance',  metavar="INSTANCE",  nargs=1,
                        action='store', dest='instance', type='string', default='ami-2db23d2c',
                        help="The instance-id to use for each server from (default: ami-2db23d2c).")
    up_group.add_option('-t', '--type',  metavar="TYPE",  nargs=1,
                        action='store', dest='type', type='string', default='t1.micro',
                        help="The instance-type to use for each server (default: t1.micro).")
    up_group.add_option('-l', '--login',  metavar="LOGIN",  nargs=1,
                        action='store', dest='login', type='string', default='ec2-user',
                        help="The ssh username name to use to connect to the new servers (default: ec2-user).")
    up_group.add_option('-v', '--subnet',  metavar="SUBNET",  nargs=1,
                        action='store', dest='subnet', type='string', default=None,
                        help="The vpc subnet id in which the instances should be launched. (default: None).")

    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('-p', '--post-file',  metavar="POST_FILE",  nargs=1,
                        action='store', dest='post_file', type='string', default=False,
                        help="The POST file to deliver with the bee's payload.")
    attack_group.add_option('-m', '--mime-type',  metavar="MIME_TYPE",  nargs=1,
                        action='store', dest='mime_type', type='string', default='text/plain',
                        help="The MIME type to send with the request.")
    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).")
    attack_group.add_option('-H', '--headers', metavar="HEADERS", nargs=1,
                        action='store', dest='headers', type='string', default='',
                        help="HTTP headers to send to the target to attack. Multiple headers should be separated by semi-colons, e.g header1:value1;header2:value2")
    attack_group.add_option('-e', '--csv', metavar="FILENAME", nargs=1,
                        action='store', dest='csv_filename', type='string', default='',
                        help="Store the distribution of results in a csv file for all completed bees (default: '').")

    parser.add_option_group(attack_group)

    run_group = OptionGroup(parser, "run",
            """Beginning an run requires only that you specify the -C option with the command you wish to target.""")

    run_group.add_option('-C', '--cmd', metavar="CMD", nargs=1,
                        action='store', dest='cmd', type='string',
                        help="Command of the target to attack.")
    run_group.add_option("-b", "--balancing",
                  	action="store_true", dest="balancing", default=False,
                  	help="balancing")

    parser.add_option_group(run_group)

    (options, args) = parser.parse_args()

    if len(args) <= 0:
        parser.error('Please enter a command.')

    command = args[0]

    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.type, options.login, options.key, options.subnet)
    elif command == 'attack':
        if not options.url:
            parser.error('To run an attack you need to specify a url with -u')

        parsed = urlparse(options.url)
        if not parsed.scheme:
            parsed = urlparse("http://" + options.url)

        if not parsed.path:
            parser.error('It appears your URL lacks a trailing slash, this will disorient the bees. Please try again with a trailing slash.')

        additional_options = dict(
            headers=options.headers,
            post_file=options.post_file,
            mime_type=options.mime_type,
            csv_filename=options.csv_filename,
        )

        bees.attack(options.url, options.number, options.concurrent, **additional_options)

    elif command == 'run':
        if not options.cmd:
            parser.error('To run an attack you need to specify a command with -C')
        bees.run(options.cmd, options.balancing)

    elif command == 'setup':
        bees.setup()

    elif command == 'down':
        bees.down()
    elif command == 'report':
        bees.report()
Example #18
0
def attack(swarm, battleplan):
    bees.attack(swarm['username'], swarm['key-name'], swarm['zone'], swarm['instances'], battleplan)