Commit dd58a118 authored by Neil Williams's avatar Neil Williams Committed by Senthil Kumaran S
Browse files

LAVA-798 - lookup device-types by alias

Allow admins to configure aliases for device-types and provide an API
to lookup the device-type name by the alias (or a string contained
within the alias name).
Add documentation of how this can be used to relate device tree
names to device-type names whilst keeping device-type names which
are easily understood by humans. Device types can have any number
of aliases and some aliases can relate to multiple device types.

Change-Id: I1b2e877acb810addf82c4cafbc214b889a5cd110
parent 104feb59
......@@ -234,6 +234,10 @@ completed by the admin to provide information for test writers:
**Processor name**
e.g. AM335X
**Alias**
A list of :term:`aliases <alias>` for this device-type.
e.g. 'am335x-boneblack'
**CPU model name**
e.g. OMAP 4430 / OMAP4460
......@@ -244,3 +248,11 @@ completed by the admin to provide information for test writers:
**Bit count**
e.g. 32 or 64
.. note:: When modifying device type objects in the
:ref:`django_admin_interface`, take care with multiple selection boxes.
Fields like architecture name or :term:`alias` can show in the list as being
available for selection in a device type object but only the **selected**
line or lines will actually be saved as references within the device type
object. The references will show up on the device type detail page in the
*Information* tab.
......@@ -13,7 +13,7 @@ Glossary of terms
expected to need to read the entire glossary to find the information. FIXME
- need to add many more terms here
**A** [ :term:`action level` ]
**A** [ :term:`action level` ] [ :term:`alias` ]
**C** [ :term:`chart` ] [ :term:`ci loop` ]
......@@ -76,6 +76,14 @@ Glossary of terms
.. seealso:: :ref:`pipeline_construction`
alias
A string which can be used to relate the descriptive device-type name to a
particular list of aliases which could be used to lookup the matching
device-type. This can be useful to list the :term:`device tree blobs <DTB>`
which can be used with this device-type. (Aliases cannot be used in job
submissions directly.) Multiple device-types are allowed to share the one
or more aliases.
chart
A chart allows users to track :term:`results` over time using
:term:`queries <query>`.
......
......@@ -16,6 +16,8 @@ basic information on the type of device.
#. **Processor Family** (e.g. OMAP4, Exynos)
#. **Alias** (e.g. omap4-panda, omap4-panda-es)
#. **CPU model** (often empty but may contain a list of model strings which are
all equivalent within this device type).
......
......@@ -6,7 +6,7 @@ from django.db.models import Q
from lava_scheduler_app.models import (
Device, DeviceStateTransition, DeviceType, TestJob, Tag, JobFailureTag,
User, Worker, DefaultDeviceOwner,
Architecture, ProcessorFamily, BitWidth, Core
Architecture, ProcessorFamily, Alias, BitWidth, Core
)
from linaro_django_xmlrpc.models import AuthToken
......@@ -312,6 +312,10 @@ class DeviceTypeAdmin(admin.ModelAdmin):
return obj.cpu_model
return ''
def list_of_aliases(self, obj):
if obj.aliases:
return ', '.join([alias.name for alias in obj.aliases])
def bit_count(self, obj):
if obj.bits:
return obj.bits
......@@ -374,6 +378,7 @@ admin.site.register(TestJob, TestJobAdmin)
admin.site.register(Tag)
admin.site.register(Architecture)
admin.site.register(ProcessorFamily)
admin.site.register(Alias)
admin.site.register(BitWidth)
admin.site.register(Core)
admin.site.register(JobFailureTag)
......
......@@ -265,9 +265,11 @@ class SchedulerAPI(ExposedAPI):
"""
devices_list = []
for dev in Device.objects.exclude(status=Device.RETIRED).select_related('current_job', 'device_type'):
for dev in Device.objects.all():
if not dev.is_visible_to(self.user):
continue
if dev.status == Device.RETIRED:
continue
devices_list.append(dev)
return [list((dev.hostname, dev.device_type.name, Device.STATUS_CHOICES[dev.status][1].lower(), dev.current_job.pk if dev.current_job else None, dev.is_pipeline))
......@@ -317,6 +319,46 @@ class SchedulerAPI(ExposedAPI):
return all_device_types
def get_device_type_by_alias(self, alias):
"""
Name
----
`get_device_type_by_alias` (`alias`)
Description
-----------
Get the matching device-type(s) for the specified alias. It is
possible that more than one device-type can be returned, depending
on local admin configuration. An alias can be used to provide the
link between the device-type name and the Device Tree name.
It is possible for multiple device-types to have the same alias
(to assist in transitions and migrations).
The specified alias string can be a partial match, returning all
device-types which have an alias name containing the requested
string.
Arguments
---------
`alias`: string
Name of the alias to lookup
Return value
------------
This function returns a dictionary containing the alias as the key
and a list of device-types which use that alias as the value. If the
specified alias does not match any device-type, the dictionary contains
an empty list for the alias key.
{'apq8016-sbc': ['dragonboard410c']}
{'ompa4-panda': ['panda', 'panda-es']}
"""
aliases = DeviceType.objects.filter(aliases__name__contains=alias)
return {
alias: [device_type.name for device_type in aliases]
}
def get_device_status(self, hostname):
"""
Name
......
# -*- coding: utf-8 -*-
# Generated by Django 1.10.3 on 2016-11-21 11:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lava_scheduler_app', '0021_blacklist_to_array'),
]
operations = [
migrations.CreateModel(
name='Alias',
fields=[
('name', models.CharField(help_text='e.g. the device tree name(s)', max_length=200, primary_key=True, serialize=False, verbose_name='Alias for this device-type')),
],
),
migrations.AddField(
model_name='devicetype',
name='aliases',
field=models.ManyToManyField(blank=True, null=True, related_name='device_types', to='lava_scheduler_app.Alias'),
),
]
......@@ -223,6 +223,19 @@ class ProcessorFamily(models.Model):
return self.pk
class Alias(models.Model):
name = models.CharField(
primary_key=True,
verbose_name=u'Alias for this device-type',
help_text=u'e.g. the device tree name(s)',
max_length=200,
editable=True,
)
def __unicode__(self):
return self.pk
class BitWidth(models.Model):
width = models.PositiveSmallIntegerField(
primary_key=True,
......@@ -278,6 +291,12 @@ class DeviceType(models.Model):
editable=True,
)
aliases = models.ManyToManyField(
Alias,
related_name='device_types',
blank=True,
)
bits = models.ForeignKey(
BitWidth,
related_name='device_types',
......
......@@ -52,6 +52,8 @@
<dd>{{ processor|default:'.' }}</dd>
<dt>CPU model</dt>
<dd>{{ cpu_model|default:'.' }}</dd>
<dt>Aliases</dt>
<dd>{{ aliases|default:'.' }}</dd>
</dl>
</div>
<div class="col-md-6">
......
......@@ -11,10 +11,12 @@ from django.contrib.auth.models import Permission, User
from django.utils import timezone
from lava_scheduler_app.models import (
Device,
DeviceType,
Tag,
TestJob,
TemporaryDevice,
validate_yaml,
Alias,
)
from lava_scheduler_daemon.dbjobsource import DatabaseJobSource
from lava_scheduler_app.schema import validate_submission, validate_device, SubmissionException
......@@ -312,6 +314,27 @@ actions:
server.scheduler.get_device_status('black02')
)
def test_type_aliases(self):
aliases = DeviceType.objects.filter(aliases__name__contains='black')
retval = {
'black': [device_type.name for device_type in aliases]
}
self.assertEqual(retval, {'black': []})
device_type = self.factory.make_device_type('beaglebone-black')
alias = Alias.objects.create(name='am335x-boneblack')
device_type.aliases.add(alias)
aliases = DeviceType.objects.filter(aliases__name__contains='black')
retval = {
'black': [device_type.name for device_type in aliases]
}
self.assertEqual(retval, {'black': ['beaglebone-black']})
alias.delete()
aliases = DeviceType.objects.filter(aliases__name__contains='black')
retval = {
'black': [device_type.name for device_type in aliases]
}
self.assertEqual(retval, {'black': []})
# comment out the decorator to run this queue timing test
@unittest.skip('Developer only - timing test')
def test_queueing(self):
......
......@@ -794,6 +794,7 @@ def device_type_detail(request, pk):
bits_width = dt.bits.width if dt.bits else ''
cpu_name = dt.cpu_model if dt.cpu_model else ''
desc = dt.description if dt.description else ''
aliases = ', '.join([alias.name for alias in dt.aliases.all()])
if dt.health_check_job == "":
health_freq_str = ""
......@@ -812,6 +813,7 @@ def device_type_detail(request, pk):
'arch_bits': bits_width,
'cores': core_string,
'cpu_model': cpu_name,
'aliases': aliases,
'description': desc,
'search_data': search_data,
"discrete_data": discrete_data,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment