Пример #1
0
 def test_match_devices_without_map(self):
     """
     Without a map, there is no support for knowing which interfaces to
     put onto a VLAN, so these devices cannot be assigned to a VLAN testjob
     See http://localhost/static/docs/v2/vland.html#vland-and-interface-tags-in-lava
     """
     self.bbb3 = self.factory.make_device(self.factory.bbb_type,
                                          hostname="bbb-03")
     self.cubie2 = self.factory.make_device(self.factory.cubie_type,
                                            hostname="cubie2")
     devices = [self.bbb3, self.cubie2]
     self.factory.ensure_tag("usb-eth")
     self.factory.ensure_tag("sata")
     self.factory.bbb1.tags.set(Tag.objects.filter(name="usb-eth"))
     self.factory.cubie1.tags.set(Tag.objects.filter(name="sata"))
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__),
                                    "sample_jobs",
                                    "bbb-cubie-vlan-group.yaml")
     with open(sample_job_file, "r") as test_support:
         data = yaml_safe_load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml_safe_dump(data), user)
     assignments = {}
     for job in vlan_job:
         self.assertFalse(
             match_vlan_interface(self.bbb3,
                                  yaml_safe_load(job.definition)))
         self.assertFalse(
             match_vlan_interface(self.cubie2,
                                  yaml_safe_load(job.definition)))
Пример #2
0
 def test_vlan_interface(self):  # pylint: disable=too-many-locals
     device_dict = DeviceDictionary.get('bbb-01')
     chk = {
         'hostname': 'bbb-01',
         'parameters': {
             'map': {'eth1': {'192.168.0.2': 7}, 'eth0': {'192.168.0.2': 5}},
             'interfaces': ['eth0', 'eth1'],
             'sysfs': {
                 'eth1': '/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1',
                 'eth0': '/sys/devices/pci0000:00/0000:00:19.0/net/eth0'
             },
             'mac_addr': {'eth1': '00:24:d7:9b:c0:8c', 'eth0': 'f0:de:f1:46:8c:21'},
             'tags': {'eth1': ['1G'], 'eth0': ['1G', '10G']}}
     }
     self.assertEqual(chk, device_dict.to_dict())
     submission = yaml.load(open(self.filename, 'r'))
     self.assertIn('protocols', submission)
     self.assertIn('lava-vland', submission['protocols'])
     roles = [role for role, _ in submission['protocols']['lava-vland'].iteritems()]
     params = submission['protocols']['lava-vland']
     vlans = {}
     for role in roles:
         for name, tags in params[role].iteritems():
             vlans[name] = tags
     self.assertIn('vlan_one', vlans)
     self.assertIn('vlan_two', vlans)
     jobs = split_multinode_yaml(submission, 'abcdefghijkl')
     job_roles = {}
     for role in roles:
         self.assertEqual(len(jobs[role]), 1)
         job_roles[role] = jobs[role][0]
     for role in roles:
         self.assertIn('device_type', job_roles[role])
         self.assertIn('protocols', job_roles[role])
         self.assertIn('lava-vland', job_roles[role]['protocols'])
     client_job = job_roles['client']
     server_job = job_roles['server']
     self.assertIn('vlan_one', client_job['protocols']['lava-vland'])
     self.assertIn('10G', client_job['protocols']['lava-vland']['vlan_one']['tags'])
     self.assertIn('vlan_two', server_job['protocols']['lava-vland'])
     self.assertIn('1G', server_job['protocols']['lava-vland']['vlan_two']['tags'])
     client_tags = client_job['protocols']['lava-vland']['vlan_one']
     client_dict = DeviceDictionary.get('bbb-01').to_dict()
     for interface, tags in client_dict['parameters']['tags'].iteritems():
         if any(set(tags).intersection(client_tags)):
             self.assertEqual(interface, 'eth0')
             self.assertEqual(
                 client_dict['parameters']['map'][interface],
                 {'192.168.0.2': 5}
             )
     # find_device_for_job would have a call to match_vlan_interface(device, job.definition) added
     bbb1 = Device.objects.get(hostname='bbb-01')
     self.assertTrue(match_vlan_interface(bbb1, client_job))
     cubie1 = Device.objects.get(hostname='ct-01')
     self.assertTrue(match_vlan_interface(cubie1, server_job))
Пример #3
0
 def test_same_type_devices_with_map(self):
     bbb2 = self.factory.make_device(self.factory.bbb_type, hostname='bbb-02')
     devices = list(Device.objects.filter(status=Device.IDLE).order_by('is_public'))
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'bbb-bbb-vland-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertIsNotNone(device)
         self.assertEqual(device.device_type, job.requested_device_type)
         # map has been defined
         self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
         if device in devices:
             devices.remove(device)
     assign_jobs()
     self.factory.bbb1.refresh_from_db()
     bbb2.refresh_from_db()
     self.assertIsNotNone(self.factory.bbb1.current_job)
     self.assertIsNotNone(bbb2.current_job)
     self.assertIsNotNone(self.factory.bbb1.current_job.actual_device)
     self.assertIsNotNone(bbb2.current_job.actual_device)  # pylint: disable=no-member
     self.assertNotEqual(self.factory.bbb1.current_job, bbb2.current_job)
     self.assertNotEqual(
         self.factory.bbb1.current_job.actual_device, bbb2.current_job.actual_device)  # pylint: disable=no-member
