def test_terminate_with_concurrent_read(self):
        scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 1, 'Succeeded')
        updated_scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 0, 'Succeeded')
        instance = AzureScaleSetInstance('fake_id', 'fake_vm', datetime.now())
        future = TestingFuture()

        mock_api = mock.Mock(AzureApi)
        mock_api.list_scale_sets = mock.Mock(return_value=[scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[instance])
        mock_api.terminate_scale_set_instances = mock.Mock(return_value=future)

        cached_api = AzureWriteThroughCachedApi(mock_api)

        self.assertEqual(cached_api.list_scale_sets('test_rg'), [scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(scale_set), [instance])
        cached_api.terminate_scale_set_instances(scale_set, [instance])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(scale_set)
        mock_api.terminate_scale_set_instances.assert_called_once_with(scale_set, [instance])

        # Call list again concurrently with the delete, and make sure it's still served from the cache
        self.assertEqual(cached_api.list_scale_sets('test_rg'), [scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(scale_set), [instance])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(scale_set)

        future.complete()
        mock_api.list_scale_sets = mock.Mock(return_value=[updated_scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[])
        self.assertEqual(cached_api.list_scale_sets('test_rg'), [updated_scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(updated_scale_set), [])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(updated_scale_set)
示例#2
0
    def test_failed_scale_up(self):
        region = 'test'

        mock_client, monitor_client, resource_client = _default_mock_clients(
            region)

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        failed_scale_set = AzureScaleSet(region, resource_group,
                                         'test-scale-set1', instance_type, 0,
                                         'Failed')
        scale_set = AzureScaleSet(region, resource_group, 'test-scale-set2',
                                  instance_type, 0, 'Succeeded')

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group,
            AzureWrapper(mock_client, monitor_client, resource_client),
            instance_type, False, [failed_scale_set, scale_set], [])

        virtual_scale_set.scale(5)

        mock_client.virtual_machine_scale_sets.create_or_update.assert_called_once(
        )
        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.
            call_args[1]['parameters'].sku.capacity, 5)
示例#3
0
    def test_slow_scale_up(self):
        region = 'test'

        mock_client, monitor_client, resource_client = _default_mock_clients(
            region)

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region, resource_group, 'test-scale-set',
                                  instance_type, 0, 'Succeeded')
        scale_set2 = AzureScaleSet(region, resource_group, 'test-scale-set2',
                                   instance_type, 0, 'Succeeded')

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group,
            AzureWrapper(mock_client, monitor_client, resource_client),
            instance_type, True, [scale_set, scale_set2], [])

        virtual_scale_set.scale(2)

        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.call_count,
            2)
        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.
            call_args_list[0][1]['parameters'].sku.capacity, 1)
        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.
            call_args_list[1][1]['parameters'].sku.capacity, 1)
    def test_update(self):
        scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 1, 'Succeeded')
        updated_scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 0, 'Succeeded')
        instance = AzureScaleSetInstance('fake_id', 'fake_vm', datetime.now())
        future = CompletedFuture(None)

        mock_api = mock.Mock(AzureApi)
        mock_api.list_scale_sets = mock.Mock(return_value=[scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[instance])
        mock_api.update_scale_set = mock.Mock(return_value=future)

        cached_api = AzureWriteThroughCachedApi(mock_api)

        self.assertEqual(cached_api.list_scale_sets('test_rg'), [scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(scale_set), [instance])
        cached_api.update_scale_set(scale_set, 0).result()
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(scale_set)
        mock_api.update_scale_set.assert_called_once_with(scale_set, 0)

        mock_api.list_scale_sets = mock.Mock(return_value=[updated_scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[])
        self.assertEqual(cached_api.list_scale_sets('test_rg'), [updated_scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(updated_scale_set), [])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(updated_scale_set)
    def test_inconsistent_delegate(self):
        scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 0, 'Succeeded')
        updated_scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 1, 'Succeeded')
        instance = AzureScaleSetInstance('fake_id', 'fake_vm', datetime.now())
        future = CompletedFuture(None)

        mock_api = mock.Mock(AzureApi)
        mock_api.list_scale_sets = mock.Mock(return_value=[scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[])
        mock_api.update_scale_set = mock.Mock(return_value=future)

        cached_api = AzureWriteThroughCachedApi(mock_api)

        self.assertEqual(cached_api.list_scale_sets('test_rg'), [scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(scale_set), [])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(scale_set)
        cached_api.update_scale_set(scale_set, 1).result()
        mock_api.update_scale_set.assert_called_once_with(scale_set, 1)

        mock_api.list_scale_sets = mock.Mock(return_value=[updated_scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[])
        self.assertEqual(cached_api.list_scale_sets('test_rg'), [updated_scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(updated_scale_set), [])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(updated_scale_set)

        # Test that even if there is inconsistency between the list_scale_sets and list_scale_set_instances, the
        # cache doesn't end up with bad data
        mock_api.list_scale_set_instances = mock.Mock(return_value=[instance])
        self.assertEqual(cached_api.list_scale_set_instances(updated_scale_set), [instance])
        mock_api.list_scale_set_instances.assert_called_once_with(updated_scale_set)
    def test_refresh(self):
        scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16',
                                  1, 'Succeeded')
        updated_scale_set = AzureScaleSet('eastus', 'test_rg', 'test',
                                          'Standard_H16', 0, 'Succeeded')
        scale_set2 = AzureScaleSet('eastus', 'test_rg', 'test2',
                                   'Standard_H16', 0, 'Succeeded')
        instance = AzureScaleSetInstance('fake_id', 'fake_vm', datetime.now())

        mock_api = mock.Mock(AzureApi)
        mock_api.list_scale_sets = mock.Mock(return_value=[scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[instance])

        cached_api = AzureWriteThroughCachedApi(mock_api)

        self.assertEqual(cached_api.list_scale_sets('test_rg'), [scale_set])
        self.assertEqual(cached_api.list_scale_set_instances(scale_set),
                         [instance])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(scale_set)

        mock_api.list_scale_sets = mock.Mock(
            return_value=[updated_scale_set, scale_set2])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[])
        self.assertEqual(
            set(cached_api.list_scale_sets('test_rg', force_refresh=True)),
            {updated_scale_set, scale_set2})
        self.assertEqual(
            cached_api.list_scale_set_instances(updated_scale_set), [])
        mock_api.list_scale_sets.assert_called_once_with('test_rg')
        mock_api.list_scale_set_instances.assert_called_once_with(
            updated_scale_set)
示例#7
0
    def test_scale_in(self):
        region = 'test'
        resource_group = 'test-resource-group'

        instance = VirtualMachineScaleSetVM(location=region)
        instance.vm_id = 'test-vm-id'
        instance.instance_id = 0
        instance.instance_view = VirtualMachineInstanceView()
        instance.instance_view.statuses = []

        mock_client, monitor_client, resource_client = _default_mock_clients(
            region, instances=[instance])

        TestNode = collections.namedtuple('TestNode',
                                          ['instance_id', 'unschedulable'])
        test_node = TestNode(instance_id=instance.vm_id, unschedulable=False)

        instance_type = 'Standard_D1_v2'
        scale_set = AzureScaleSet(region, resource_group, 'test-scale-set',
                                  instance_type, 1, 'Succeeded')

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group,
            AzureWrapper(mock_client, monitor_client, resource_client),
            instance_type, False, [scale_set], [test_node])

        self.assertEqual(virtual_scale_set.instance_ids, {instance.vm_id})
        self.assertEqual(virtual_scale_set.nodes, [test_node])

        virtual_scale_set.scale_nodes_in([test_node])
        mock_client.virtual_machine_scale_sets.delete_instances.assert_called_once_with(
            resource_group, scale_set.name, [instance.instance_id])
示例#8
0
    def test_tainted_scale_set(self):
        region = 'test'

        mock_client, monitor_client, resource_client = _default_mock_clients(
            region)

        instance_type = 'Standard_NC24'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region,
                                  resource_group,
                                  'test-scale-set',
                                  instance_type,
                                  0,
                                  'Succeeded',
                                  no_schedule_taints={'gpu': 'yes'})

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group,
            AzureWrapper(mock_client, monitor_client, resource_client),
            instance_type, True, [scale_set], [])

        dir_path = os.path.dirname(os.path.realpath(__file__))
        with open(os.path.join(dir_path, 'data/busybox.yaml'), 'r') as f:
            dummy_pod = yaml.load(f.read())
        pod = KubePod(pykube.Pod(None, dummy_pod))

        self.assertFalse(virtual_scale_set.is_taints_tolerated(pod))

        dummy_pod['spec']['tolerations'] = [{
            'key': 'gpu',
            'operator': 'Exists'
        }]
        pod = KubePod(pykube.Pod(None, dummy_pod))
        self.assertTrue(virtual_scale_set.is_taints_tolerated(pod))
示例#9
0
    def test_scale_up(self):
        region = 'test'
        mock_client = mock.Mock()
        mock_client.virtual_machine_scale_set_vms = mock.Mock()
        mock_client.virtual_machine_scale_set_vms.list = mock.Mock(
            return_value=[])
        mock_client.virtual_machine_scale_sets = mock.Mock()
        mock_client.virtual_machine_scale_sets.create_or_update = mock.Mock()

        monitor_client = mock.Mock()
        monitor_client.activity_logs = mock.Mock()
        monitor_client.activity_logs.list = mock.Mock(return_value=[])

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region, resource_group, 'test-scale-set',
                                  instance_type, 0, 'Succeeded')

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group, AzureWrapper(mock_client, monitor_client),
            instance_type, False, [scale_set], [])

        virtual_scale_set.scale(5)

        mock_client.virtual_machine_scale_sets.create_or_update.assert_called_once(
        )
        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.
            call_args[1]['parameters'].sku.capacity, 5)
