Skip to content

Commit

Permalink
Adding 'host' info to volume-compute connection information.
Browse files Browse the repository at this point in the history
Added a new key 'host' for the initialize/terminate volume connection
information. Updated the HpSanISCSIDriver to use teh initialize and
terminate methods. Added missing unit tests for the HpSanISCSIDriver.
Fixes bug 992729.

Change-Id: I09fad6b5328cbfb860ab2c7ae5d206010f3dd45d
  • Loading branch information
rnirmal committed May 2, 2012
1 parent 994bba6 commit d14ac4b
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 61 deletions.
8 changes: 6 additions & 2 deletions nova/tests/test_libvirt.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ def get_all_block_devices(self):
self.fake_conn = FakeLibvirtConnection()
self.connr = {
'ip': '127.0.0.1',
'initiator': 'fake_initiator'
'initiator': 'fake_initiator',
'host': 'fake_host'
}

def test_libvirt_iscsi_driver(self):
Expand Down Expand Up @@ -478,12 +479,15 @@ def create_service(self, **kwargs):
def test_get_connector(self):
initiator = 'fake.initiator.iqn'
ip = 'fakeip'
host = 'fakehost'
self.flags(my_ip=ip)
self.flags(host=host)

conn = connection.LibvirtConnection(True)
expected = {
'ip': ip,
'initiator': initiator
'initiator': initiator,
'host': host
}
volume = {
'id': 'fake'
Expand Down
1 change: 1 addition & 0 deletions nova/tests/test_virt_drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ def test_get_volume_connector(self):
result = self.connection.get_volume_connector({'id': 'fake'})
self.assertTrue('ip' in result)
self.assertTrue('initiator' in result)
self.assertTrue('host' in result)

@catch_notimplementederror
def test_attach_detach_volume(self):
Expand Down
13 changes: 13 additions & 0 deletions nova/tests/volume/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2012 OpenStack LLC
#
# 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.
212 changes: 212 additions & 0 deletions nova/tests/volume/test_HpSanISCSIDriver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Copyright 2012 OpenStack LLC
#
# 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.
from nova import exception
from nova import log as logging
from nova.volume import san
from nova import test

LOG = logging.getLogger(__name__)


class HpSanISCSITestCase(test.TestCase):

def setUp(self):
super(HpSanISCSITestCase, self).setUp()
self.stubs.Set(san.HpSanISCSIDriver, "_cliq_run",
self._fake_cliq_run)
self.stubs.Set(san.HpSanISCSIDriver, "_get_iscsi_properties",
self._fake_get_iscsi_properties)
self.driver = san.HpSanISCSIDriver()
self.volume_name = "fakevolume"
self.connector = {'ip': '10.0.0.2',
'initiator': 'iqn.1993-08.org.debian:01:222',
'host': 'fakehost'}
self.properties = {'target_discoverd': True,
'target_portal': '10.0.1.6:3260',
'target_iqn':
'iqn.2003-10.com.lefthandnetworks:group01:25366:fakev',
'volume_id': 1}

def tearDown(self):
super(HpSanISCSITestCase, self).tearDown()

def _fake_get_iscsi_properties(self, volume):
return self.properties

def _fake_cliq_run(self, verb, cliq_args):
"""Return fake results for the various methods."""

def create_volume(cliq_args):
"""
input = "createVolume description="fake description"
clusterName=Cluster01 volumeName=fakevolume
thinProvision=0 output=XML size=1GB"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="181" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['thinProvision'], '1')
self.assertEqual(cliq_args['size'], '1GB')
return output, None

def delete_volume(cliq_args):
"""
input = "deleteVolume volumeName=fakevolume prompt=false
output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="164" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['prompt'], 'false')
return output, None

def assign_volume(cliq_args):
"""
input = "assignVolumeToServer volumeName=fakevolume
serverName=fakehost
output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="174" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['serverName'], self.connector['host'])
return output, None

def unassign_volume(cliq_args):
"""
input = "unassignVolumeToServer volumeName=fakevolume
serverName=fakehost output=XML
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="205" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['serverName'], self.connector['host'])
return output, None

def get_cluster_info(cliq_args):
"""
input = "getClusterInfo clusterName=Cluster01 searchDepth=1
verbose=0 output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded." name="CliqSuccess"
processingTime="1164" result="0">
<cluster blockSize="1024" description=""
maxVolumeSizeReplication1="622957690"
maxVolumeSizeReplication2="311480287"
minVolumeSize="262144" name="Cluster01"
pageSize="262144" spaceTotal="633697992"
storageNodeCount="2" unprovisionedSpace="622960574"
useVip="true">
<nsm ipAddress="10.0.1.7" name="111-vsa"/>
<nsm ipAddress="10.0.1.8" name="112-vsa"/>
<vip ipAddress="10.0.1.6" subnetMask="255.255.255.0"/>
</cluster></response></gauche>"""
return output, None

