Source code for utah.provisioning.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 basic inventory routines."""


import logging
import os
import sqlite3

from utah.config import config
from utah.provisioning.exceptions import UTAHProvisioningException


[docs]class UTAHProvisioningInventoryException(UTAHProvisioningException): """Provide a class for UTAH provisioning inventory exceptions.""" pass
[docs]class Inventory(object): """Provide a generic class for an arbitrary inventory of machines. Raise exceptions for most methods, since they should be defined by subclasses. Except for special read-only cases, subclasses should provide request(). Subclasses will generally also need to provide delete() for cleanup purposes. All other methods (i.e. release, destroy) are optional. """ def __init__(self, uniqueid, lockfile='~/.utah-inventory'): """Initialize inventory lock mechanism. To avoid provisioning machines to multiple requestors simultaneously, Inventory implements a lock file. Each inventory type should provide a unique id, which is combined with the class name to generate an inventory identifier. This identifier is stored in the lock file and checked on class instantiation to ensure the same inventory is running. Subclasses can circumvent this by not calling the superclass __init__ function if necessary. """ inventory = '{}{}'.format(self.__class__.__name__, str(uniqueid)) self.lockfile = os.path.expanduser(lockfile) if os.path.isfile(self.lockfile): lockfile = open(self.lockfile, 'r') userinventory = lockfile.read() lockfile.close() if inventory != userinventory: raise UTAHProvisioningInventoryException( 'Different inventory in use: {}\n' 'Delete {} if you are sure it is no longer valid' .format(userinventory, self.lockfile)) else: lockfile = open(self.lockfile, 'w') lockfile.write(inventory) lockfile.close()
[docs] def delete(self): """Delete this inventory and remove the lockfile. Subclasses can call this via super to delete the lockfile, or implement lockfile deletion in their delete() method. """ os.unlink(self.lockfile) del self
[docs] def request(self, machinetype=None, *args, **kw): """Return a Machine object that can be provisioned and run tests. May interpret arguments and call the appropriate constructor with the appropriate arguments, or may take a Machine class as an argument and send all arguments to that constructor. """ raise UTAHProvisioningInventoryException( 'Method not defined for this inventory')
[docs] def release(self): """Release a Machine for later use. Indicate that a machine is not now in use for tests, but may still have a working installed system, potentially suitable for further use. :returns: False since this is unimplemented but not exception-worthy :rtype: bool """ return False
[docs] def destroy(self): """Mark a machine as destroyed and unusable for future tests. Current implementations do not call machine.destroy(), requiring that do be done separately. :returns: False since this is unimplemented but not exception-worthy :rtype: bool """ return False
[docs]class SQLiteInventory(Inventory): """Provide basic SQLite database access with a cursor.""" def __init__(self, db='~/.utah-sqlite-inventory', *args, **kw): db = os.path.expanduser(db) super(SQLiteInventory, self).__init__(*args, uniqueid=db, **kw) self.db = db self._connection = sqlite3.connect( self.db, config.sqlite3_db_connection_timeout) self._connection.isolation_level = None self._connection.row_factory = sqlite3.Row
[docs] def execute(self, sql, parameters=None): """Execute SQL statement and return cursor. This method is expected to be used as a wrapper around all `connection.execute` calls so that all the SQL statements are logged in case this information is needed to troubleshoot problems. :param sql: A sql statement to be executed :type sql: str :param parameters: Parameters to use to replace the placeholder values in the sql statement. :type parameters: list (question mark placeholders) | dict (colon named placeholders) :returns: Cursor used to execute statement :rtype: object """ if parameters is None: parameters = [] logging.debug('Executing SQL statement: {}, {}' .format(sql, parameters)) cursor = self._connection.execute(sql, parameters) return cursor
[docs] def delete(self): """Remove database.""" os.unlink(self.db) super(SQLiteInventory, self).delete()
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.