示例#10
0
    def test_out_of_quota(self):
        region = 'test'
        mock_client = mock.Mock()
        mock_client.virtual_machine_scale_set_vms = mock.Mock()
        mock_client.virtual_machine_scale_set_vms.list = mock.Mock(
            return_value=[])
        mock_client.virtual_machine_scale_sets = mock.Mock()
        mock_client.virtual_machine_scale_sets.create_or_update = mock.Mock()

        monitor_client = mock.Mock()
        monitor_client.activity_logs = mock.Mock()
        monitor_client.activity_logs.list = mock.Mock(return_value=[])

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region,
                                  resource_group,
                                  'test-scale-set',
                                  instance_type,
                                  0,
                                  'Succeeded',
                                  timeout_until=datetime.now(pytz.utc) +
                                  timedelta(minutes=10),
                                  timeout_reason="fake reason")
        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group, AzureWrapper(mock_client, monitor_client),
            instance_type, False, [scale_set], [])
        self.assertTrue(virtual_scale_set.is_timed_out())
    def test_out_of_quota(self):
        scale_set = VirtualMachineScaleSet('eastus', {}, sku=Sku('Standard_H16', capacity=1))
        scale_set.name = 'test'
        scale_set.provisioning_state = 'Succeeded'
        scale_set.id = 'fake_id'

        compute_client = mock.Mock()
        compute_client.virtual_machine_scale_sets = mock.Mock()
        compute_client.virtual_machine_scale_sets.list = mock.Mock(return_value=[scale_set])

        reason = "Operation results in exceeding quota limits of Core. Maximum allowed: 800, Current in use: 784, Additional requested: 320."
        message = "{\"error\":{\"code\":\"OperationNotAllowed\",\"message\":\"" + reason + "\"}}"
        monitor_client = mock.Mock()
        monitor_client.activity_logs = mock.Mock()
        now = datetime.now(pytz.utc)
        monitor_client.activity_logs.list = mock.Mock(return_value=[EventData('Error',
                                                                              now,
                                                                              now,
                                                                              resource_id=scale_set.id,
                                                                              status=LocalizableString('Failed'),
                                                                              properties={'statusCode': 'Conflict',
                                                                                          'statusMessage': message})])

        api = AzureWrapper(compute_client, monitor_client)
        resource_group = 'test_rg'
        expected = AzureScaleSet(scale_set.location, resource_group, scale_set.name, scale_set.sku.name, scale_set.sku.capacity,
                                 scale_set.provisioning_state, now + TIMEOUT_PERIOD, reason)
        acutal = api.list_scale_sets(resource_group)
        self.assertEqual([expected], acutal)

        compute_client.virtual_machine_scale_sets.list.assert_called_once_with(resource_group)
        monitor_client.activity_logs.list.assert_called_once()
    def test_basic(self):
        scale_set = VirtualMachineScaleSet(
            'eastus', {
                PRIORITY_TAG: '1',
                NO_SCHEDULE_TAINTS_TAG: json.dumps({'gpu': 'yes'})
            },
            sku=Sku('Standard_H16', capacity=1))
        scale_set.name = 'test'
        scale_set.provisioning_state = 'Succeeded'
        scale_set.id = 'fake_id'

        compute_client = mock.Mock()
        compute_client.virtual_machine_scale_sets = mock.Mock()
        compute_client.virtual_machine_scale_sets.list = mock.Mock(
            return_value=[scale_set])

        monitor_client = mock.Mock()
        monitor_client.activity_logs = mock.Mock()
        monitor_client.activity_logs.list = mock.Mock(return_value=[])

        api = AzureWrapper(compute_client, monitor_client, None)
        resource_group = 'test_rg'
        expected = AzureScaleSet(scale_set.location,
                                 resource_group,
                                 scale_set.name,
                                 scale_set.sku.name,
                                 scale_set.sku.capacity,
                                 scale_set.provisioning_state,
                                 priority=1,
                                 no_schedule_taints={'gpu': 'yes'})
        self.assertEqual([expected], api.list_scale_sets(resource_group))

        compute_client.virtual_machine_scale_sets.list.assert_called_once_with(
            resource_group)
        monitor_client.activity_logs.list.assert_called_once()
