Esempio n. 1
0
    def setUp(self):
        self.factory = InfrastructureAgentFactory()

        self.fake_ec2 = flexmock(name='self.fake_ec2')
        self.fake_ec2.should_receive('get_key_pair')
        self.fake_ec2.should_receive('create_key_pair').with_args('bookeyname') \
            .and_return(KeyPair())
        self.fake_ec2.should_receive('get_all_security_groups').and_return([])
        self.fake_ec2.should_receive('create_security_group') \
            .with_args('boogroup', 'AppScale security group') \
            .and_return(SecurityGroup())
        self.fake_ec2.should_receive('authorize_security_group')

        instance = flexmock(name='instance',
                            private_dns_name='private-ip',
                            public_dns_name='public-ip',
                            id='i-id',
                            state='running',
                            key_name='bookeyname')

        self.fake_ec2.should_receive('terminate_instances').and_return(
            [instance])
        self.fake_ec2.should_receive('run_instances')

        flexmock(boto.ec2)
        boto.ec2.should_receive('connect_to_region').and_return(self.fake_ec2)
    def validate_machine_image(self):
        """Checks with the given cloud (if running in a cloud) to ensure that the
    user-specified ami/emi exists, aborting if it does not.

    Raises:
      BadConfigurationException: If the given machine image does not exist.
    """
        if not self.args.infrastructure:
            return

        cloud_agent = InfrastructureAgentFactory.create_agent(
            self.args.infrastructure)
        params = cloud_agent.get_params_from_args(self.args)

        if not cloud_agent.does_image_exist(params):
            raise BadConfigurationException(
                "Couldn't find the given machine image.")

        if not cloud_agent.does_zone_exist(params):
            raise BadConfigurationException("Couldn't find the given zone.")

        # Make sure that if the user gives us an Elastic IP / static IP, that they
        # actually own it.
        if self.args.static_ip:
            if not cloud_agent.does_address_exist(params):
                raise BadConfigurationException(
                    "Couldn't find the given static IP.")

        if not self.args.disks:
            return

        for disk in set(self.args.disks.values()):
            if not cloud_agent.does_disk_exist(params, disk):
                raise BadConfigurationException(
                    "Couldn't find disk {0}".format(disk))
    def validate_credentials(self):
        """If running over a cloud infrastructure, makes sure that all of the
    necessary credentials have been specified.
    """
        if not self.args.infrastructure:
            return

        cloud_agent = InfrastructureAgentFactory.create_agent(
            self.args.infrastructure)
        params = cloud_agent.get_params_from_args(self.args)
        cloud_agent.assert_required_parameters(params, BaseAgent.OPERATION_RUN)
Esempio n. 4
0
    def setUp(self):
        self.factory = InfrastructureAgentFactory()

        (flexmock(EC2Connection).should_receive('get_key_pair').and_return(
            None))
        (flexmock(EC2Connection).should_receive('create_key_pair').with_args(
            'bookeyname').and_return(KeyPair()))
        (flexmock(EC2Connection).should_receive(
            'get_all_security_groups').and_return([]))
        (flexmock(
            EC2Connection).should_receive('create_security_group').with_args(
                'boogroup',
                'AppScale security group').and_return(SecurityGroup()))
        (flexmock(EC2Connection).should_receive(
            'authorize_security_group').and_return())
        (flexmock(EC2Connection).should_receive('run_instances').and_return())
Esempio n. 5
0
def make_app(secret, is_autoscaler):
    options.__dict__['_options'].clear()
    options.define('secret', secret)
    agent_factory = InfrastructureAgentFactory()

    if is_autoscaler:
        scaler_route = ('/instances', InstancesHandler, {
            'agent_factory': agent_factory
        })
    else:
        scaler_route = (
            '/instances', Respond404Handler,
            dict(reason='This node was not started as an autoscaler.'))
    app = web.Application([
        ('/instance', InstanceHandler, {
            'agent_factory': agent_factory
        }),
        scaler_route,
    ])
    return app