Пример #4
0
 def test_match_devices_without_map(self):
     """
     Without a map, there is no support for knowing which interfaces to
     put onto a VLAN, so these devices cannot be assigned to a VLAN testjob
     See http://localhost/static/docs/v2/vland.html#vland-and-interface-tags-in-lava
     """
     self.bbb3 = self.factory.make_device(self.factory.bbb_type, hostname='bbb-03')
     self.cubie2 = self.factory.make_device(self.factory.cubie_type, hostname='cubie2')
     devices = [self.bbb3, self.cubie2]
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertIsNone(device)
         # no map defined
         self.assertFalse(match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
     self.assertIsNone(assignments['client'])
     self.assertIsNone(assignments['server'])
Пример #5
0
def schedule_jobs_for_device(logger, device):
    jobs = TestJob.objects.filter(
        state__in=[TestJob.STATE_SUBMITTED, TestJob.STATE_SCHEDULING])
    jobs = jobs.filter(actual_device__isnull=True)
    jobs = jobs.filter(requested_device_type__pk=device.device_type.pk)
    jobs = jobs.order_by("-state", "-priority", "submit_time", "target_group",
                         "id")

    for job in jobs:
        if not device.can_submit(job.submitter):
            continue

        device_tags = set(device.tags.all())
        job_tags = set(job.tags.all())
        if not job_tags.issubset(device_tags):
            continue

        job_dict = yaml.safe_load(job.definition)
        if 'protocols' in job_dict and 'lava-vland' in job_dict['protocols']:
            if not match_vlan_interface(device, job_dict):
                continue

        logger.debug(" -> %s (%s, %s)", device.hostname,
                     device.get_state_display(), device.get_health_display())
        logger.debug("  |--> [%d] scheduling", job.id)
        if job.is_multinode:
            # TODO: keep track of the multinode jobs
            job.go_state_scheduling(device)
        else:
            job.go_state_scheduled(device)
        job.save()
        return job.id
    return None
Пример #6
0
 def test_match_devices_without_map(self):
     devices = Device.objects.filter(
         status=Device.IDLE).order_by('is_public')
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__),
                                    'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # no map defined
         self.assertFalse(
             match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
     self.assertEqual(assignments['client'].hostname,
                      self.factory.bbb1.hostname)
     self.assertEqual(assignments['server'].hostname,
                      self.factory.cubie1.hostname)
Пример #7
0
def schedule_jobs_for_device(logger, device):
    jobs = TestJob.objects.filter(
        state__in=[TestJob.STATE_SUBMITTED, TestJob.STATE_SCHEDULING]
    )
    jobs = jobs.filter(actual_device__isnull=True)
    jobs = jobs.filter(requested_device_type__pk=device.device_type.pk)
    jobs = jobs.order_by("-state", "-priority", "submit_time", "target_group", "id")

    for job in jobs:
        if not device.can_submit(job.submitter):
            continue

        device_tags = set(device.tags.all())
        job_tags = set(job.tags.all())
        if not job_tags.issubset(device_tags):
            continue

        if not device.is_valid():
            prev_health_display = device.get_health_display()
            device.health = Device.HEALTH_BAD
            device.log_admin_entry(
                None,
                "%s → %s (Invalid device configuration)"
                % (prev_health_display, device.get_health_display()),
            )
            device.save()
            logger.debug(
                "%s → %s (Invalid device configuration for %s)"
                % (prev_health_display, device.get_health_display(), device.hostname)
            )
            continue

        job_dict = yaml.safe_load(job.definition)
        if "protocols" in job_dict and "lava-vland" in job_dict["protocols"]:
            if not match_vlan_interface(device, job_dict):
                continue

        logger.debug(
            " -> %s (%s, %s)",
            device.hostname,
            device.get_state_display(),
            device.get_health_display(),
        )
        logger.debug("  |--> [%d] scheduling", job.id)
        if job.is_multinode:
            # TODO: keep track of the multinode jobs
            job.go_state_scheduling(device)
        else:
            job.go_state_scheduled(device)
        job.save()
        return job.id
    return None
Пример #8
0
    def test_match_devices_with_map(self):
        devices = Device.objects.filter(status=Device.IDLE).order_by('is_public')
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'bbb-cubie-vlan-group.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        del(data['protocols']['lava-multinode']['roles']['client']['tags'])
        del(data['protocols']['lava-multinode']['roles']['server']['tags'])

        interfaces = []
        job_dict = split_multinode_yaml(data, 'abcdefg123456789')
        client_job = job_dict['client'][0]
        device_dict = self.factory.bbb1.load_configuration()
        self.assertIsNotNone(device_dict)
        tag_list = client_job['protocols']['lava-vland']['vlan_one']['tags']

        for interface in device_dict['parameters']['interfaces']:
            tags = device_dict['parameters']['interfaces'][interface]['tags']
            if set(tags) & set(tag_list) == set(tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces), len(client_job['protocols']['lava-vland'].keys()))

        interfaces = []
        server_job = job_dict['server'][0]
        device_dict = self.factory.cubie1.load_configuration()
        self.assertIsNotNone(device_dict)
        tag_list = server_job['protocols']['lava-vland']['vlan_two']['tags']
        for interface in device_dict['parameters']['interfaces']:
            tags = device_dict['parameters']['interfaces'][interface]['tags']
            if set(tags) & set(tag_list) == set(tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces), len(client_job['protocols']['lava-vland'].keys()))

        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)

        # vlan_one: client role. RJ45 10M. bbb device type
        # vlan_two: server role. RJ45 100M. cubie device type.

        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
        self.assertEqual(assignments['client'].hostname, self.factory.bbb1.hostname)
        self.assertEqual(assignments['server'].hostname, self.factory.cubie1.hostname)
