Source code for utah.provisioning.baremetal.inventory

# Ubuntu Testing Automation Harness
# Copyright 2012 Canonical Ltd.

# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.

# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.

# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
Provide inventory functions specific to bare metal deployments.
"""

import logging
import os

from utah.process import pid_in_use
from utah.provisioning.inventory import (
    UTAHProvisioningInventoryException,
    SQLiteInventory,
)


[docs]class ManualBaremetalSQLiteInventory(SQLiteInventory): """Keep an inventory of manually entered machines. All columns other than machineid, name, and state are assumed to be arguments for system creation (i.e., with cobbler). """ def __init__(self, db='~/.utah-baremetal-inventory', lockfile='~/.utah-baremetal-lock', *args, **kw): db = os.path.expanduser(db) lockfile = os.path.expanduser(lockfile) if not os.path.isfile(db): raise UTAHProvisioningInventoryException( 'No machine database found at {}'.format(db)) super(ManualBaremetalSQLiteInventory, self).__init__( *args, db=db, lockfile=lockfile, **kw) machines_count = (self.execute('SELECT COUNT(*) FROM machines') .fetchall()[0][0]) if machines_count == 0: raise UTAHProvisioningInventoryException('No machines in database') self.machines = []
[docs] def request(self, machinetype, name=None, *args, **kw): """Return a Machine object meeting the given criteria. :param machinetype: What machine type to use :type machinetype: class :param name: Name of machine to use :type: str or None All other parameters are passed to Machine constructor. :returns: Machine object :rtype: obj """ query = 'SELECT * FROM machines' queryvars = [] if name is not None: query += ' WHERE name=?' queryvars.append(name) result = self.execute(query, queryvars).fetchall() if result is None: raise UTAHProvisioningInventoryException( 'No machines meet criteria') else: for minfo in result: machineinfo = dict(minfo) if machineinfo['state'] == 'available': return self._take(machineinfo, machinetype, *args, **kw) for minfo in result: machineinfo = dict(minfo) pid = machineinfo['pid'] proc = pid_in_use(pid, ['utah', 'run_test']) if not proc: return self._take(machineinfo, machinetype, *args, **kw) else: logging.info('machine in use by: %s', proc.cmdline) raise UTAHProvisioningInventoryException( 'All machines meeting criteria are currently unavailable')
def _take(self, machineinfo, machinetype, *args, **kw): machineid = machineinfo.pop('machineid') name = machineinfo.pop('name') state = machineinfo.pop('state') machineinfo.pop('pid') update = self.execute( 'UPDATE machines ' "SET pid=?, state='provisioned' " 'WHERE machineid=? AND state=?', [os.getpid(), machineid, state]).rowcount if update == 1: machine = machinetype(*args, inventory=self, machineinfo=machineinfo, name=name, **kw) self.machines.append(machine) return machine elif update == 0: raise UTAHProvisioningInventoryException( 'Machine was requested by another process') elif update > 1: raise UTAHProvisioningInventoryException( 'Multiple machines exist matching those criteria; ' 'database {} may be corrupt'.format(self.db)) else: raise UTAHProvisioningInventoryException( 'Negative rowcount returned when requesting machine')
[docs] def release(self, machine=None, name=None): """Release a machine so it can be used by other processes. :param machine: Machine object to release :type machine: obj or None :param name: name of machine to release :type name: str or None """ if machine is not None: name = machine.name if name is None: raise UTAHProvisioningInventoryException( 'name required to release a machine') query = "UPDATE machines SET state='available' WHERE name=?" queryvars = [name] update = self.execute(query, queryvars).rowcount if update == 1: if machine is not None: if machine in self.machines: self.machines.remove(machine) elif update == 0: raise UTAHProvisioningInventoryException( 'SERIOUS ERROR: Another process released this machine ' 'before we could, which means two processes provisioned ' 'the same machine simultaneously') elif update > 1: raise UTAHProvisioningInventoryException( 'Multiple machines exist matching those criteria; ' 'database {} may be corrupt'.format(self.db)) else: raise UTAHProvisioningInventoryException( 'Negative rowcount returned when releasing machine') # Here is how I currently create the database: # CREATE TABLE machines (machineid INTEGER PRIMARY KEY, # name TEXT NOT NULL UNIQUE, # state TEXT default 'available', # pid INT, # [mac-address] TEXT NOT NULL UNIQUE, # [power-address] TEXT DEFAULT '10.97.0.13', # [power-id] TEXT, # [power-user] TEXT DEFAULT 'ubuntu', # [power-pass] TEXT DEFAULT 'ubuntu', # [power-type] TEXT DEFAULT 'sentryswitch_cdu'); # Here is how I currently populate the database: # INSERT INTO machines (name, [mac-address], [power-id]) # VALUES ('acer-veriton-01-Pete', 'd0:27:88:9f:73:ce', 'Veriton_1'); # INSERT INTO machines (name, [mac-address], [power-id]) # VALUES ('acer-veriton-02-Pete', 'd0:27:88:9b:84:5b', 'Veriton_2');
Read the Docs v: latest
Versions
latest
Downloads
PDF
HTML
Epub
On Read the Docs
Project Home
Builds

Free document hosting provided by Read the Docs.