Esempio n. 6
0
    def setUp(self):
        self.factory = InfrastructureAgentFactory()
        self.fake_ec2 = flexmock(name='self.fake_ec2')
        flexmock(boto.ec2)
        boto.ec2.should_receive('connect_to_region').and_return(self.fake_ec2)

        reservation = Reservation()
        instance = flexmock(name='instance', private_dns_name='private-ip',
                            public_dns_name='public-ip', id='i-aabbccee', state='running',
                            key_name='bookeyname', ip_address='public-ip',
                            private_ip_address='private-ip')
        new_instance = flexmock(name='new-instance', private_dns_name='new-private-ip',
                                public_dns_name='new-public-ip', id='i-aabbccff',
                                state='running', key_name='bookeyname',
                                ip_address='new-public-ip',
                                private_ip_address='new-private-ip')

        t_aabbccee = flexmock(name='instance', private_dns_name='private-ip',
                            public_dns_name='public-ip', id='i-aabbccee', state='terminated',
                            key_name='bookeyname', ip_address='public-ip',
                            private_ip_address='private-ip')
        t_aabbccff = flexmock(name='new-instance', private_dns_name='new-private-ip',
                                public_dns_name='new-public-ip', id='i-aabbccff',
                                state='terminated', key_name='bookeyname',
                                ip_address='new-public-ip',
                                private_ip_address='new-private-ip')
        t_aabbccdd = flexmock(name='instance', private_dns_name='private-ip',
                              public_dns_name='public-ip', id='i-aabbccdd', state='terminated',
                              key_name='bookeyname', ip_address='public-ip',
                              private_ip_address='private-ip')

        reservation.instances = [instance]
        new_reservation = Reservation()
        new_reservation.instances = [instance, new_instance]

        # For testing wait_for_status
        self.good_reservation = Reservation()
        self.good_reservation.instances = [instance, new_instance]
        self.good_reservations = [self.good_reservation]
        self.terminated_reservation = Reservation()

        # Used because we filter for 'terminated' and it should return no instances..
        self.empty_reservation = Reservation()
        self.empty_reservation.instances = []
        self.empty_reservations = [self.empty_reservation]

        self.terminated_reservation.instances = [t_aabbccee, t_aabbccff, t_aabbccdd]
        self.terminated_reservations = [self.terminated_reservation]

        self.instance_notfound_body = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance ID '{}' does not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.multiple_instance_notfound_body = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance IDs '{}' do not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.full_params = {
            'credentials': {
                'a': 'b', 'EC2_URL': 'http://testing.appscale.com:8773/foo/bar',
                'EC2_ACCESS_KEY': 'access_key', 'EC2_SECRET_KEY': 'secret_key'},
            'group': 'boogroup',
            'image_id': 'booid',
            'infrastructure': 'ec2',
            'instance_type': 'booinstance_type',
            'keyname': 'bookeyname',
            'num_vms': '1',
            'use_spot_instances': False,
            'region': 'my-zone-1',
            'zone': 'my-zone-1b',
            'autoscale_agent': True,
        }
