ironic/ironic/tests/manager/test_task_manager.py
Devananda van der Veen 59d5bea14a Restructuring driver API and inheritance.
Based on discussions during and after the Ironic team meeting on June
03, regarding support for substantially different driver work flows,
this is a re-working of the internal driver API.

tl;dr: The strict separation of "control" and "deploy" driver was an
       artefact of the ipmi + pxe implementation used in nova-baremetal,
       and does not map on to all drivers. Furthermore, the prior
       implementation did not accurately represent the separation of
       "core", "standard", and "vendor-specific" driver functionality.

These changes impact the v1 API structure, but since that is largely not
implemented yet, this change does not attempt to affect the public API
itself.

Highlights:
- No more deploy + control driver; nodes have one and only one driver.
  This drops the deploy_driver and deploy_info parameters,
  and renames control_driver -> driver, and control_info -> driver_info.
- Interfaces for core, standard, and vendor functionality now clearly
  defined in the driver API.
- Improve Fake driver to demonstrate use of interfaces.
- Convert IPMI and SSH driver classes into interfaces, and move to
  drivers/modules/ directory.
- Stub for the pxe interfaces.
- Stub implementations of pxe+ipmi and pxe+ssh drivers.
- driver_info field uses more standard names, but requires
  driver-specific data to be in a nested object. Examples in
  tests/db/utils.py as before.

A separate doc change will follow this to update the API v1 spec.

Also includes some cosmetic cleanup of test_ssh.py and test_ipmi.py.

Change-Id: I057ede8e07b1b57010e81ef58415debe0ba8b934
2013-06-11 17:12:21 -07:00

162 lines
5.7 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf-8
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Tests for :class:`ironic.manager.task_manager`."""
from testtools import matchers
from ironic.common import exception
from ironic.db import api as dbapi
from ironic.manager import task_manager
from ironic.openstack.common import uuidutils
from ironic.tests.db import base
from ironic.tests.db import utils
from ironic.tests.manager import utils as mgr_utils
def create_fake_node(i):
dbh = dbapi.get_instance()
node = utils.get_test_node(id=i,
uuid=uuidutils.generate_uuid(),
control_driver='fake',
deploy_driver='fake')
dbh.create_node(node)
return node['uuid']
def ContainsUUIDs(uuids):
def _task_uuids(task):
return [r.node.uuid for r in task.resources]
return matchers.AfterPreprocessing(_task_uuids,
matchers.Equals(uuids))
class TaskManagerTestCase(base.DbTestCase):
def setUp(self):
super(TaskManagerTestCase, self).setUp()
self.dbapi = dbapi.get_instance()
self.driver = mgr_utils.get_mocked_node_manager()
self.uuids = [create_fake_node(i) for i in xrange(1, 6)]
self.uuids.sort()
def test_get_one_node(self):
uuids = [self.uuids[0]]
self.config(host='test-host')
with task_manager.acquire(uuids) as task:
node = task.resources[0].node
self.assertEqual(uuids[0], node.uuid)
self.assertEqual('test-host', node.reservation)
def test_get_many_nodes(self):
uuids = self.uuids[1:3]
self.config(host='test-host')
with task_manager.acquire(uuids) as task:
self.assertThat(task, ContainsUUIDs(uuids))
for node in [r.node for r in task.resources]:
self.assertEqual('test-host', node.reservation)
def test_get_nodes_nested(self):
uuids = self.uuids[0:2]
more_uuids = self.uuids[3:4]
with task_manager.acquire(uuids) as task:
self.assertThat(task, ContainsUUIDs(uuids))
with task_manager.acquire(more_uuids) as another_task:
self.assertThat(another_task, ContainsUUIDs(more_uuids))
def test_get_locked_node(self):
uuids = self.uuids[0:2]
def _lock_again(u):
with task_manager.acquire(u):
raise exception.IronicException("Acquired lock twice.")
with task_manager.acquire(uuids) as task:
self.assertThat(task, ContainsUUIDs(uuids))
self.assertRaises(exception.NodeLocked,
_lock_again,
uuids)
def test_get_shared_lock(self):
uuids = self.uuids[0:2]
# confirm we can elevate from shared -> exclusive
with task_manager.acquire(uuids, shared=True) as task:
self.assertThat(task, ContainsUUIDs(uuids))
with task_manager.acquire(uuids, shared=False) as inner_task:
self.assertThat(inner_task, ContainsUUIDs(uuids))
# confirm someone else can still get a shared lock
with task_manager.acquire(uuids, shared=False) as task:
self.assertThat(task, ContainsUUIDs(uuids))
with task_manager.acquire(uuids, shared=True) as inner_task:
self.assertThat(inner_task, ContainsUUIDs(uuids))
class ExclusiveLockDecoratorTestCase(base.DbTestCase):
def setUp(self):
super(ExclusiveLockDecoratorTestCase, self).setUp()
self.dbapi = dbapi.get_instance()
self.driver = mgr_utils.get_mocked_node_manager()
self.uuids = [create_fake_node(123)]
def test_require_exclusive_lock(self):
@task_manager.require_exclusive_lock
def do_state_change(task):
for r in task.resources:
task.dbapi.update_node(r.node.uuid,
{'task_state': 'test-state'})
with task_manager.acquire(self.uuids, shared=True) as task:
self.assertRaises(exception.ExclusiveLockRequired,
do_state_change,
task)
with task_manager.acquire(self.uuids, shared=False) as task:
do_state_change(task)
for uuid in self.uuids:
res = self.dbapi.get_node(uuid)
self.assertEqual('test-state', res.task_state)
@task_manager.require_exclusive_lock
def _do_state_change(self, task):
for r in task.resources:
task.dbapi.update_node(r.node.uuid,
{'task_state': 'test-state'})
def test_require_exclusive_lock_on_object(self):
with task_manager.acquire(self.uuids, shared=True) as task:
self.assertRaises(exception.ExclusiveLockRequired,
self._do_state_change,
task)
with task_manager.acquire(self.uuids, shared=False) as task:
self._do_state_change(task)
for uuid in self.uuids:
res = self.dbapi.get_node(uuid)
self.assertEqual('test-state', res.task_state)