def get_volume_info(cliq_args):
"""
input = "getVolumeInfo volumeName=fakevolume output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded." name="CliqSuccess"
processingTime="87" result="0">
<volume autogrowPages="4" availability="online"
blockSize="1024" bytesWritten="0" checkSum="false"
clusterName="Cluster01" created="2011-02-08T19:56:53Z"
deleting="false" description="" groupName="Group01"
initialQuota="536870912" isPrimary="true"
iscsiIqn="iqn.2003-10.com.lefthandnetworks:group01:25366:fakev"
maxSize="6865387257856" md5="9fa5c8b2cca54b2948a63d833097e1ca"
minReplication="1" name="vol-b" parity="0" replication="2"
reserveQuota="536870912" scratchQuota="4194304"
serialNumber="9fa5c8b2cca54b2948a63d8"
size="1073741824" stridePages="32" thinProvision="true">
<status description="OK" value="2"/>
<permission access="rw" authGroup="api-1"
chapName="chapusername" chapRequired="true"
id="25369" initiatorSecret="" iqn=""
iscsiEnabled="true" loadBalance="true"
targetSecret="supersecret"/>
</volume></response></gauche>"""
return output, None

def test_error(cliq_args):
output = """<gauche version="1.0">
<response description="Volume '134234' not found."
name="CliqVolumeNotFound" processingTime="1083"
result="8000100c"/>
</gauche>"""
return output, None

self.assertEqual(cliq_args['output'], 'XML')
try:
verbs = {'createVolume': create_volume,
'deleteVolume': delete_volume,
'assignVolumeToServer': assign_volume,
'unassignVolumeToServer': unassign_volume,
'getClusterInfo': get_cluster_info,
'getVolumeInfo': get_volume_info,
'testError': test_error}
except KeyError:
raise NotImplementedError()

return verbs[verb](cliq_args)

def test_create_volume(self):
volume = {'name': self.volume_name, 'size': 1}
model_update = self.driver.create_volume(volume)
expected_iqn = "iqn.2003-10.com.lefthandnetworks:group01:25366:fakev"
expected_location = "10.0.1.6:3260,1 %s" % expected_iqn
self.assertEqual(model_update['provider_location'], expected_location)

def test_delete_volume(self):
volume = {'name': self.volume_name}
self.driver.delete_volume(volume)

def test_initialize_connection(self):
volume = {'name': self.volume_name}
result = self.driver.initialize_connection(volume, self.connector)
self.assertEqual(result['driver_volume_type'], 'iscsi')
self.assertDictMatch(result['data'], self.properties)

def test_terminate_connection(self):
volume = {'name': self.volume_name}
self.driver.terminate_connection(volume, self.connector)

def test_create_snapshot(self):
try:
self.driver.create_snapshot("")
except NotImplementedError:
pass

def test_create_volume_from_snapshot(self):
try:
self.driver.create_volume_from_snapshot("", "")
except NotImplementedError:
pass

def test_cliq_error(self):
try:
self.driver._cliq_run_xml("testError", {})
except exception.Error:
pass
5 changes: 3 additions & 2 deletions nova/virt/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,12 +676,13 @@ def get_volume_connector(self, instance):
"""Get connector information for the instance for attaching to volumes.
Connector information is a dictionary representing the ip of the
machine that will be making the connection and and the name of the
iscsi initiator as follows::
machine that will be making the connection, the name of the iscsi
initiator and the hostname of the machine as follows::
{
'ip': ip,
'initiator': initiator,
'host': hostname
}
"""
raise NotImplementedError()
2 changes: 1 addition & 1 deletion nova/virt/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,4 @@ def get_disk_available_least(self):
pass

def get_volume_connector(self, instance):
return {'ip': '127.0.0.1', 'initiator': 'fake'}
return {'ip': '127.0.0.1', 'initiator': 'fake', 'host': 'fakehost'}
1 change: 1 addition & 0 deletions nova/virt/libvirt/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ def get_volume_connector(self, instance):
return {
'ip': FLAGS.my_ip,
'initiator': self._initiator,
'host': FLAGS.host
}

def _cleanup_resize(self, instance):
Expand Down
5 changes: 3 additions & 2 deletions nova/virt/vmwareapi_conn.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,11 @@ def get_console_output(self, instance):
def get_volume_connector(self, _instance):
"""Return volume connector information"""
# TODO(vish): When volume attaching is supported, return the
# proper initiator iqn.
# proper initiator iqn and host.
return {
'ip': FLAGS.vmwareapi_host_ip,
'initiator': None
'initiator': None,
'host': None
}

def attach_volume(self, connection_info, instance_name, mountpoint):
Expand Down
11 changes: 7 additions & 4 deletions nova/virt/xenapi/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def __init__(self, url, user, pw):
self._host = host.Host(self._session)
self._vmops = vmops.VMOps(self._session)
self._initiator = None
self._hypervisor_hostname = None
self._pool = pool.ResourcePool(self._session)

@property
Expand Down Expand Up @@ -336,17 +337,19 @@ def get_vnc_console(self, instance):

def get_volume_connector(self, instance):
"""Return volume connector information"""
if not self._initiator:
if not self._initiator or not self._hypervisor_hostname:
stats = self.get_host_stats(refresh=True)
try:
self._initiator = stats['host_other-config']['iscsi_iqn']
except (TypeError, KeyError):
LOG.warn(_('Could not determine iscsi initiator name'),
self._hypervisor_hostname = stats['host_hostname']
except (TypeError, KeyError) as err:
LOG.warn(_('Could not determine key: %s') % err,
instance=instance)
self._initiator = None
return {
'ip': self.get_host_ip_addr(),
'initiator': self._initiator
'initiator': self._initiator,
'host': self._hypervisor_hostname
}

@staticmethod
Expand Down

0 comments on commit d14ac4b

Please sign in to comment.