Esempio n. 7
0
class TestEC2AgentTerminateInstances(TestCase):
    def setUp(self):
        self.factory = InfrastructureAgentFactory()
        self.fake_ec2 = flexmock(name='self.fake_ec2')
        flexmock(boto.ec2)
        boto.ec2.should_receive('connect_to_region').and_return(self.fake_ec2)

        reservation = Reservation()
        instance = flexmock(name='instance', private_dns_name='private-ip',
                            public_dns_name='public-ip', id='i-aabbccee', state='running',
                            key_name='bookeyname', ip_address='public-ip',
                            private_ip_address='private-ip')
        new_instance = flexmock(name='new-instance', private_dns_name='new-private-ip',
                                public_dns_name='new-public-ip', id='i-aabbccff',
                                state='running', key_name='bookeyname',
                                ip_address='new-public-ip',
                                private_ip_address='new-private-ip')

        t_aabbccee = flexmock(name='instance', private_dns_name='private-ip',
                            public_dns_name='public-ip', id='i-aabbccee', state='terminated',
                            key_name='bookeyname', ip_address='public-ip',
                            private_ip_address='private-ip')
        t_aabbccff = flexmock(name='new-instance', private_dns_name='new-private-ip',
                                public_dns_name='new-public-ip', id='i-aabbccff',
                                state='terminated', key_name='bookeyname',
                                ip_address='new-public-ip',
                                private_ip_address='new-private-ip')
        t_aabbccdd = flexmock(name='instance', private_dns_name='private-ip',
                              public_dns_name='public-ip', id='i-aabbccdd', state='terminated',
                              key_name='bookeyname', ip_address='public-ip',
                              private_ip_address='private-ip')

        reservation.instances = [instance]
        new_reservation = Reservation()
        new_reservation.instances = [instance, new_instance]

        # For testing wait_for_status
        self.good_reservation = Reservation()
        self.good_reservation.instances = [instance, new_instance]
        self.good_reservations = [self.good_reservation]
        self.terminated_reservation = Reservation()

        # Used because we filter for 'terminated' and it should return no instances..
        self.empty_reservation = Reservation()
        self.empty_reservation.instances = []
        self.empty_reservations = [self.empty_reservation]

        self.terminated_reservation.instances = [t_aabbccee, t_aabbccff, t_aabbccdd]
        self.terminated_reservations = [self.terminated_reservation]

        self.instance_notfound_body = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance ID '{}' does not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.multiple_instance_notfound_body = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance IDs '{}' do not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.full_params = {
            'credentials': {
                'a': 'b', 'EC2_URL': 'http://testing.appscale.com:8773/foo/bar',
                'EC2_ACCESS_KEY': 'access_key', 'EC2_SECRET_KEY': 'secret_key'},
            'group': 'boogroup',
            'image_id': 'booid',
            'infrastructure': 'ec2',
            'instance_type': 'booinstance_type',
            'keyname': 'bookeyname',
            'num_vms': '1',
            'use_spot_instances': False,
            'region': 'my-zone-1',
            'zone': 'my-zone-1b',
            'autoscale_agent': True,
        }

    def test_ec2_terminate_instances(self):
        """
        Test out a successful terminate instances
        """
        # Uncomment to get logging from the agent, helpful for debugging
        #logging.basicConfig(level=logging.DEBUG)
        #l = logging.getLogger('appscale.agents.ec_agent')
        #l.setLevel(logging.DEBUG)

        ec2 = self.factory.create_agent('ec2')

        (self.fake_ec2.should_receive('terminate_instances')
         .and_return(True))

        self.full_params['instance_ids'] = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']

        (self.fake_ec2.should_receive('get_all_reservations')
            .and_return(self.terminated_reservations))

        instance_ids = set(self.full_params[ec2.PARAM_INSTANCE_IDS])
        status_filters = {"instance-state-name": 'terminated',
                          "key-name": self.full_params[ec2.PARAM_KEYNAME]}
        conn = ec2.open_connection(self.full_params)
        result = ec2._EC2Agent__terminate_instances(instance_ids, conn, status_filters, max_attempts=1)
        self.assertTrue(result)

    def test_ec2_terminate_instances_invalid_id(self):
        """
        Test out an invalid instance id
        """
        ec2 = self.factory.create_agent('ec2')
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        self.full_params['instance_ids'] = instance_ids

        # First instance ID doesn't exist, second call will succeed
        (self.fake_ec2.should_receive('terminate_instances')
         .and_raise(EC2ResponseError(400, 'no reason',
                                     self.instance_notfound_body.format(instance_ids[0])))
         .and_return(True))

        # _wait_for_status should return true.
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_return(self.terminated_reservations))

        instance_ids = set(self.full_params[ec2.PARAM_INSTANCE_IDS])
        status_filters = {"instance-state-name": 'terminated',
                          "key-name": self.full_params[ec2.PARAM_KEYNAME]}
        conn = ec2.open_connection(self.full_params)
        result = ec2._EC2Agent__terminate_instances(instance_ids, conn, status_filters, max_attempts=1)
        self.assertTrue(result)

    def test_ec2_terminate_instances_multiple_invalid_id(self):
        """
        Test out a multiple invalid instance ids.
        """
        # Uncomment to get logging from the agent, helpful for debugging
        logging.basicConfig(level=logging.DEBUG)
        l = logging.getLogger('appscale.agents.ec_agent')
        l.setLevel(logging.DEBUG)

        ec2 = self.factory.create_agent('ec2')
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        self.full_params['instance_ids'] = instance_ids

        # First instance ID doesn't exist, second call will succeed
        (self.fake_ec2.should_receive('terminate_instances')
         .and_raise(EC2ResponseError(400, 'no reason',
                                     self.multiple_instance_notfound_body.format(instance_ids[0:2])))
         .and_return(True))

        # _wait_for_status should return true.
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_return(self.terminated_reservations))

        instance_ids = set(self.full_params[ec2.PARAM_INSTANCE_IDS])
        status_filters = {"instance-state-name": 'terminated',
                          "key-name": self.full_params[ec2.PARAM_KEYNAME]}
        conn = ec2.open_connection(self.full_params)
        result = ec2._EC2Agent__terminate_instances(instance_ids, conn, status_filters, max_attempts=1)
        self.assertTrue(result)

    def test_ec2_terminate_instances_all_not_found(self):
        """
        Test out all not found, should return true
        """
        # Uncomment to get logging from the agent, helpful for debugging
        logging.basicConfig(level=logging.DEBUG)
        l = logging.getLogger('appscale.agents.ec_agent')
        l.setLevel(logging.DEBUG)

        ec2 = self.factory.create_agent('ec2')
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        self.full_params['instance_ids'] = instance_ids

        # First instance ID doesn't exist, second call will succeed
        (self.fake_ec2.should_receive('terminate_instances')
         .and_raise(EC2ResponseError(400, 'no reason',
                                     self.multiple_instance_notfound_body.format(instance_ids[:])))
         .and_return(True))

        # _wait_for_status should return true.
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_return(self.terminated_reservations))

        instance_ids = set(self.full_params[ec2.PARAM_INSTANCE_IDS])
        status_filters = {"instance-state-name": 'terminated',
                          "key-name": self.full_params[ec2.PARAM_KEYNAME]}
        conn = ec2.open_connection(self.full_params)
        result = ec2._EC2Agent__terminate_instances(instance_ids, conn, status_filters, max_attempts=1)

        self.assertTrue(result)

    def test_ec2_terminate_instances_keeps_running(self):
        """
        Test out case where all instances keep running.
        boto.terminate_instances throws InstanceIDInvalid.NotFound
        We recover and keep waiting for the other 2 instances, which keep running
        and do *not* terminate.

        Will take about 120 seconds to run (timeout)

        Should return False
        """
        ec2 = self.factory.create_agent('ec2')
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        self.full_params['instance_ids'] = instance_ids

        # First instance ID doesn't exist, second call will succeed
        (self.fake_ec2.should_receive('terminate_instances')
         .and_raise(EC2ResponseError(400, 'no reason',
                                     self.instance_notfound_body.format(instance_ids[0])))
         .and_return(True))

        # _wait_for_status should return true.
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_return(self.empty_reservations))

        instance_ids = set(self.full_params[ec2.PARAM_INSTANCE_IDS])
        status_filters = {"instance-state-name": 'terminated',
                          "key-name": self.full_params[ec2.PARAM_KEYNAME]}
        conn = ec2.open_connection(self.full_params)
        result = ec2._EC2Agent__terminate_instances(instance_ids, conn, status_filters, max_attempts=1)

        self.assertFalse(result)
