diff --git a/iotronic/api/controllers/v1/board.py b/iotronic/api/controllers/v1/board.py index 2a733ba..ce8b5d7 100644 --- a/iotronic/api/controllers/v1/board.py +++ b/iotronic/api/controllers/v1/board.py @@ -17,7 +17,7 @@ class Board(base.APIBase): """ uuid = types.uuid - name = wsme.wsattr(wtypes.text) + code = wsme.wsattr(int) status = wsme.wsattr(wtypes.text) @staticmethod @@ -226,9 +226,10 @@ class BoardsController(rest.RestController): 'updated_at': None, 'reservation': None, 'id': 106, 'name': u'provaaaa'} """ - b="{'status': '1', 'uuid': 'a9a86ab8-ad45-455e-86c3-d8f7d892ec9d', 'name': 'provaaaa'}" - board = Board(**b.as_dict()) - board.uuid = uuidutils.generate_uuid() + + uuid = uuidutils.generate_uuid() + b={'status': 'DISCONNECTED', 'uuid': uuid, 'code':'11223344'} + board = Board(**b) new_Board = objects.Board(pecan.request.context, **board.as_dict()) diff --git a/iotronic/conductor/manager.py b/iotronic/conductor/manager.py index 0dc4d7b..adcc207 100644 --- a/iotronic/conductor/manager.py +++ b/iotronic/conductor/manager.py @@ -59,7 +59,7 @@ from iotronic.common import swift from iotronic.iotconductor import task_manager from iotronic.iotconductor import utils -from iotronic import objects + from iotronic.openstack.common import periodic_task ''' @@ -78,6 +78,7 @@ import oslo_messaging as messaging from oslo_utils import excutils from oslo_utils import uuidutils from iotronic.conductor import utils +from iotronic import objects from iotronic.common import hash_ring as hash from iotronic.common.i18n import _ @@ -629,6 +630,7 @@ class ConductorManager(periodic_task.PeriodicTasks): host = CONF.host self.host = host self.topic = topic + self.drivers = ['fake'] #self.power_state_sync_count = collections.defaultdict(int) #self.notifier = rpc.get_notifier() ''' @@ -685,7 +687,7 @@ class ConductorManager(periodic_task.PeriodicTasks): self._collect_periodic_tasks(iface) ''' # clear all locks held by this conductor before registering - self.dbapi.clear_node_reservations_for_conductor(self.host) + #self.dbapi.clear_node_reservations_for_conductor(self.host) try: # Register this conductor with the cluster cdr = self.dbapi.register_conductor({'hostname': self.host,'drivers': ['fake']}) @@ -695,6 +697,8 @@ class ConductorManager(periodic_task.PeriodicTasks): LOG.warn(_LW("A conductor with hostname %(hostname)s " "was previously registered. Updating registration"), {'hostname': self.host}) + + #TO BE CHANGED cdr = self.dbapi.register_conductor({'hostname': self.host, 'drivers': self.drivers}, update_existing=True) @@ -1432,8 +1436,7 @@ class ConductorManager(periodic_task.PeriodicTasks): action=action, node=task.node.uuid, state=task.node.provision_state) - @periodic_task.periodic_task( - spacing=CONF.conductor.sync_power_state_interval) + #@periodic_task.periodic_task(spacing=CONF.conductor.sync_power_state_interval) def _sync_power_states(self, context): """Periodic task to sync power states for the nodes. @@ -1501,8 +1504,7 @@ class ConductorManager(periodic_task.PeriodicTasks): # Yield on every iteration eventlet.sleep(0) - @periodic_task.periodic_task( - spacing=CONF.conductor.check_provision_state_interval) + #@periodic_task.periodic_task(spacing=CONF.conductor.check_provision_state_interval) def _check_deploy_timeouts(self, context): """Periodically checks whether a deploy RPC call has timed out. @@ -1542,8 +1544,7 @@ class ConductorManager(periodic_task.PeriodicTasks): task.node.conductor_affinity = self.conductor.id task.node.save() - @periodic_task.periodic_task( - spacing=CONF.conductor.sync_local_state_interval) + #@periodic_task.periodic_task(spacing=CONF.conductor.sync_local_state_interval) def _sync_local_state(self, context): """Perform any actions necessary to sync local state. @@ -1617,7 +1618,7 @@ class ConductorManager(periodic_task.PeriodicTasks): nodes :return: generator yielding tuples of requested fields """ - columns = ['uuid', 'driver'] + list(fields or ()) + columns = ['uuid',] + list(fields or ()) node_list = self.dbapi.get_nodeinfo_list(columns=columns, **kwargs) for result in node_list: if self._mapped_to_this_conductor(*result[:2]): @@ -1905,8 +1906,7 @@ class ConductorManager(periodic_task.PeriodicTasks): driver = self._get_driver(driver_name) return driver.get_properties() - @periodic_task.periodic_task( - spacing=CONF.conductor.send_sensor_data_interval) + #@periodic_task.periodic_task(spacing=CONF.conductor.send_sensor_data_interval) def _send_sensor_data(self, context): """Periodically sends sensor data to Ceilometer.""" # do nothing if send_sensor_data option is False @@ -2130,8 +2130,7 @@ class ConductorManager(periodic_task.PeriodicTasks): action='inspect', node=task.node.uuid, state=task.node.provision_state) - @periodic_task.periodic_task( - spacing=CONF.conductor.check_provision_state_interval) + #@periodic_task.periodic_task(spacing=CONF.conductor.check_provision_state_interval) def _check_inspect_timeouts(self, context): """Periodically checks inspect_timeout and fails upon reaching it. @@ -2179,12 +2178,12 @@ class ConductorManager(periodic_task.PeriodicTasks): :param: last_error: the error message to be updated in node.last_error """ - node_iter = self.iter_nodes(filters=filters, + node_iter = self.iter_boards(filters=filters, sort_key=sort_key, sort_dir='asc') workers_count = 0 - for node_uuid, driver in node_iter: + for node_uuid in node_iter: try: with task_manager.acquire(context, node_uuid) as task: if (task.node.maintenance or @@ -2224,11 +2223,12 @@ class ConductorManager(periodic_task.PeriodicTasks): state to perform deletion. """ - with task_manager.acquire(context, board_id) as task: - board = task.board - board.destroy() - LOG.info(_LI('Successfully deleted board %(board)s.'), - {'board': board.uuid}) + #with task_manager.acquire(context, board_id) as task: + #board = task.board + board = objects.Board.get(context, board_id) + board.destroy() + LOG.info(_LI('Successfully deleted board %(board)s.'), + {'board': board.uuid}) #if board.instance_uuid is not None: # raise exception.BoardAssociated(board=board.uuid, # instance=board.instance_uuid) @@ -2245,25 +2245,45 @@ class ConductorManager(periodic_task.PeriodicTasks): # INSPECTIONFAIL -> MANAGEABLE # DEPLOYFAIL -> DELETING # ZAPFAIL -> MANAGEABLE (in the future) - ''' - valid_states = (states.AVAILABLE, states.NOSTATE, - states.MANAGEABLE) - if board.provision_state not in valid_states: - msg = (_('Can not delete board "%(board)s" while it is in ' - 'provision state "%(state)s". Valid provision states ' - 'to perform deletion are: "%(valid_states)s"') % - {'board': board.uuid, 'state': board.provision_state, - 'valid_states': valid_states}) - raise exception.InvalidState(msg) - if board.console_enabled: - try: - task.driver.console.stop_console(task) - except Exception as err: - LOG.error(_LE('Failed to stop console while deleting ' - 'the board %(board)s: %(err)s.'), - {'board': board.uuid, 'err': err}) - board.destroy() - LOG.info(_LI('Successfully deleted board %(board)s.'), - {'board': board.uuid}) - ''' + ''' + valid_states = (states.AVAILABLE, states.NOSTATE, + states.MANAGEABLE) + if board.provision_state not in valid_states: + msg = (_('Can not delete board "%(board)s" while it is in ' + 'provision state "%(state)s". Valid provision states ' + 'to perform deletion are: "%(valid_states)s"') % + {'board': board.uuid, 'state': board.provision_state, + 'valid_states': valid_states}) + raise exception.InvalidState(msg) + if board.console_enabled: + try: + task.driver.console.stop_console(task) + except Exception as err: + LOG.error(_LE('Failed to stop console while deleting ' + 'the board %(board)s: %(err)s.'), + {'board': board.uuid, 'err': err}) + board.destroy() + LOG.info(_LI('Successfully deleted board %(board)s.'), + {'board': board.uuid}) + ''' + + def iter_boards(self, fields=None, **kwargs): + """Iterate over boards mapped to this conductor. + Requests board set from and filters out boards that are not + mapped to this conductor. + + Yields tuples (board_uuid, driver, ...) where ... is derived from + fields argument, e.g.: fields=None means yielding ('uuid', 'driver'), + fields=['foo'] means yielding ('uuid', 'driver', 'foo'). + + :param fields: list of fields to fetch in addition to uuid and driver + :param kwargs: additional arguments to pass to dbapi when looking for + boards + :return: generator yielding tuples of requested fields + """ + columns = ['uuid',] + list(fields or ()) + board_list = self.dbapi.get_boardinfo_list(columns=columns, **kwargs) + for result in board_list: + if self._mapped_to_this_conductor(*result[:2]): + yield result diff --git a/iotronic/conductor/rpcapi.py b/iotronic/conductor/rpcapi.py index 42a7f72..0ff61d4 100644 --- a/iotronic/conductor/rpcapi.py +++ b/iotronic/conductor/rpcapi.py @@ -29,6 +29,9 @@ from iotronic.common import rpc from iotronic.conductor import manager from iotronic.objects import base as objects_base +from oslo_log import log as logging +LOG = logging.getLogger('object') + class ConductorAPI(object): """Client side of the conductor RPC API. diff --git a/iotronic/db/api.py b/iotronic/db/api.py index 9af30a3..e8b46ae 100644 --- a/iotronic/db/api.py +++ b/iotronic/db/api.py @@ -485,4 +485,58 @@ class Connection(object): 'extra': { ... }, } :returns: A board. + """ + + @abc.abstractmethod + def get_boardinfo_list(self, columns=None, filters=None, limit=None, + marker=None, sort_key=None, sort_dir=None): + """Get specific columns for matching boards. + + Return a list of the specified columns for all boards that match the + specified filters. + + :param columns: List of column names to return. + Defaults to 'id' column when columns == None. + :param filters: Filters to apply. Defaults to None. + + :associated: True | False + :reserved: True | False + :maintenance: True | False + :chassis_uuid: uuid of chassis + :driver: driver's name + :provision_state: provision state of board + :provisioned_before: + boards with provision_updated_at field before this + interval in seconds + :param limit: Maximum number of boards to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + :returns: A list of tuples of the specified columns. + """ + + @abc.abstractmethod + def get_board_list(self, filters=None, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of boards. + + :param filters: Filters to apply. Defaults to None. + + :associated: True | False + :reserved: True | False + :maintenance: True | False + :chassis_uuid: uuid of chassis + :driver: driver's name + :provision_state: provision state of board + :provisioned_before: + boards with provision_updated_at field before this + interval in seconds + :param limit: Maximum number of boards to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) """ \ No newline at end of file diff --git a/iotronic/db/sqlalchemy/api.py b/iotronic/db/sqlalchemy/api.py index f557aad..39c76a8 100644 --- a/iotronic/db/sqlalchemy/api.py +++ b/iotronic/db/sqlalchemy/api.py @@ -738,4 +738,25 @@ class Connection(api.Connection): instance_uuid=values['instance_uuid'], board=values['uuid']) raise exception.BoardAlreadyExists(uuid=values['uuid']) - return board \ No newline at end of file + return board + + def get_boardinfo_list(self, columns=None, filters=None, limit=None, + marker=None, sort_key=None, sort_dir=None): + # list-ify columns default values because it is bad form + # to include a mutable list in function definitions. + if columns is None: + columns = [models.Board.id] + else: + columns = [getattr(models.Board, c) for c in columns] + + query = model_query(*columns, base_model=models.Board) + query = self._add_boards_filters(query, filters) + return _paginate_query(models.Board, limit, marker, + sort_key, sort_dir, query) + + def get_board_list(self, filters=None, limit=None, marker=None, + sort_key=None, sort_dir=None): + query = model_query(models.Board) + query = self._add_boards_filters(query, filters) + return _paginate_query(models.Board, limit, marker, + sort_key, sort_dir, query) \ No newline at end of file diff --git a/iotronic/db/sqlalchemy/models.py b/iotronic/db/sqlalchemy/models.py index b270168..6095713 100644 --- a/iotronic/db/sqlalchemy/models.py +++ b/iotronic/db/sqlalchemy/models.py @@ -224,11 +224,7 @@ class Board(Base): ''' id = Column(Integer, primary_key=True) uuid = Column(String(36)) - # NOTE(deva): we store instance_uuid directly on the node so that we can - # filter on it more efficiently, even though it is - # user-settable, and would otherwise be in node.properties. - uuid = Column(String(36), nullable=True) - name = Column(String(255), nullable=True) - status = Column(String(10), nullable=True) - reservation = Column(String(255), nullable=True) + code = Column(String(25)) + status = Column(String(15), nullable=True) + #reservation = Column(String(255), nullable=True) diff --git a/iotronic/objects/board.py b/iotronic/objects/board.py index 61c7e0c..79e69ce 100644 --- a/iotronic/objects/board.py +++ b/iotronic/objects/board.py @@ -31,10 +31,9 @@ class Board(base.IotronicObject): fields = { 'id': int, 'uuid': obj_utils.str_or_none, - 'name': obj_utils.str_or_none, + 'code': obj_utils.str_or_none, 'status': obj_utils.str_or_none, - 'reservation': obj_utils.str_or_none, - + #'reservation': obj_utils.str_or_none, } @staticmethod diff --git a/utils/dump.sql b/utils/dump.sql index af5fe08..b0b13ff 100644 --- a/utils/dump.sql +++ b/utils/dump.sql @@ -15,8 +15,8 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `iotronic` /*!40100 DEFAULT CHARACTER SET utf8 */; - +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `iotronic` /*!40100 DEFAULT CHARACTER SET utf8 */; + USE `iotronic`; -- @@ -31,9 +31,8 @@ CREATE TABLE `boards` ( `updated_at` datetime DEFAULT NULL, `id` int(11) NOT NULL AUTO_INCREMENT, `uuid` varchar(36) NOT NULL, - `name` varchar(50) DEFAULT NULL, - `status` varchar(10) DEFAULT NULL, - `reservation` varchar(255) DEFAULT NULL, + `code` varchar(25) DEFAULT NULL, + `status` varchar(15) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uuid` (`uuid`) ) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8;