Пример #9
0
 def test_same_type_devices_with_map(self):
     device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
     device_dict.parameters = {  # client, RJ45 10M 100M
         'extends': 'beaglebone-black.jinja2',
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
         'mac_addr': {'eth0': "f0:de:f1:46:8c:22", 'eth1': "00:24:d7:9b:c0:8b"},
         'tags': {'eth0': [], 'eth1': ['RJ45', '10M', '100M']},
         'map': {'eth0': {'192.168.0.2': 5}, 'eth1': {'192.168.0.2': 7}}
     }
     device_dict.save()
     bbb2 = self.factory.make_device(self.factory.bbb_type, hostname='bbb2')
     device_dict = DeviceDictionary(hostname=bbb2.hostname)
     device_dict.parameters = {  # server, RJ45 10M 100M
         'extends': 'beaglebone-black.jinja2',
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
         'mac_addr': {'eth0': "f0:de:f1:46:8c:21", 'eth1': "00:24:d7:9b:c0:8c"},
         'tags': {'eth0': [], 'eth1': ['RJ45', '10M', '100M']},
         'map': {'eth0': {'192.168.0.2': 7}, 'eth1': {'192.168.0.2': 9}}
     }
     device_dict.save()
     devices = list(Device.objects.filter(status=Device.IDLE).order_by('is_public'))
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'bbb-bbb-vland-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # map has been defined
         self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
         if device in devices:
             devices.remove(device)
     assign_jobs()
     self.factory.bbb1.refresh_from_db()
     bbb2.refresh_from_db()
     self.assertIsNotNone(self.factory.bbb1.current_job)
     self.assertIsNotNone(bbb2.current_job)
     self.assertIsNotNone(self.factory.bbb1.current_job.actual_device)
     self.assertIsNotNone(bbb2.current_job.actual_device)
     self.assertNotEqual(self.factory.bbb1.current_job, bbb2.current_job)
     self.assertNotEqual(self.factory.bbb1.current_job.actual_device, bbb2.current_job.actual_device)
Пример #10
0
 def test_match_devices_without_map(self):
     """
     Without a map, there is no support for knowing which interfaces to
     put onto a VLAN, so these devices cannot be assigned to a VLAN testjob
     See http://localhost/static/docs/v2/vland.html#vland-and-interface-tags-in-lava
     """
     self.bbb3 = self.factory.make_device(self.factory.bbb_type, hostname='bbb-03')
     self.cubie2 = self.factory.make_device(self.factory.cubie_type, hostname='cubie2')
     devices = [self.bbb3, self.cubie2]
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         self.assertFalse(match_vlan_interface(self.bbb3, yaml.load(job.definition)))
         self.assertFalse(match_vlan_interface(self.cubie2, yaml.load(job.definition)))
Пример #11
0
 def test_match_devices_with_map(self):
     devices = Device.objects.filter(status=Device.IDLE).order_by('is_public')
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
     device_dict.parameters = {
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
         'mac_addr': {'eth0': "f0:de:f1:46:8c:21", 'eth1': "00:24:d7:9b:c0:8c"},
         'tags': {'eth0': ['1G', '10G'], 'eth1': ['1G']},
         'map': {'eth0': {'192.168.0.2': 5}, 'eth1': {'192.168.0.2': 7}}
     }
     device_dict.save()
     device_dict = DeviceDictionary(hostname=self.factory.cubie1.hostname)
     device_dict.parameters = {
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
         'mac_addr': {'eth0': "f0:de:f1:46:8c:21", 'eth1': "00:24:d7:9b:c0:8c"},
         'tags': {'eth0': ['1G', '10G'], 'eth1': ['1G']},
         'map': {'eth0': {'192.168.0.2': 4}, 'eth1': {'192.168.0.2': 6}}
     }
     device_dict.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # map has been defined
         self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
     self.assertEqual(assignments['client'].hostname, self.factory.bbb1.hostname)
     self.assertEqual(assignments['server'].hostname, self.factory.cubie1.hostname)
