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)))
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))
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
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'])
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
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)
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
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)
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)
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)))
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)
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
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)
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)
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)
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)
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))
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)
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])
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])