示例#13
0
    def test_priority(self):
        region = 'test'
        mock_client = mock.Mock()
        mock_client.virtual_machine_scale_set_vms = mock.Mock()
        mock_client.virtual_machine_scale_set_vms.list = mock.Mock(
            return_value=[])
        mock_client.virtual_machine_scale_sets = mock.Mock()
        mock_client.virtual_machine_scale_sets.create_or_update = mock.Mock()

        monitor_client = mock.Mock()
        monitor_client.activity_logs = mock.Mock()
        monitor_client.activity_logs.list = mock.Mock(return_value=[])

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region,
                                  resource_group,
                                  'test-scale-set',
                                  instance_type,
                                  0,
                                  'Succeeded',
                                  priority=-1)
        # Name sorts lexicographically before previous scale set, but priority is after it
        scale_set2 = AzureScaleSet(region,
                                   resource_group,
                                   'a-test-scale-set',
                                   instance_type,
                                   0,
                                   'Succeeded',
                                   priority=1)

        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group, AzureWrapper(mock_client, monitor_client),
            instance_type, True, [scale_set, scale_set2], [])

        virtual_scale_set.scale(1)

        self.assertEqual(virtual_scale_set.global_priority, -1)

        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.call_count,
            1)
        self.assertEqual(
            mock_client.virtual_machine_scale_sets.create_or_update.
            call_args_list[0][0][1], 'test-scale-set')
    def test_copied(self):
        scale_set = AzureScaleSet('eastus', 'test_rg', 'test', 'Standard_H16', 1, 'Succeeded')
        instance = AzureScaleSetInstance('fake_id', 'fake_vm', datetime.now())

        mock_api = mock.Mock(AzureApi)
        mock_api.list_scale_sets = mock.Mock(return_value=[scale_set])
        mock_api.list_scale_set_instances = mock.Mock(return_value=[instance])

        cached_api = AzureWriteThroughCachedApi(mock_api)

        returned_scale_set = cached_api.list_scale_sets('test_rg')[0]
        self.assertEqual(returned_scale_set.capacity, 1)
        returned_scale_set.capacity = 0
        self.assertEqual(cached_api.list_scale_sets('test_rg')[0].capacity, 1)

        returned_instance = cached_api.list_scale_set_instances(scale_set)[0]
        self.assertEqual(returned_instance.vm_id, 'fake_vm')
        returned_instance.vm_id = 'modified'
        self.assertEqual(cached_api.list_scale_set_instances(scale_set)[0].vm_id, 'fake_vm')
示例#15
0
    def test_out_of_quota(self):
        region = 'test'

        mock_client, monitor_client, resource_client = _default_mock_clients(
            region)

        instance_type = 'Standard_D1_v2'
        resource_group = 'test-resource-group'
        scale_set = AzureScaleSet(region,
                                  resource_group,
                                  'test-scale-set',
                                  instance_type,
                                  0,
                                  'Succeeded',
                                  timeout_until=datetime.now(pytz.utc) +
                                  timedelta(minutes=10),
                                  timeout_reason="fake reason")
        virtual_scale_set = AzureVirtualScaleSet(
            region, resource_group,
            AzureWrapper(mock_client, monitor_client, resource_client),
            instance_type, False, [scale_set], [])
        self.assertTrue(virtual_scale_set.is_timed_out())