Пример #12
0
def schedule_jobs_for_device(logger, device, print_header):
    jobs = TestJob.objects.filter(state=TestJob.STATE_SUBMITTED)
    jobs = jobs.filter(actual_device__isnull=True)
    jobs = jobs.filter(requested_device_type__pk=device.device_type.pk)
    jobs = jobs.select_related("submitter")
    jobs = jobs.order_by("-priority", "submit_time", "sub_id", "id")

    device_tags = set(device.tags.all())
    for job in jobs:
        if not device.can_submit(job.submitter):
            continue

        job_tags = set(job.tags.all())
        if not job_tags.issubset(device_tags):
            continue

        job_dict = yaml_safe_load(job.definition)
        if "protocols" in job_dict and "lava-vland" in job_dict["protocols"]:
            if not match_vlan_interface(device, job_dict):
                continue

        if print_header:
            logger.debug("- %s", device.device_type.name)

        logger.debug(
            " -> %s (%s, %s)",
            device.hostname,
            device.get_state_display(),
            device.get_health_display(),
        )
        logger.debug("  |--> [%d] scheduling", job.id)
        if job.is_multinode:
            # TODO: keep track of the multinode jobs
            job.go_state_scheduling(device)
        else:
            job.go_state_scheduled(device)
        job.save()
        return job.id
    return None
Пример #13
0
 def test_match_devices_without_map(self):
     devices = Device.objects.filter(status=Device.IDLE).order_by('is_public')
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__), 'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # no map defined
         self.assertFalse(match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
     self.assertEqual(assignments['client'].hostname, self.factory.bbb1.hostname)
     self.assertEqual(assignments['server'].hostname, self.factory.cubie1.hostname)
Пример #14
0
 def test_match_devices_with_map_and_tags(self):
     devices = Device.objects.filter(
         status=Device.IDLE).order_by('is_public')
     self.factory.ensure_tag('usb-eth')
     self.factory.ensure_tag('sata')
     self.factory.bbb1.tags = Tag.objects.filter(name='usb-eth')
     self.factory.bbb1.save()
     self.factory.cubie1.tags = Tag.objects.filter(name='sata')
     self.factory.cubie1.save()
     device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
     device_dict.parameters = {
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0':
             "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1':
             "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
         },
         'mac_addr': {
             'eth0': "f0:de:f1:46:8c:21",
             'eth1': "00:24:d7:9b:c0:8c"
         },
         'tags': {
             'eth0': [],
             'eth1': ['RJ45', '10M']
         },
         'map': {
             'eth0': {
                 '192.168.0.2': 5
             },
             'eth1': {
                 '192.168.0.2': 7
             }
         }
     }
     device_dict.save()
     device_dict = DeviceDictionary(hostname=self.factory.cubie1.hostname)
     device_dict.parameters = {
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0':
             "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1':
             "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
         },
         'mac_addr': {
             'eth0': "f0:de:f1:46:8c:21",
             'eth1': "00:24:d7:9b:c0:8c"
         },
         'tags': {
             'eth0': [],
             'eth1': ['RJ45', '100M']
         },
         'map': {
             'eth0': {
                 '192.168.0.2': 4
             },
             'eth1': {
                 '192.168.0.2': 6
             }
         }
     }
     device_dict.save()
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__),
                                    'bbb-cubie-vlan-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # map has been defined
         self.assertTrue(
             match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
     self.assertEqual(assignments['client'].hostname,
                      self.factory.bbb1.hostname)
     self.assertEqual(assignments['server'].hostname,
                      self.factory.cubie1.hostname)
Пример #15
0
 def test_same_type_devices_with_map(self):
     device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
     device_dict.parameters = {  # client, RJ45 10M 100M
         'extends': 'beaglebone-black.jinja2',
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0':
             "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1':
             "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
         },
         'mac_addr': {
             'eth0': "f0:de:f1:46:8c:22",
             'eth1': "00:24:d7:9b:c0:8b"
         },
         'tags': {
             'eth0': [],
             'eth1': ['RJ45', '10M', '100M']
         },
         'map': {
             'eth0': {
                 '192.168.0.2': 5
             },
             'eth1': {
                 '192.168.0.2': 7
             }
         }
     }
     device_dict.save()
     bbb2 = self.factory.make_device(self.factory.bbb_type, hostname='bbb2')
     device_dict = DeviceDictionary(hostname=bbb2.hostname)
     device_dict.parameters = {  # server, RJ45 10M 100M
         'extends': 'beaglebone-black.jinja2',
         'interfaces': ['eth0', 'eth1'],
         'sysfs': {
             'eth0':
             "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
             'eth1':
             "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
         },
         'mac_addr': {
             'eth0': "f0:de:f1:46:8c:21",
             'eth1': "00:24:d7:9b:c0:8c"
         },
         'tags': {
             'eth0': [],
             'eth1': ['RJ45', '10M', '100M']
         },
         'map': {
             'eth0': {
                 '192.168.0.2': 7
             },
             'eth1': {
                 '192.168.0.2': 9
             }
         }
     }
     device_dict.save()
     devices = list(
         Device.objects.filter(status=Device.IDLE).order_by('is_public'))
     user = self.factory.make_user()
     sample_job_file = os.path.join(os.path.dirname(__file__),
                                    'bbb-bbb-vland-group.yaml')
     with open(sample_job_file, 'r') as test_support:
         data = yaml.load(test_support)
     vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
     assignments = {}
     for job in vlan_job:
         device = find_device_for_job(job, devices)
         self.assertEqual(device.device_type, job.requested_device_type)
         # map has been defined
         self.assertTrue(
             match_vlan_interface(device, yaml.load(job.definition)))
         assignments[job.device_role] = device
         if device in devices:
             devices.remove(device)
     assign_jobs()
     self.factory.bbb1.refresh_from_db()
     bbb2.refresh_from_db()
     self.assertIsNotNone(self.factory.bbb1.current_job)
     self.assertIsNotNone(bbb2.current_job)
     self.assertIsNotNone(self.factory.bbb1.current_job.actual_device)
     self.assertIsNotNone(bbb2.current_job.actual_device)
     self.assertNotEqual(self.factory.bbb1.current_job, bbb2.current_job)
     self.assertNotEqual(self.factory.bbb1.current_job.actual_device,
                         bbb2.current_job.actual_device)