Esempio n. 8
0
class TestEC2AgentStatusChange(TestCase):
    """
    Test cases that test out the ec2agent.wait_for_status_change() method and how
    it handles the cases where an instance id is not found.
    """
    def setUp(self):
        self.factory = InfrastructureAgentFactory()
        self.fake_ec2 = flexmock(name='self.fake_ec2')
        flexmock(boto.ec2)
        boto.ec2.should_receive('connect_to_region').and_return(self.fake_ec2)

        reservation = Reservation()
        instance = flexmock(name='instance', private_dns_name='private-ip',
                            public_dns_name='public-ip', id='i-aabbccee', state='running',
                            key_name='bookeyname', ip_address='public-ip',
                            private_ip_address='private-ip')
        new_instance = flexmock(name='new-instance', private_dns_name='new-private-ip',
                                public_dns_name='new-public-ip', id='i-aabbccff',
                                state='running', key_name='bookeyname',
                                ip_address='new-public-ip',
                                private_ip_address='new-private-ip')

        t_aabbccee = flexmock(name='instance', private_dns_name='private-ip',
                              public_dns_name='public-ip', id='i-aabbccee', state='terminated',
                              key_name='bookeyname', ip_address='public-ip',
                              private_ip_address='private-ip')
        t_aabbccff = flexmock(name='new-instance', private_dns_name='new-private-ip',
                              public_dns_name='new-public-ip', id='i-aabbccff',
                              state='terminated', key_name='bookeyname',
                              ip_address='new-public-ip',
                              private_ip_address='new-private-ip')
        t_aabbccdd = flexmock(name='instance', private_dns_name='private-ip',
                              public_dns_name='public-ip', id='i-aabbccdd', state='terminated',
                              key_name='bookeyname', ip_address='public-ip',
                              private_ip_address='private-ip')

        reservation.instances = [instance]
        new_reservation = Reservation()
        new_reservation.instances = [instance, new_instance]

        # For testing wait_for_status
        self.good_reservation = Reservation()
        self.good_reservation.instances = [instance, new_instance]
        self.good_reservations = [self.good_reservation]
        self.terminated_reservation = Reservation()

        # Used because we filter for 'terminated' and it should return no instances..
        self.empty_reservation = Reservation()
        self.empty_reservation.instances = []
        self.empty_reservations = [self.empty_reservation]

        self.terminated_reservation.instances = [t_aabbccee, t_aabbccff, t_aabbccdd]
        self.terminated_reservations = [self.terminated_reservation]

        self.instance_notfound_body = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance ID '{}' does not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.multiple_instances_not_found = """
        <Response xmlns=""><Errors>
        <Error>
        <Code>InvalidInstanceID.NotFound</Code>
        <Message>The instance IDs '{}' do not exist</Message>
        </Error></Errors>
        <RequestID>23548a3a-d6c8-4de7-b846-4e072587c582</RequestID></Response>
        """

        self.full_params = {
            'credentials': {
                'a': 'b', 'EC2_URL': 'http://testing.appscale.com:8773/foo/bar',
                'EC2_ACCESS_KEY': 'access_key', 'EC2_SECRET_KEY': 'secret_key'},
            'group': 'boogroup',
            'image_id': 'booid',
            'infrastructure': 'ec2',
            'instance_type': 'booinstance_type',
            'keyname': 'bookeyname',
            'num_vms': '1',
            'use_spot_instances': False,
            'region': 'my-zone-1',
            'zone': 'my-zone-1b',
            'autoscale_agent': True
        }

    def test_ec2_wait_for_status_change_invalid_filters(self):
        """
        Simple test case if an invalid filter is passed"
        """
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        with self.assertRaisesRegexp(InvalidFilter, 'instance-state-name is missing from filter'):
            ec2.wait_for_status_change(['i-aabbccdd'], conn, filters={})

    def test_ec2_wait_for_status_change_stopped_not_found(self):
        """
        When waiting for the 'stopped' state, if an instance is not found
        it is considered to be an error and the method will throw
        an InstanceIDNotFound exception.
        """
        filters = {'instance-state-name': 'stopped',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        # Throw an invalid id when stopping an instance. wait_for_status should raise an
        # exception.
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_raise(EC2ResponseError(400, "no reason",
                                     self.instance_notfound_body.format('i-aabbccdd'))))

        with self.assertRaises(InstanceIDNotFound):
            ec2.wait_for_status_change(['i-aabbccdd'], conn, filters, 5, 1)

    def test_ec2_wait_for_status_change_already_terminated(self):
        """
        Terminate an instance and the cloud returns InvalidInstanceID.NotFound

        This should be reported as a success
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)

        instance_ids = ['i-aabbccdd']
        self.fake_ec2.should_receive('get_all_reservations').and_raise(
            EC2ResponseError(400, "no reason", self.instance_notfound_body.format(instance_ids[0])))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=10, poll_interval=1)
        self.assertTrue(result)

    def test_ec2_wait_for_status_change_one_not_found_terminated(self):
        """
        The first instance id in the list is marked as not found.

        Note: self.terminated_reservations does return the instance id, which shouldn't have an impact
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)

        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        (self.fake_ec2.should_receive('get_all_reservations')
            .and_raise(EC2ResponseError(400, "no reason",
                                        self.instance_notfound_body.format(instance_ids[0])))
            .and_return(self.terminated_reservations))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=10, poll_interval=1)

        self.assertTrue(result)

    def test_ec2_wait_for_status_change_all_not_found_terminated(self):
        """
        Case where all instances are not found

        Should return True
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']

        # Raise an exception for each instance id in serial
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_raise(EC2ResponseError(400, "no reason", self.instance_notfound_body.format(instance_ids[0])))
         .and_raise(EC2ResponseError(400, "no reason", self.instance_notfound_body.format(instance_ids[1])))
         .and_raise(EC2ResponseError(400, "no reason", self.instance_notfound_body.format(instance_ids[2]))))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=5, poll_interval=1)

        self.assertTrue(result)

    def test_ec2_wait_for_status_change_multiple_not_found(self):
        """
        Case where multiple instances are not found.

        Should return True
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']

        # Raise exception for the first two instance ids.
        missing_ids = ','.join(instance_ids[0:2])
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_raise(EC2ResponseError(400, "no reason",
                                     self.multiple_instances_not_found.format(missing_ids)))
         .and_return(self.terminated_reservations))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=5, poll_interval=1)

        self.assertTrue(result)

    def test_ec2_wait_for_status_change_multiple_not_found_different_order(self):
        """
        Multiple instance ids not found, first one is found

        Should return True
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']

        # Raise exception for the first two instance ids.
        missing_ids = ','.join(instance_ids[1:])
        (self.fake_ec2.should_receive('get_all_reservations')
         .and_raise(EC2ResponseError(400, "no reason",
                                     self.multiple_instances_not_found.format(missing_ids)))
         .and_return(self.terminated_reservations))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=5, poll_interval=1)

        self.assertTrue(result)

    def test_ec2_wait_for_status_change_keeps_on_running(self):
        """
        Case where all instances keep running and never reach 'terminated'

        Should return False
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)
        # First element is missing
        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']

        (self.fake_ec2.should_receive('get_all_reservations')
            .and_raise(EC2ResponseError(400, 'no reason',
                                        self.instance_notfound_body.format(instance_ids[1])))
            .and_return(self.empty_reservations)
            .and_return(self.empty_reservations)
            .and_return(self.empty_reservations)
            .and_return(self.empty_reservations)
         )

        # Last two won't reach terminated state
        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=3, poll_interval=1)

        self.assertFalse(result)

    def test_ec2_wait_for_status_change_successfully_terminated(self):
        """
        The first instance id in the list is marked as not found.

        Note: self.terminated_reservations does return the instance id, which shouldn't have an impact
        """
        filters = {'instance-state-name': 'terminated',
                   'key-name': self.full_params['keyname']}
        ec2 = self.factory.create_agent('ec2')
        conn = ec2.open_connection(self.full_params)

        instance_ids = ['i-aabbccdd', 'i-aabbccee', 'i-aabbccff']
        (self.fake_ec2.should_receive('get_all_reservations')
            .and_return(self.terminated_reservations))

        result = ec2.wait_for_status_change(instance_ids, conn, filters, max_wait_time=10, poll_interval=1)

        self.assertTrue(result)

    def tearDown(self):
        pass
