ironic/ironic/tests/test_neutron.py

294 lines
14 KiB
Python

#
# Copyright 2014 OpenStack Foundation
# 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.
import mock
from neutronclient.common import exceptions as neutron_client_exc
from neutronclient.v2_0 import client
from oslo.config import cfg
from ironic.common import exception
from ironic.common import neutron
from ironic.common import pxe_utils
from ironic.common import utils
from ironic.conductor import task_manager
from ironic.db import api as dbapi
from ironic.openstack.common import context
from ironic.tests import base
from ironic.tests.conductor import utils as mgr_utils
from ironic.tests.objects import utils as object_utils
CONF = cfg.CONF
class TestNeutron(base.TestCase):
def setUp(self):
super(TestNeutron, self).setUp()
mgr_utils.mock_the_extension_manager(driver='fake')
self.config(enabled_drivers=['fake'])
self.config(url='test-url',
url_timeout=30,
group='neutron')
self.config(insecure=False,
certfile='test-file',
admin_user='test-admin-user',
admin_tenant_name='test-admin-tenant',
admin_password='test-admin-password',
auth_uri='test-auth-uri',
group='keystone_authtoken')
self.dbapi = dbapi.get_instance()
self.context = context.get_admin_context()
self.node = object_utils.create_test_node(self.context)
def test_invalid_auth_strategy(self):
self.config(auth_strategy='wrong_config', group='neutron')
token = 'test-token-123'
my_context = context.RequestContext(user='test-user',
tenant='test-tenant',
auth_token=token)
self.assertRaises(exception.ConfigInvalid,
neutron.NeutronAPI,
my_context)
def test_create_with_token(self):
token = 'test-token-123'
my_context = context.RequestContext(user='test-user',
tenant='test-tenant',
auth_token=token)
expected = {'timeout': 30,
'insecure': False,
'ca_cert': 'test-file',
'token': token,
'endpoint_url': 'test-url',
'auth_strategy': None}
with mock.patch.object(client.Client, "__init__") as mock_client_init:
mock_client_init.return_value = None
neutron.NeutronAPI(my_context)
mock_client_init.assert_called_once_with(**expected)
def test_create_without_token(self):
my_context = context.RequestContext(user='test-user',
tenant='test-tenant')
expected = {'timeout': 30,
'insecure': False,
'ca_cert': 'test-file',
'endpoint_url': 'test-url',
'username': 'test-admin-user',
'tenant_name': 'test-admin-tenant',
'password': 'test-admin-password',
'auth_url': 'test-auth-uri'}
with mock.patch.object(client.Client, "__init__") as mock_client_init:
mock_client_init.return_value = None
neutron.NeutronAPI(my_context)
mock_client_init.assert_called_once_with(**expected)
def test_create_noauth(self):
self.config(auth_strategy='noauth', group='neutron')
my_context = context.RequestContext()
expected = {'ca_cert': 'test-file',
'insecure': False,
'endpoint_url': 'test-url',
'timeout': 30,
'auth_strategy': 'noauth'}
with mock.patch.object(client.Client, "__init__") as mock_client_init:
mock_client_init.return_value = None
neutron.NeutronAPI(my_context)
mock_client_init.assert_called_once_with(**expected)
def test_neutron_port_update(self):
opts = [{'opt_name': 'bootfile-name',
'opt_value': 'pxelinux.0'},
{'opt_name': 'tftp-server',
'opt_value': '1.1.1.1'},
{'opt_name': 'server-ip-address',
'opt_value': '1.1.1.1'}]
port_id = 'fake-port-id'
expected = {'port': {'extra_dhcp_opts': opts}}
my_context = context.RequestContext(user='test-user',
tenant='test-tenant')
with mock.patch.object(client.Client, "__init__") as mock_client_init:
mock_client_init.return_value = None
api = neutron.NeutronAPI(my_context)
with mock.patch.object(client.Client,
"update_port") as mock_update_port:
mock_update_port.return_value = None
api.update_port_dhcp_opts(port_id, opts)
mock_update_port.assert_called_once_with(port_id, expected)
def test_neutron_port_update_with_execption(self):
opts = [{}]
port_id = 'fake-port-id'
my_context = context.RequestContext(user='test-user',
tenant='test-tenant')
with mock.patch.object(client.Client, "__init__") as mock_client_init:
mock_client_init.return_value = None
api = neutron.NeutronAPI(my_context)
with mock.patch.object(client.Client,
"update_port") as mock_update_port:
mock_update_port.side_effect = (
neutron_client_exc.NeutronClientException())
self.assertRaises(
exception.FailedToUpdateDHCPOptOnPort,
api.update_port_dhcp_opts,
port_id, opts)
@mock.patch.object(client.Client, 'update_port')
@mock.patch.object(client.Client, '__init__')
def test_neutron_address_update(self, mock_client_init, mock_update_port):
address = 'fe:54:00:77:07:d9'
port_id = 'fake-port-id'
expected = {'port': {'mac_address': address}}
my_context = context.RequestContext(user='test-user',
tenant='test-tenant')
mock_client_init.return_value = None
api = neutron.NeutronAPI(my_context)
mock_update_port.return_value = None
api.update_port_address(port_id, address)
mock_update_port.assert_called_once_with(port_id, expected)
@mock.patch.object(client.Client, 'update_port')
@mock.patch.object(client.Client, '__init__')
def test_neutron_address_update_with_exception(self, mock_client_init,
mock_update_port):
address = 'fe:54:00:77:07:d9'
port_id = 'fake-port-id'
my_context = context.RequestContext(user='test-user',
tenant='test-tenant')
mock_client_init.return_value = None
api = neutron.NeutronAPI(my_context)
mock_update_port.side_effect = (
neutron_client_exc.NeutronClientException())
self.assertRaises(exception.FailedToUpdateMacOnPort,
api.update_port_address, port_id, address)
def test_get_node_vif_ids_no_ports(self):
expected = {}
with task_manager.acquire(self.context, self.node.uuid) as task:
result = neutron.get_node_vif_ids(task)
self.assertEqual(expected, result)
def test__get_node_vif_ids_one_port(self):
port1 = object_utils.create_test_port(self.context,
node_id=self.node.id,
id=6, address='aa:bb:cc',
uuid=utils.generate_uuid(),
extra={'vif_port_id': 'test-vif-A'},
driver='fake')
expected = {port1.uuid: 'test-vif-A'}
with task_manager.acquire(self.context, self.node.uuid) as task:
result = neutron.get_node_vif_ids(task)
self.assertEqual(expected, result)
def test__get_node_vif_ids_two_ports(self):
port1 = object_utils.create_test_port(self.context,
node_id=self.node.id,
id=6,
address='aa:bb:cc',
uuid=utils.generate_uuid(),
extra={'vif_port_id': 'test-vif-A'},
driver='fake')
port2 = object_utils.create_test_port(self.context,
node_id=self.node.id,
id=7,
address='dd:ee:ff',
uuid=utils.generate_uuid(),
extra={'vif_port_id': 'test-vif-B'},
driver='fake')
expected = {port1.uuid: 'test-vif-A', port2.uuid: 'test-vif-B'}
with task_manager.acquire(self.context, self.node.uuid) as task:
result = neutron.get_node_vif_ids(task)
self.assertEqual(expected, result)
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
@mock.patch('ironic.common.neutron.get_node_vif_ids')
def test_update_neutron(self, mock_gnvi, mock_updo, mock_wait_neutron):
opts = pxe_utils.dhcp_options_for_instance()
mock_gnvi.return_value = {'port-uuid': 'vif-uuid'}
with task_manager.acquire(self.context,
self.node.uuid) as task:
neutron.update_neutron(task, self.node)
mock_updo.assertCalleOnceWith('vif-uuid', opts)
mock_wait_neutron.assert_called_once_with(task)
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
@mock.patch('ironic.common.neutron.NeutronAPI.__init__')
@mock.patch('ironic.common.neutron.get_node_vif_ids')
def test_update_neutron_no_vif_data(self, mock_gnvi, mock_init,
mock_wait_neutron):
mock_gnvi.return_value = {}
with task_manager.acquire(self.context,
self.node.uuid) as task:
neutron.update_neutron(task, self.node)
self.assertFalse(mock_init.called)
self.assertFalse(mock_wait_neutron.called)
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
@mock.patch('ironic.common.neutron.get_node_vif_ids')
def test_update_neutron_some_failures(self, mock_gnvi, mock_updo,
mock_wait_neutron):
# confirm update is called twice, one fails, but no exception raised
mock_gnvi.return_value = {'p1': 'v1', 'p2': 'v2'}
exc = exception.FailedToUpdateDHCPOptOnPort('fake exception')
mock_updo.side_effect = [None, exc]
with task_manager.acquire(self.context,
self.node.uuid) as task:
neutron.update_neutron(task, self.node)
self.assertEqual(2, mock_updo.call_count)
mock_wait_neutron.assert_called_once_with(task)
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
@mock.patch('ironic.common.neutron.get_node_vif_ids')
def test_update_neutron_fails(self, mock_gnvi, mock_updo,
mock_wait_neutron):
# confirm update is called twice, both fail, and exception is raised
mock_gnvi.return_value = {'p1': 'v1', 'p2': 'v2'}
exc = exception.FailedToUpdateDHCPOptOnPort('fake exception')
mock_updo.side_effect = [exc, exc]
with task_manager.acquire(self.context,
self.node.uuid) as task:
self.assertRaises(exception.FailedToUpdateDHCPOptOnPort,
neutron.update_neutron,
task, self.node)
self.assertEqual(2, mock_updo.call_count)
self.assertFalse(mock_wait_neutron.called)
def test__wait_for_neutron_update(self):
kw = {
'id': 190238451205398,
'uuid': utils.generate_uuid(),
'driver': 'fake_ssh'
}
node = object_utils.create_test_node(self.context, **kw)
mgr_utils.mock_the_extension_manager(driver="fake_ssh")
with task_manager.acquire(self.context, node.uuid) as task:
with mock.patch('time.sleep') as mock_sleep:
neutron._wait_for_neutron_update(task)
mock_sleep.assert_called_once_with(15)
def test__wait_for_neutron_update_no_sleep(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
with mock.patch('time.sleep') as mock_sleep:
neutron._wait_for_neutron_update(task)
self.assertFalse(mock_sleep.called)