Пример #16
0
    def test_match_devices_with_map(self):
        devices = Device.objects.filter(
            status=Device.IDLE).order_by('is_public')
        device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
        device_dict.parameters = {  # client, RJ45 10M only
            'extends': 'beaglebone-black.jinja2',
            'interfaces': ['eth0', 'eth1'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:21",
                'eth1': "00:24:d7:9b:c0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 5
                },
                'eth1': {
                    '192.168.0.2': 7
                }
            }
        }
        device_dict.save()
        device_dict = DeviceDictionary(hostname=self.factory.cubie1.hostname)
        device_dict.parameters = {  # server includes 100M
            'extends': 'cubietruck.jinja2',
            'interfaces': ['eth0', 'eth1'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:21",
                'eth1': "00:24:d7:9b:c0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M', '100M']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 4
                },
                'eth1': {
                    '192.168.0.2': 6
                }
            }
        }
        device_dict.save()
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__),
                                       'bbb-cubie-vlan-group.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        del (data['protocols']['lava-multinode']['roles']['client']['tags'])
        del (data['protocols']['lava-multinode']['roles']['server']['tags'])

        interfaces = []
        job_dict = split_multinode_yaml(data, 'abcdefg123456789')
        client_job = job_dict['client'][0]
        device_dict = DeviceDictionary.get(
            self.factory.bbb1.hostname).to_dict()
        self.assertIsNotNone(device_dict)
        tag_list = client_job['protocols']['lava-vland']['vlan_one']['tags']
        for interface, tags in device_dict['parameters']['tags'].iteritems():
            if set(tags) & set(tag_list) == set(
                    tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces),
                         len(client_job['protocols']['lava-vland'].keys()))

        interfaces = []
        server_job = job_dict['server'][0]
        device_dict = DeviceDictionary.get(
            self.factory.cubie1.hostname).to_dict()
        self.assertIsNotNone(device_dict)
        tag_list = server_job['protocols']['lava-vland']['vlan_two']['tags']
        for interface, tags in device_dict['parameters']['tags'].iteritems():
            if set(tags) & set(tag_list) == set(
                    tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces),
                         len(client_job['protocols']['lava-vland'].keys()))

        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)

        # vlan_one: client role. RJ45 10M. bbb device type
        # vlan_two: server role. RJ45 100M. cubie device type.

        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(
                match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
        self.assertEqual(assignments['client'].hostname,
                         self.factory.bbb1.hostname)
        self.assertEqual(assignments['server'].hostname,
                         self.factory.cubie1.hostname)
Пример #17
0
    def _assign_jobs(self):
        """
        Check all jobs against all available devices and assign only if all conditions are met
        This routine needs to remain fast, so has to manage local cache variables of device status but
        still cope with a job queue over 1,000 and a device matrix of over 100. The main load is in
        find_device_for_job as *all* jobs in the queue must be checked at each tick. (A job far back in
        the queue may be the only job which exactly matches the most recent devices to become available.)

        When viewing the logs of these operations, the device will be Idle when Assigning to a Submitted
        job. That job may be for a device_type or a specific device (typically health checks use a specific
        device). The device will be Reserved when Assigned to a Submitted job on that device - the type will
        not be mentioned. The total number of assigned jobs and devices will be output at the end of each tick.
        Finally, the reserved device is removed from the local cache of available devices.

        Warnings are emitted if the device states are not as expected, before or after assignment.
        """
        # FIXME: this function needs to be moved to dispatcher-master when lava_scheduler_daemon is disabled.
        # FIXME: in dispatcher-master, implement as in share/zmq/assign.[dia|png]
        # FIXME: Make the forced health check constraint explicit
        # evaluate the testjob query set using list()
        self._validate_queue()
        jobs = list(self._get_job_queue())
        if not jobs:
            return
        assigned_jobs = []
        reserved_devices = []
        # this takes a significant amount of time when under load, only do it once per tick
        devices = list(self._get_available_devices())
        # a forced health check can be assigned even if the device is not in the list of idle devices.
        for job in jobs:
            device = find_device_for_job(job, devices)
            if device:
                if job.is_pipeline:
                    job_dict = yaml.load(job.definition)
                    if 'protocols' in job_dict and 'lava-vland' in job_dict['protocols']:
                        if not match_vlan_interface(device, job_dict):
                            self.logger.debug("%s does not match vland tags", str(device.hostname))
                            devices.remove(device)
                            continue
                if not self._validate_idle_device(job, device):
                    self.logger.debug("Removing %s from the list of available devices",
                                      str(device.hostname))
                    devices.remove(device)
                    continue
                self.logger.info("Assigning %s for %s", device, job)
                # avoid catching exceptions inside atomic (exceptions are slow too)
                # https://docs.djangoproject.com/en/1.7/topics/db/transactions/#controlling-transactions-explicitly
                if AuthToken.objects.filter(user=job.submitter).count():
                    job.submit_token = AuthToken.objects.filter(user=job.submitter).first()
                else:
                    job.submit_token = AuthToken.objects.create(user=job.submitter)
                try:
                    # Make this sequence atomic
                    with transaction.atomic():
                        job.actual_device = device
                        job.save()
                        device.current_job = job
                        # implicit device save in state_transition_to()
                        device.state_transition_to(
                            Device.RESERVED, message="Reserved for job %s" % job.display_id, job=job)
                except IntegrityError:
                    # Retry in the next call to _assign_jobs
                    self.logger.warning(
                        "Transaction failed for job %s, device %s", job.display_id, device.hostname)
                assigned_jobs.append(job.id)
                reserved_devices.append(device.hostname)
                self.logger.info("Assigned %s to %s", device, job)
                if device in devices:
                    self.logger.debug("Removing %s from the list of available devices",
                                      str(device.hostname))
                    devices.remove(device)
        # re-evaluate the devices query set using list() now that the job loop is complete
        devices = list(self._get_available_devices())
        postprocess = self._validate_non_idle_devices(reserved_devices, devices)
        if postprocess and reserved_devices:
            self.logger.debug("All queued jobs checked, %d devices reserved and validated", len(reserved_devices))

        # worker heartbeat must not occur within this loop
        self.logger.info("Assigned %d jobs on %s devices", len(assigned_jobs), len(reserved_devices))
Пример #18
0
    def test_match_devices_with_map(self):
        devices = Device.objects.filter(status=Device.IDLE).order_by('is_public')
        device_dict = DeviceDictionary(hostname=self.factory.bbb1.hostname)
        device_dict.parameters = {  # client, RJ45 10M only
            'extends': 'beaglebone-black.jinja2',
            'interfaces': ['eth0', 'eth1'],
            'sysfs': {
                'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
            'mac_addr': {'eth0': "f0:de:f1:46:8c:21", 'eth1': "00:24:d7:9b:c0:8c"},
            'tags': {'eth0': [], 'eth1': ['RJ45', '10M']},
            'map': {'eth0': {'192.168.0.2': 5}, 'eth1': {'192.168.0.2': 7}}
        }
        device_dict.save()
        device_dict = DeviceDictionary(hostname=self.factory.cubie1.hostname)
        device_dict.parameters = {  # server includes 100M
            'extends': 'cubietruck.jinja2',
            'interfaces': ['eth0', 'eth1'],
            'sysfs': {
                'eth0': "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1': "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1"},
            'mac_addr': {'eth0': "f0:de:f1:46:8c:21", 'eth1': "00:24:d7:9b:c0:8c"},
            'tags': {'eth0': [], 'eth1': ['RJ45', '10M', '100M']},
            'map': {'eth0': {'192.168.0.2': 4}, 'eth1': {'192.168.0.2': 6}}
        }
        device_dict.save()
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__), 'bbb-cubie-vlan-group.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        del(data['protocols']['lava-multinode']['roles']['client']['tags'])
        del(data['protocols']['lava-multinode']['roles']['server']['tags'])

        interfaces = []
        job_dict = split_multinode_yaml(data, 'abcdefg123456789')
        client_job = job_dict['client'][0]
        device_dict = DeviceDictionary.get(self.factory.bbb1.hostname).to_dict()
        self.assertIsNotNone(device_dict)
        tag_list = client_job['protocols']['lava-vland']['vlan_one']['tags']
        for interface, tags in device_dict['parameters']['tags'].iteritems():
            if set(tags) & set(tag_list) == set(tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces), len(client_job['protocols']['lava-vland'].keys()))

        interfaces = []
        server_job = job_dict['server'][0]
        device_dict = DeviceDictionary.get(self.factory.cubie1.hostname).to_dict()
        self.assertIsNotNone(device_dict)
        tag_list = server_job['protocols']['lava-vland']['vlan_two']['tags']
        for interface, tags in device_dict['parameters']['tags'].iteritems():
            if set(tags) & set(tag_list) == set(tag_list) and interface not in interfaces:
                interfaces.append(interface)
                break
        self.assertEqual(['eth1'], interfaces)
        self.assertEqual(len(interfaces), len(client_job['protocols']['lava-vland'].keys()))

        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)

        # vlan_one: client role. RJ45 10M. bbb device type
        # vlan_two: server role. RJ45 100M. cubie device type.

        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
        self.assertEqual(assignments['client'].hostname, self.factory.bbb1.hostname)
        self.assertEqual(assignments['server'].hostname, self.factory.cubie1.hostname)
