Exemplo n.º 1
0
  def testSubnetLifecycle(self, mock_cmd):
    zone = 'us-west-1a'
    vpc_id = 'vpc-1234'
    region = 'us-west-1'
    subnet_id = 'subnet-1234'
    create_response = {'Subnet': {'SubnetId': subnet_id}}
    exists_response = {'Subnets': [{'SubnetId': subnet_id, 'VpcId': vpc_id}]}
    exists_response_no_resources = {'Subnets': []}
    delete_response = {}
    create_cmd = _AwsCommand(region, 'create-subnet',
                             '--vpc-id={}'.format(vpc_id),
                             '--cidr-block=10.0.0.0/24',
                             '--availability-zone={}'.format(zone))
    describe_cmd = _AwsCommand(
        region, 'describe-subnets',
        '--filter=Name=vpc-id,Values={}'.format(vpc_id),
        '--filter=Name=subnet-id,Values={}'.format(subnet_id))
    delete_cmd = _AwsCommand(region, 'delete-subnet',
                             '--subnet-id={}'.format(subnet_id))

    # Test the Create() command
    mock_cmd.side_effect = [(json.dumps(create_response), '', 0)]
    util.IssueRetryableCommand.side_effect = [(json.dumps(exists_response), '')]
    subnet = aws_network.AwsSubnet(zone, vpc_id)
    subnet.Create()
    mock_cmd.assert_called_with(create_cmd)
    util.IssueRetryableCommand.assert_called_with(describe_cmd)

    # Reset the mocks and call the Delete() command.
    mock_cmd.reset_mock()
    util.IssueRetryableCommand.reset_mock()
    mock_cmd.side_effect = [(json.dumps(delete_response), '', 0)]
    util.IssueRetryableCommand.side_effect = [
        (json.dumps(exists_response_no_resources), '')
    ]
    subnet.Delete()
    mock_cmd.assert_called_with(delete_cmd, raise_on_failure=False)
    util.IssueRetryableCommand.assert_called_with(describe_cmd)
    def Prepare(self, vm):
        """Prepares the DB and everything for the AWS-RDS provider.

    Args:
      vm: The VM to be used as the test client.

    """
        logging.info('Preparing MySQL Service benchmarks for RDS.')

        # TODO: Refactor the RDS DB instance creation and deletion logic out
        # to a new class called RDSDBInstance that Inherits from
        # perfkitbenchmarker.resource.BaseResource.
        # And do the same for GCP.

        # First is to create another subnet in the same VPC as the VM but in a
        # different zone. RDS requires two subnets in two different zones to create
        # a DB instance, EVEN IF you do not specify multi-AZ in your DB creation
        # request.

        # Get a list of zones and pick one that's different from the zone VM is in.
        new_subnet_zone = None
        get_zones_cmd = util.AWS_PREFIX + [
            'ec2', 'describe-availability-zones'
        ]
        stdout, _, _ = vm_util.IssueCommand(get_zones_cmd)
        response = json.loads(stdout)
        all_zones = response['AvailabilityZones']
        for zone in all_zones:
            if zone['ZoneName'] != vm.zone:
                new_subnet_zone = zone['ZoneName']
                break

        if new_subnet_zone is None:
            raise DBStatusQueryError(
                'Cannot find a zone to create the required '
                'second subnet for the DB instance.')

        # Now create a new subnet in the zone that's different from where the VM is
        logging.info('Creating a second subnet in zone %s', new_subnet_zone)
        new_subnet = aws_network.AwsSubnet(new_subnet_zone, vm.network.vpc.id,
                                           '10.0.1.0/24')
        new_subnet.Create()
        logging.info('Successfully created a new subnet, subnet id is: %s',
                     new_subnet.id)
        # Remember this so we can cleanup properly.
        vm.extra_subnet_for_db = new_subnet

        # Now we can create a new DB subnet group that has two subnets in it.
        db_subnet_group_name = 'pkb%s' % FLAGS.run_uri
        create_db_subnet_group_cmd = util.AWS_PREFIX + [
            'rds', 'create-db-subnet-group', '--db-subnet-group-name',
            db_subnet_group_name, '--db-subnet-group-description',
            'pkb_subnet_group_for_db', '--subnet-ids', vm.network.subnet.id,
            new_subnet.id
        ]
        stdout, stderr, _ = vm_util.IssueCommand(create_db_subnet_group_cmd)
        logging.info(
            'Created a DB subnet group, stdout is:\n%s\nstderr is:\n%s',
            stdout, stderr)
        vm.db_subnet_group_name = db_subnet_group_name

        # open up tcp port 3306 in the VPC's security group, we need that to connect
        # to the DB.
        open_port_cmd = util.AWS_PREFIX + [
            'ec2', 'authorize-security-group-ingress', '--group-id',
            vm.group_id, '--source-group', vm.group_id, '--protocol', 'tcp',
            '--port', MYSQL_PORT
        ]
        stdout, stderr, _ = vm_util.IssueCommand(open_port_cmd)
        logging.info('Granted DB port ingress, stdout is:\n%s\nstderr is:\n%s',
                     stdout, stderr)

        # Finally, it's time to create the DB instance!
        vm.db_instance_id = 'pkb-DB-%s' % FLAGS.run_uri
        db_class = \
            RDS_CORE_TO_DB_CLASS_MAP['%s' % FLAGS.mysql_svc_db_instance_cores]
        vm.db_instance_master_user = MYSQL_ROOT_USER
        vm.db_instance_master_password = _GenerateRandomPassword()

        create_db_cmd = util.AWS_PREFIX + [
            'rds', 'create-db-instance', '--db-instance-identifier',
            vm.db_instance_id, '--db-instance-class', db_class, '--engine',
            RDS_DB_ENGINE, '--engine-version', RDS_DB_ENGINE_VERSION,
            '--storage-type', RDS_DB_STORAGE_TYPE_GP2, '--allocated-storage',
            RDS_DB_STORAGE_GP2_SIZE, '--vpc-security-group-ids', vm.group_id,
            '--master-username', vm.db_instance_master_user,
            '--master-user-password', vm.db_instance_master_password,
            '--availability-zone', vm.zone, '--db-subnet-group-name',
            vm.db_subnet_group_name
        ]

        status_query_cmd = util.AWS_PREFIX + [
            'rds', 'describe-db-instances', '--db-instance-id',
            vm.db_instance_id
        ]

        stdout, stderr, _ = vm_util.IssueCommand(create_db_cmd)
        logging.info(
            'Request to create the DB has been issued, stdout:\n%s\n'
            'stderr:%s\n', stdout, stderr)
        response = json.loads(stdout)

        db_creation_status = _RDSParseDBInstanceStatus(response)

        for status_query_count in xrange(1, DB_STATUS_QUERY_LIMIT + 1):
            if db_creation_status == 'available':
                break

            if db_creation_status not in RDS_DB_CREATION_PENDING_STATUS:
                raise DBStatusQueryError(
                    'Invalid status in DB creation response. '
                    ' stdout is\n%s, stderr is\n%s' % (stdout, stderr))

            logging.info(
                'Querying db creation status, current state is %s, query '
                'count is %d', db_creation_status, status_query_count)
            time.sleep(DB_STATUS_QUERY_INTERVAL)

            stdout, stderr, _ = vm_util.IssueCommand(status_query_cmd)
            response = json.loads(stdout)
            db_creation_status = _RDSParseDBInstanceStatus(response)
        else:
            raise DBStatusQueryError(
                'DB creation timed-out, we have '
                'waited at least %s * %s seconds.' %
                (DB_STATUS_QUERY_INTERVAL, DB_STATUS_QUERY_LIMIT))

        # We are good now, db has been created. Now get the endpoint address.
        # On RDS, you always connect with a DNS name, if you do that from a EC2 VM,
        # that DNS name will be resolved to an internal IP address of the DB.
        if 'DBInstance' in response:
            vm.db_instance_address = response['DBInstance']['Endpoint'][
                'Address']
        else:
            if 'DBInstances' in response:
                vm.db_instance_address = \
                    response['DBInstances'][0]['Endpoint']['Address']

        logging.info('Successfully created an RDS DB instance. Address is %s',
                     vm.db_instance_address)
        logging.info('Complete output is:\n %s', response)