Esempio n. 9
0
    def test_gce_run_instances(self):
        # mock out interactions with GCE
        # first, mock out the oauth library calls
        fake_credentials = flexmock(name='fake_credentials', invalid=False)
        fake_storage = flexmock(name='fake_storage')
        fake_storage.should_receive('get').and_return(fake_credentials)

        flexmock(oauth2client.file)
        oauth2client.file.should_receive('Storage').with_args(
            GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

        # next, mock out http calls to GCE
        fake_http = flexmock(name='fake_http')
        fake_authorized_http = flexmock(name='fake_authorized_http')

        flexmock(httplib2)
        httplib2.should_receive('Http').and_return(fake_http)
        fake_credentials.should_receive('authorize').with_args(fake_http) \
            .and_return(fake_authorized_http)

        # add some fake data in where no instances are initially running, then one
        # is (in response to our insert request)
        no_instance_info = {}

        instance_id = u'appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d'
        list_instance_info = {
            u'items': [{
                u'status':
                u'RUNNING',
                u'kind':
                u'compute#instance',
                u'machineType':
                u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/machineTypes/n1-standard-1',
                u'name':
                instance_id,
                u'zone':
                u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b',
                u'tags': {
                    u'fingerprint': u'42WmSpB8rSM='
                },
                u'image':
                u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/images/lucid64',
                u'disks': [{
                    u'index': 0,
                    u'kind': u'compute#attachedDisk',
                    u'type': u'EPHEMERAL',
                    u'mode': u'READ_WRITE'
                }],
                u'canIpForward':
                False,
                u'serviceAccounts': [{
                    u'scopes': [GCEAgent.GCE_SCOPE],
                    u'email':
                    u'*****@*****.**'
                }],
                u'metadata': {
                    u'kind': u'compute#metadata',
                    u'fingerprint': u'42WmSpB8rSM='
                },
                u'creationTimestamp':
                u'2013-05-22T11:52:33.254-07:00',
                u'id':
                u'8684033495853907982',
                u'selfLink':
                u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d',
                u'networkInterfaces': [{
                    u'accessConfigs': [{
                        u'kind': u'compute#accessConfig',
                        u'type': u'ONE_TO_ONE_NAT',
                        u'name': u'External NAT',
                        u'natIP': u'public-ip'
                    }],
                    u'networkIP':
                    u'private-ip',
                    u'network':
                    u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazgroup',
                    u'name':
                    u'nic0'
                }]
            }],
            u'kind':
            u'compute#instanceList',
            u'id':
            u'projects/appscale.com:appscale/zones/my-zone-1b/instances',
            u'selfLink':
            u'https://www.googleapis.com/compute/v1beta14/projects/961228229472/zones/my-zone-1b/instances'
        }

        fake_list_instance_request = flexmock(
            name='fake_list_instance_request')
        fake_list_instance_request.should_receive('execute').with_args(
            http=fake_authorized_http).and_return(no_instance_info) \
            .and_return(no_instance_info) \
            .and_return(list_instance_info)

        fake_instances = flexmock(name='fake_instances')
        fake_gce = flexmock(name='fake_gce')
        fake_gce.should_receive('instances').and_return(fake_instances) \
            .and_return(fake_instances).and_return(fake_instances)
        fake_instances.should_receive('list').with_args(project=self.project,
                                                        filter="name eq boogroup-.*", zone='my-zone-1b') \
            .and_return(fake_list_instance_request) \
            .and_return(fake_list_instance_request)

        # we only need to create one node, so set up mocks for that
        add_instance = u'operation-1369248752891-4dd5311848461-afc55a20'
        add_instance_info = {
            u'status': u'PENDING',
            u'kind': u'compute#operation',
            u'name': add_instance,
            u'azone': unicode(GCEAgent.GCE_URL) +
            u'appscale.com:appscale/zones/my-zone-1b',
            u'startTime': u'2013-05-22T11:52:32.939-07:00',
            u'insertTime': u'2013-05-22T11:52:32.891-07:00',
            u'targetLink': unicode(GCEAgent.GCE_URL) +
            u'appscale.com:appscale/zones/my-zone-1b/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d',
            u'operationType': u'insert',
            u'progress': 0,
            u'id': u'6663616273628949255',
            u'selfLink': unicode(GCEAgent.GCE_URL) +
            u'appscale.com:appscale/zones/my-zone-1b/operations/operation-1369248752891-4dd5311848461-afc55a20',
            u'user': u'*****@*****.**'
        }

        fake_add_instance_request = flexmock(name='fake_add_instance_request')
        fake_add_instance_request.should_receive('execute').with_args(
            http=fake_authorized_http).and_return(add_instance_info)

        fake_instances.should_receive('insert').with_args(
            project=self.project, body=dict,
            zone=str).and_return(fake_add_instance_request)

        created_instance_info = {u'status': u'DONE'}

        fake_instance_checker = flexmock(name='fake_network_checker')
        fake_instance_checker.should_receive('execute').and_return(
            created_instance_info)

        fake_blocker = flexmock(name='fake_blocker')
        fake_gce.should_receive('globalOperations').and_return(fake_blocker)
        fake_blocker.should_receive('get').with_args(
            project=self.project,
            operation=add_instance).and_return(fake_instance_checker)

        # finally, inject our fake GCE connection
        flexmock(discovery)
        discovery.should_receive('build').with_args(
            'compute', GCEAgent.API_VERSION).and_return(fake_gce)

        # next, presume that the persistent disk we want to use exists
        disk_name = 'my-persistent-disk-1'
        disk_info = {'status': 'DONE'}
        fake_disk_request = flexmock(name='fake_disk_request')
        fake_disk_request.should_receive('execute').with_args(
            http=fake_authorized_http).and_return(disk_info)

        fake_disks = flexmock(name='fake_disks')
        fake_disks.should_receive('get').with_args(
            project=self.project, disk=disk_name,
            zone=str).and_return(fake_disk_request)
        fake_disks.should_receive('insert').with_args(
            project=self.project, sourceImage=str, body=dict,
            zone=str).and_return(fake_disk_request)

        fake_gce.should_receive('disks').and_return(fake_disks)

        i = InfrastructureAgentFactory.create_agent('gce')
        # first, validate that the run_instances call goes through successfully
        # and gives the user an operation id

        agent_run_instances_result = ([
            u'appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d'
        ], ['public-ip'], ['private-ip'])
        security_configured = i.configure_instance_security(self.params)

        self.assertTupleEqual(
            agent_run_instances_result,
            i.run_instances(int(self.params['num_vms']),
                            self.params,
                            security_configured,
                            public_ip_needed=False))