Пример #19
0
    def test_differing_vlan_tags(self):
        """
        More devices of the requested type than needed by the test
        with some devices having unsuitable vland interface tags.
        """
        x86 = self.factory.make_device_type('x86')
        x86_1 = self.factory.make_device(device_type=x86, hostname='x86-01')
        x86_2 = self.factory.make_device(device_type=x86, hostname='x86-02')
        x86_3 = self.factory.make_device(device_type=x86, hostname='x86-03')
        x86_4 = self.factory.make_device(device_type=x86, hostname='x86-04')

        devices = list(Device.objects.filter(status=Device.IDLE).order_by('is_public'))
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'x86-vlan.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertIsNotNone(device)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
            if device in devices:
                devices.remove(device)
        assign_jobs()

        # reset state, pretend the assigned jobs have completed.
        for job in TestJob.objects.all():
            job.status = TestJob.COMPLETE
            job.actual_device.status = Device.IDLE
            job.actual_device.current_job = None
            job.actual_device.save(update_fields=['status', 'current_job'])
            job.save(update_fields=['status'])

        # take x86_1 offline, forcing the idle list to include x86_3 for evaluation

        x86_1.status = Device.OFFLINE
        x86_1.save(update_fields=['status'])
        x86_1.refresh_from_db()

        devices = list(Device.objects.filter(status=Device.IDLE).order_by('is_public'))
        self.assertNotIn(x86_1, devices)
        self.assertIn(x86_2, devices)
        self.assertIn(x86_3, devices)
        self.assertIn(x86_4, devices)
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs', 'x86-vlan.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertIsNotNone(device)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
            if device in devices:
                devices.remove(device)
        assign_jobs()
        x86_1.refresh_from_db()
        x86_2.refresh_from_db()
        x86_3.refresh_from_db()
        x86_4.refresh_from_db()
        self.assertEqual(Device.STATUS_CHOICES[Device.OFFLINE], Device.STATUS_CHOICES[x86_1.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.RESERVED], Device.STATUS_CHOICES[x86_2.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.IDLE], Device.STATUS_CHOICES[x86_3.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.RESERVED], Device.STATUS_CHOICES[x86_4.status])
Пример #20
0
    def test_differing_vlan_tags(self):
        """
        More devices of the requested type than needed by the test
        with some devices having unsuitable vland interface tags.
        """
        x86 = self.factory.make_device_type('x86')
        x86_1 = self.factory.make_device(device_type=x86, hostname='x86-1')
        device_dict = DeviceDictionary(hostname=x86_1.hostname)
        device_dict.parameters = {  # client, RJ45 10M 100M with separate 10G
            'extends': 'x86.jinja2',
            'interfaces': ['eth0', 'eth1', 'eth2'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1",
                'eth2':
                "/sys/devices/pci0000:00/0000:00:1c.2/0000:04:00.0/net/eth2"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:22",
                'eth1': "00:24:d7:9b:c0:8b",
                'eth2': "00:24:d7:9b:c0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M', '100M', '1G'],
                'eth2': ['SFP+', '10G']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 5
                },
                'eth1': {
                    '192.168.0.2': 7
                },
                'eth2': {
                    '192.168.0.2': 12
                }
            }
        }
        device_dict.save()

        x86_2 = self.factory.make_device(device_type=x86, hostname='x86-2')
        device_dict = DeviceDictionary(hostname=x86_2.hostname)
        device_dict.parameters = {  # client, RJ45 10M 100M with separate 10G
            'extends': 'x86.jinja2',
            'interfaces': ['eth0', 'eth1', 'eth2'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1",
                'eth2':
                "/sys/devices/pci0000:00/0000:00:1c.2/0000:04:00.0/net/eth2"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:22",
                'eth1': "00:24:d7:9b:d0:8b",
                'eth2': "00:24:d7:9b:d0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M', '100M', '1G'],
                'eth2': ['SFP+', '10G']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 14
                },
                'eth1': {
                    '192.168.0.2': 17
                },
                'eth2': {
                    '192.168.0.2': 22
                }
            }
        }
        device_dict.save()

        x86_3 = self.factory.make_device(device_type=x86, hostname='x86-3')
        device_dict = DeviceDictionary(hostname=x86_3.hostname)
        device_dict.parameters = {  # client, 40G, not 10G
            'extends': 'x86.jinja2',
            'interfaces': ['eth0', 'eth1', 'eth2'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1",
                'eth2':
                "/sys/devices/pci0000:00/0000:00:1c.2/0000:04:00.0/net/eth2"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:22",
                'eth1': "00:24:d7:9b:d0:8b",
                'eth2': "00:24:d7:9b:d0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M', '100M', '1G'],
                'eth2': ['QSFP+', '40G']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 15
                },
                'eth1': {
                    '192.168.0.2': 16
                },
                'eth2': {
                    '192.168.0.2': 20
                }
            }
        }
        device_dict.save()

        x86_4 = self.factory.make_device(device_type=x86, hostname='x86-4')
        device_dict = DeviceDictionary(hostname=x86_4.hostname)
        device_dict.parameters = {  # client, RJ45 10M 100M with separate 10G
            'extends': 'x86.jinja2',
            'interfaces': ['eth0', 'eth1', 'eth2'],
            'sysfs': {
                'eth0':
                "/sys/devices/pci0000:00/0000:00:19.0/net/eth0",
                'eth1':
                "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1",
                'eth2':
                "/sys/devices/pci0000:00/0000:00:1c.2/0000:04:00.0/net/eth2"
            },
            'mac_addr': {
                'eth0': "f0:de:f1:46:8c:22",
                'eth1': "00:24:d7:9b:d0:8b",
                'eth2': "00:24:d7:9b:d0:8c"
            },
            'tags': {
                'eth0': [],
                'eth1': ['RJ45', '10M', '100M', '1G'],
                'eth2': ['SFP+', '10G']
            },
            'map': {
                'eth0': {
                    '192.168.0.2': 14
                },
                'eth1': {
                    '192.168.0.2': 17
                },
                'eth2': {
                    '192.168.0.2': 22
                }
            }
        }
        device_dict.save()

        devices = list(
            Device.objects.filter(status=Device.IDLE).order_by('is_public'))
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__),
                                       'sample_jobs', 'x86-vlan.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertIsNotNone(device)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(
                match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
            if device in devices:
                devices.remove(device)
        assign_jobs()

        # reset state, pretend the assigned jobs have completed.
        for job in TestJob.objects.all():
            job.status = TestJob.COMPLETE
            job.actual_device.status = Device.IDLE
            job.actual_device.current_job = None
            job.actual_device.save(update_fields=['status', 'current_job'])
            job.save(update_fields=['status'])

        # take x86_1 offline, forcing the idle list to include x86_3 for evaluation

        x86_1.status = Device.OFFLINE
        x86_1.save(update_fields=['status'])
        x86_1.refresh_from_db()

        devices = list(
            Device.objects.filter(status=Device.IDLE).order_by('is_public'))
        self.assertNotIn(x86_1, devices)
        self.assertIn(x86_2, devices)
        self.assertIn(x86_3, devices)
        self.assertIn(x86_4, devices)
        user = self.factory.make_user()
        sample_job_file = os.path.join(os.path.dirname(__file__),
                                       'sample_jobs', 'x86-vlan.yaml')
        with open(sample_job_file, 'r') as test_support:
            data = yaml.load(test_support)
        vlan_job = TestJob.from_yaml_and_user(yaml.dump(data), user)
        assignments = {}
        for job in vlan_job:
            device = find_device_for_job(job, devices)
            self.assertIsNotNone(device)
            self.assertEqual(device.device_type, job.requested_device_type)
            # map has been defined
            self.assertTrue(
                match_vlan_interface(device, yaml.load(job.definition)))
            assignments[job.device_role] = device
            if device in devices:
                devices.remove(device)
        assign_jobs()
        x86_1.refresh_from_db()
        x86_2.refresh_from_db()
        x86_3.refresh_from_db()
        x86_4.refresh_from_db()
        self.assertEqual(Device.STATUS_CHOICES[Device.OFFLINE],
                         Device.STATUS_CHOICES[x86_1.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.RESERVED],
                         Device.STATUS_CHOICES[x86_2.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.IDLE],
                         Device.STATUS_CHOICES[x86_3.status])
        self.assertEqual(Device.STATUS_CHOICES[Device.RESERVED],
                         Device.STATUS_CHOICES[x86_4.status])