From f5a1d2cd817ad0ee723d03ea59c634084ca5c554 Mon Sep 17 00:00:00 2001 From: Bill Peck Date: Jun 24 2011 03:12:52 +0000 Subject: Add Hypervisor to System This allows users to filter on different hypervisors. A NULL hypervisor value means bare metal. If you don't specify one you could end up on any. Bug: 714974 Change-Id: Id17834ed115645aed06789f4be8b17bb8462143e --- diff --git a/SchemaUpgrades/upgrade_0.6.14.txt b/SchemaUpgrades/upgrade_0.6.14.txt new file mode 100644 index 0000000..0abafe9 --- /dev/null +++ b/SchemaUpgrades/upgrade_0.6.14.txt @@ -0,0 +1,16 @@ +System hypervisor column (bug 714974) +------------------------------------- + +Add new column hypervisor_id: + + ALTER TABLE system + ADD COLUMN (hypervisor_id int(11)), + ADD CONSTRAINT system_hypervisor_id + FOREIGN KEY (hypervisor_id) REFERENCES hypervisor (id) + ON UPDATE CASCADE ON DELETE CASCADE; + +To roll back: + + ALTER TABLE system + DROP FOREIGN KEY system_hypervisor_id, + DROP COLUMN hypervisor_id; diff --git a/Server/bkr/server/controllers.py b/Server/bkr/server/controllers.py index fd16821..5ee52c0 100644 --- a/Server/bkr/server/controllers.py +++ b/Server/bkr/server/controllers.py @@ -1322,6 +1322,10 @@ class Root(RPCRoot): else: kw['lab_controller'] = LabController.by_id(kw['lab_controller_id']) kw['type'] = SystemType.by_id(kw['type_id']) + if kw['hypervisor_id'] == 0: + kw['hypervisor'] = None + else: + kw['hypervisor'] = Hypervisor.by_id(kw['hypervisor_id']) # Don't change lab controller while the system is in use if system.lab_controller != kw['lab_controller'] and \ @@ -1331,7 +1335,8 @@ class Root(RPCRoot): redirect('/view/%s' % system.fqdn) log_fields = [ 'fqdn', 'vendor', 'lender', 'model', 'serial', 'location', - 'mac_address', 'status', 'status_reason', 'lab_controller', 'type'] + 'mac_address', 'status', 'status_reason', + 'lab_controller', 'type', 'hypervisor'] for field in log_fields: try: @@ -1384,6 +1389,7 @@ class Root(RPCRoot): system.serial=kw['serial'] system.vendor=kw['vendor'] system.lender=kw['lender'] + system.hypervisor=kw['hypervisor'] if kw['fqdn'] != system.fqdn: system.remote.remove() system.fqdn=kw['fqdn'] diff --git a/Server/bkr/server/model.py b/Server/bkr/server/model.py index 3c306f1..0311706 100644 --- a/Server/bkr/server/model.py +++ b/Server/bkr/server/model.py @@ -49,6 +49,13 @@ from xml.dom.minidom import Node, parseString import logging log = logging.getLogger(__name__) +hypervisor_table = Table('hypervisor', metadata, + Column('id', Integer, autoincrement=True, + nullable=False, primary_key=True), + Column('hypervisor', Unicode(100), nullable=False), + mysql_engine='InnoDB', +) + system_table = Table('system', metadata, Column('id', Integer, autoincrement=True, nullable=False, primary_key=True), @@ -84,6 +91,8 @@ system_table = Table('system', metadata, ForeignKey('release_action.id')), Column('reprovision_distro_id', Integer, ForeignKey('distro.id')), + Column('hypervisor_id', Integer, + ForeignKey('hypervisor.id')), mysql_engine='InnoDB', ) @@ -1381,7 +1390,8 @@ class System(SystemObject): def __init__(self, fqdn=None, status=None, contact=None, location=None, model=None, type=None, serial=None, vendor=None, - owner=None, lab_controller=None, lender=None): + owner=None, lab_controller=None, lender=None, + hypervisor=None): self.fqdn = fqdn self.status = status self.contact = contact @@ -1393,6 +1403,7 @@ class System(SystemObject): self.owner = owner self.lab_controller = lab_controller self.lender = lender + self.hypervisor = hypervisor def to_xml(self, clone=False): """ Return xml describing this system """ @@ -2017,7 +2028,8 @@ url --url=$tree def get_update_method(self,obj_str): methods = dict ( Cpu = self.updateCpu, Arch = self.updateArch, - Devices = self.updateDevices, Numa = self.updateNuma ) + Devices = self.updateDevices, Numa = self.updateNuma, + Hypervisor = self.updateHypervisor, ) return methods[obj_str] def update_legacy(self, inventory): @@ -2118,6 +2130,19 @@ url --url=$tree self.date_modified = datetime.utcnow() return 0 + def updateHypervisor(self, hypervisor): + try: + hvisor = Hypervisor.by_name(hypervisor) + except InvalidRequestError: + raise BX(_('Invalid Hypervisor: %s' % hypervisor)) + if self.hypervisor != hvisor: + self.activity.append(SystemActivity( + user=identity.current.user, + service=u'XMLRPC', action=u'Changed', + field_name=u'Hypervisor', old_value=self.hypervisor, + new_value=hvisor)) + self.hypervisor = hvisor + def updateArch(self, archinfo): for arch in archinfo: try: @@ -2532,7 +2557,24 @@ class SystemCc(SystemObject): def __init__(self, email_address): self.email_address = email_address - + +class Hypervisor(SystemObject): + + def __repr__(self): + return self.hypervisor + + @classmethod + def get_all_types(cls): + """ + return an array of tuples containing id, hypervisor + """ + return [(hvisor.id, hvisor.hypervisor) for hvisor in cls.query()] + + @classmethod + @sqla_cache + def by_name(cls, hvisor): + return cls.query.filter_by(hypervisor=hvisor).one() + class SystemType(SystemObject): def __init__(self, type=None): @@ -6055,6 +6097,7 @@ class SystemStatusDuration(MappedObject): pass # set up mappers between identity tables and classes SystemType.mapper = mapper(SystemType, system_type_table) +Hypervisor.mapper = mapper(Hypervisor, hypervisor_table) SystemStatus.mapper = mapper(SystemStatus, system_status_table) mapper(ReleaseAction, release_action_table) System.mapper = mapper(System, system_table, @@ -6064,7 +6107,6 @@ System.mapper = mapper(System, system_table, 'devices':relation(Device, secondary=system_device_map,backref='systems'), 'type':relation(SystemType, uselist=False), - 'arch':relation(Arch, order_by=[arch_table.c.arch], secondary=system_arch_map, @@ -6119,6 +6161,7 @@ System.mapper = mapper(System, system_table, cascade='all, delete, delete-orphan', order_by=[system_status_duration_table.c.start_time.desc()]), 'dyn_status_durations': dynamic_loader(SystemStatusDuration), + 'hypervisor':relation(Hypervisor, uselist=False), }) mapper(SystemCc, system_cc_table) diff --git a/Server/bkr/server/needpropertyxml.py b/Server/bkr/server/needpropertyxml.py index 6569f98..738a370 100644 --- a/Server/bkr/server/needpropertyxml.py +++ b/Server/bkr/server/needpropertyxml.py @@ -362,6 +362,20 @@ class XmlDistroLabController(ElementWrapper): query = lab_controller_table.c.fqdn == value return (joins, query) +class XmlHypervisor(ElementWrapper): + """ + Pick a system based on the hypervisor. + """ + def filter(self, joins): + op = self.op_table[self.get_xml_attr('op', unicode, '==')] + value = self.get_xml_attr('value', unicode, None) or None + query = None + if op: + if not joins.is_derived_from(hypervisor_table): + joins = joins.outerjoin(hypervisor_table) + query = getattr(hypervisor_table.c.hypervisor, op)(value) + return (joins, query) + class XmlSystemType(ElementWrapper): """ Pick a system with the correct system type. @@ -470,6 +484,7 @@ subclassDict = { 'arch' : XmlArch, 'numa_node_count' : XmlNumaNodeCount, 'group' : XmlGroup, + 'hypervisor' : XmlHypervisor, } if __name__=='__main__': diff --git a/Server/bkr/server/templates/system_form.kid b/Server/bkr/server/templates/system_form.kid index 9ed5692..a6570cb 100644 --- a/Server/bkr/server/templates/system_form.kid +++ b/Server/bkr/server/templates/system_form.kid @@ -185,6 +185,14 @@ $(document).ready(function(){ (Change) + + + ${label_for('hypervisor_id')} + + + ${display_field_for("hypervisor_id")} + + Save Changes diff --git a/Server/bkr/server/test/data_setup.py b/Server/bkr/server/test/data_setup.py index f3ddabc..4e6ffab 100644 --- a/Server/bkr/server/test/data_setup.py +++ b/Server/bkr/server/test/data_setup.py @@ -29,7 +29,7 @@ from bkr.server.model import LabController, User, Group, Distro, Breed, Arch, \ Device, TaskResult, TaskStatus, Job, RecipeSet, TaskPriority, \ LabControllerDistro, Power, PowerType, TaskExcludeArch, TaskExcludeOSMajor, \ Permission, RetentionTag, Product, Watchdog, Reservation, LogRecipe, \ - LogRecipeTask, ExcludeOSMajor, ExcludeOSVersion + LogRecipeTask, ExcludeOSMajor, ExcludeOSVersion, Hypervisor log = logging.getLogger(__name__) @@ -144,7 +144,7 @@ def create_distro(name=None, breed=u'Dan', def create_system(arch=u'i386', type=u'Machine', status=u'Automated', owner=None, fqdn=None, shared=False, exclude_osmajor=[], - exclude_osversion=[], **kw): + exclude_osversion=[], hypervisor=None, **kw): if owner is None: owner = create_user() if fqdn is None: @@ -160,6 +160,8 @@ def create_system(arch=u'i386', type=u'Machine', status=u'Automated', osmajor=osmajor) for osmajor in exclude_osmajor) system.excluded_osversion.extend(ExcludeOSVersion(arch=Arch.by_name(arch), osversion=osversion) for osversion in exclude_osversion) + if hypervisor: + system.hypervisor = Hypervisor.by_name(hypervisor) system.date_modified = datetime.datetime.utcnow() log.debug('Created system %r', system) return system diff --git a/Server/bkr/server/test/selenium/test_system_view.py b/Server/bkr/server/test/selenium/test_system_view.py index 0e1a975..7a6776f 100644 --- a/Server/bkr/server/test/selenium/test_system_view.py +++ b/Server/bkr/server/test/selenium/test_system_view.py @@ -31,7 +31,7 @@ from bkr.server.test.selenium import SeleniumTestCase from bkr.server.test import data_setup, get_server_base, stub_cobbler, \ assertions from bkr.server.model import Key, Key_Value_String, Key_Value_Int, System, \ - Provision, ProvisionFamily, ProvisionFamilyUpdate + Provision, ProvisionFamily, ProvisionFamilyUpdate, Hypervisor class SystemViewTest(SeleniumTestCase): @@ -491,6 +491,18 @@ class SystemViewTest(SeleniumTestCase): self.assertEqual(sel.get_selected_label('lab_controller_id'), self.lab_controller.fqdn) + # https://bugzilla.redhat.com/show_bug.cgi?id=714974 + def test_change_hypervisor(self): + self.login() + sel = self.selenium + self.go_to_system_view() + sel.select('hypervisor_id', 'KVM') + sel.click('link=Save Changes') + sel.wait_for_page_to_load('30000') + self.assertEquals(sel.get_selected_label('hypervisor_id'), 'KVM') + session.refresh(self.system) + self.assertEqual(self.system.hypervisor, Hypervisor.by_name(u'KVM')) + class SystemCcTest(SeleniumTestCase): def setUp(self): diff --git a/Server/bkr/server/test/test_model.py b/Server/bkr/server/test/test_model.py index fce5396..3592ede 100644 --- a/Server/bkr/server/test/test_model.py +++ b/Server/bkr/server/test/test_model.py @@ -327,5 +327,36 @@ class DistroSystemsFilterTest(unittest.TestCase): self.assert_(with_cciss not in systems) self.assert_(without_cciss in systems) + # https://bugzilla.redhat.com/show_bug.cgi?id=714974 + def test_hypervisor(self): + baremetal = data_setup.create_system(arch=u'i386', shared=True, + lab_controller=self.lc, hypervisor=None) + kvm = data_setup.create_system(arch=u'i386', shared=True, + lab_controller=self.lc, hypervisor=u'KVM') + session.flush() + systems = list(self.distro.systems_filter(self.user, """ + + + + + + """)) + self.assert_(baremetal not in systems) + self.assert_(kvm in systems) + systems = list(self.distro.systems_filter(self.user, """ + + + + + + """)) + self.assert_(baremetal in systems) + self.assert_(kvm not in systems) + systems = list(self.distro.systems_filter(self.user, """ + + """)) + self.assert_(baremetal in systems) + self.assert_(kvm in systems) + if __name__ == '__main__': unittest.main() diff --git a/Server/bkr/server/tools/init.py b/Server/bkr/server/tools/init.py index 1125c9b..48d64eb 100755 --- a/Server/bkr/server/tools/init.py +++ b/Server/bkr/server/tools/init.py @@ -84,6 +84,13 @@ def init_db(user_name=None, password=None, user_display_name=None, user_email_ad laptop = SystemType(u'Laptop') prototype = SystemType(u'Prototype') + #Setup Hypervisors Table + if Hypervisor.query().count() == 0: + kvm = Hypervisor(hypervisor=u'KVM') + xen = Hypervisor(hypervisor=u'Xen') + hyperv = Hypervisor(hypervisor=u'HyperV') + vmware = Hypervisor(hypervisor=u'VMWare') + #Setup base Architectures if Arch.query().count() == 0: i386 = Arch(u'i386') diff --git a/Server/bkr/server/widgets.py b/Server/bkr/server/widgets.py index 5089517..13d0369 100644 --- a/Server/bkr/server/widgets.py +++ b/Server/bkr/server/widgets.py @@ -1218,6 +1218,10 @@ class SystemForm(Form): result_name="groups"), TextField(name='mac_address', label=_(u'Mac Address')), TextField(name='cc', label=_(u'Notify CC')), + SingleSelectField(name='hypervisor_id', + label=_(u'Hypervisor'), + options=lambda: [(0, 'None')] + model.Hypervisor.get_all_types(), + validator=validators.Int()), ] def display_value(self, item, hidden_fields, value=None):