¡@

Home 

OpenStack Study: test_hds.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright (c) 2013 Hitachi Data Systems, Inc.

# Copyright (c) 2013 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.

#

"""

Self test for Hitachi Unified Storage (HUS) platform.

"""

import mox

import os

import tempfile

from cinder import test

from cinder.volume import configuration as conf

from cinder.volume.drivers.hds import hds

CONF = """

172.17.44.16

172.17.44.17

system

manager

default

172.17.39.132

9

silver

172.17.39.133

9

gold

172.17.39.134

9

platinum

172.17.39.135

9

9

3300

"""

**** CubicPower OpenStack Study ****

class SimulatedHusBackend:

"""Simulation Back end. Talks to HUS."""

alloc_lun = [] # allocated LUs

connections = [] # iSCSI connections

init_index = 0 # initiator index

target_index = 0 # target index

hlun = 0 # hlun index

out = ''

**** CubicPower OpenStack Study ****

    def __init__(self):

        self.start_lun = 0

**** CubicPower OpenStack Study ****

    def get_version(self, cmd, ver, ip0, ip1, user, pw):

        out = ("Array_ID: 92210013 (HUS130) version: 0920/B-S  LU: 4096"

               "  RG: 75  RG_LU: 1024  Utility_version: 1.0.0")

        return out

**** CubicPower OpenStack Study ****

    def get_iscsi_info(self, cmd, ver, ip0, ip1, user, pw):

        out = """CTL: 0 Port: 4 IP: 172.17.39.132 Port: 3260 Link: Up

                 CTL: 0 Port: 5 IP: 172.17.39.133 Port: 3260 Link: Up

                 CTL: 1 Port: 4 IP: 172.17.39.134 Port: 3260 Link: Up

                 CTL: 1 Port: 5 IP: 172.17.39.135 Port: 3260 Link: Up"""

        return out

**** CubicPower OpenStack Study ****

    def get_hdp_info(self, cmd, ver, ip0, ip1, user, pw):

        out = """HDP: 2  272384 MB    33792 MB  12 %  LUs:   70  Normal  Normal

              HDP: 9  546816 MB    73728 MB  13 %  LUs:  194  Normal  Normal"""

        return out

**** CubicPower OpenStack Study ****

    def create_lu(self, cmd, ver, ip0, ip1, user, pw, id, hdp, start,

                  end, size):

        if self.start_lun < int(start):  # initialize first time

            self.start_lun = int(start)

        out = ("LUN: %d HDP: 9 size: %s MB, is successfully created" %

               (self.start_lun, size))

        self.alloc_lun.append(str(self.start_lun))

        self.start_lun += 1

        return out

**** CubicPower OpenStack Study ****

    def extend_vol(self, cmd, ver, ip0, ip1, user, pw, id, lu, size):

        out = ("LUN: %s successfully extended to %s MB" % (lu, size))

        SimulatedHusBackend.out = out

        return out

**** CubicPower OpenStack Study ****

    def delete_lu(self, cmd, ver, ip0, ip1, user, pw, id, lun):

        out = ""

        if lun in self.alloc_lun:

            out = "LUN: %s is successfully deleted" % (lun)

            self.alloc_lun.remove(lun)

        return out

**** CubicPower OpenStack Study ****

    def create_dup(self, cmd, ver, ip0, ip1, user, pw, id, src_lun,

                   hdp, start, end, size):

        out = ("LUN: %s HDP: 9 size: %s MB, is successfully created" %

               (self.start_lun, size))

        self.alloc_lun.append(str(self.start_lun))

        self.start_lun += 1

        return out

**** CubicPower OpenStack Study ****

    def add_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port,

                       iqn, initiator):

        conn = (self.hlun, lun, initiator, self.init_index, iqn,

                self.target_index, ctl, port)

        out = ("H-LUN: %d mapped. LUN: %s, iSCSI Initiator: %s @ index: %d, \

                and Target: %s @ index %d is successfully paired  @ CTL: %s, \

                Port: %s" % conn)

        self.init_index += 1

        self.target_index += 1

        self.hlun += 1

        SimulatedHusBackend.connections.append(conn)

        return out

**** CubicPower OpenStack Study ****

    def del_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port,

                       iqn, initiator):

        conn = ()

        for connection in SimulatedHusBackend.connections:

            if (connection[1] == lun):

                conn = connection

                SimulatedHusBackend.connections.remove(connection)

        if conn is None:

            return

        (hlun, lun, initiator, init_index, iqn, target_index, ctl, port) = conn

        detail = (hlun, iqn)

        out = ("H-LUN: %d successfully deleted from target %s" % detail)

        return out

# The following information is passed on to tests, when creating a volume

_VOLUME = {'volume_id': '1234567890', 'size': 128,

           'volume_type': None, 'provider_location': None, 'id': 'abcdefg'}

**** CubicPower OpenStack Study ****

class HUSiSCSIDriverTest(test.TestCase):

"""Test HUS iSCSI volume driver."""

**** CubicPower OpenStack Study ****

    def __init__(self, *args, **kwargs):

        super(HUSiSCSIDriverTest, self).__init__(*args, **kwargs)

**** CubicPower OpenStack Study ****

    def setUp(self):

        super(HUSiSCSIDriverTest, self).setUp()

        (handle, self.config_file) = tempfile.mkstemp('.xml')

        os.write(handle, CONF)

        os.close(handle)

        SimulatedHusBackend.alloc_lun = []

        SimulatedHusBackend.connections = []

        SimulatedHusBackend.out = ''

        self.mox = mox.Mox()

        self.mox.StubOutWithMock(hds, 'factory_bend')

        hds.factory_bend().AndReturn(SimulatedHusBackend())

        self.mox.ReplayAll()

        self.configuration = mox.MockObject(conf.Configuration)

        self.configuration.hds_cinder_config_file = self.config_file

        self.driver = hds.HUSDriver(configuration=self.configuration)

**** CubicPower OpenStack Study ****

    def tearDown(self):

        os.remove(self.config_file)

        self.mox.UnsetStubs()

        super(HUSiSCSIDriverTest, self).tearDown()

**** CubicPower OpenStack Study ****

    def test_get_volume_stats(self):

        stats = self.driver.get_volume_stats(True)

        self.assertEqual(stats["vendor_name"], "HDS")

        self.assertEqual(stats["storage_protocol"], "iSCSI")

        self.assertGreater(stats["total_capacity_gb"], 0)

**** CubicPower OpenStack Study ****

    def test_create_volume(self):

        loc = self.driver.create_volume(_VOLUME)

        self.assertIsNotNone(loc)

        vol = _VOLUME.copy()

        vol['provider_location'] = loc['provider_location']

        self.assertIsNotNone(loc['provider_location'])

        return vol

**** CubicPower OpenStack Study ****

    def test_delete_volume(self):

        """Delete a volume (test).

        Note: this API call should not expect any exception:

        This driver will silently accept a delete request, because

        the DB can be out of sync, and Cinder manager will keep trying

        to delete, even though the volume has been wiped out of the

        Array. We don't want to have a dangling volume entry in the

        customer dashboard.

        """

        vol = self.test_create_volume()

        self.assertTrue(SimulatedHusBackend.alloc_lun)

        num_luns_before = len(SimulatedHusBackend.alloc_lun)

        self.driver.delete_volume(vol)

        num_luns_after = len(SimulatedHusBackend.alloc_lun)

        self.assertGreater(num_luns_before, num_luns_after)

**** CubicPower OpenStack Study ****

    def test_extend_volume(self):

        vol = self.test_create_volume()

        new_size = _VOLUME['size'] * 2

        self.driver.extend_volume(vol, new_size)

        self.assertTrue(str(new_size * 1024) in

                        SimulatedHusBackend.out)

**** CubicPower OpenStack Study ****

    def test_create_snapshot(self):

        vol = self.test_create_volume()

        self.mox.StubOutWithMock(self.driver, '_id_to_vol')

        self.driver._id_to_vol(vol['volume_id']).AndReturn(vol)

        self.mox.ReplayAll()

        svol = vol.copy()

        svol['volume_size'] = svol['size']

        loc = self.driver.create_snapshot(svol)

        self.assertIsNotNone(loc)

        svol['provider_location'] = loc['provider_location']

        return svol

**** CubicPower OpenStack Study ****

    def test_create_clone(self):

        vol = self.test_create_volume()

        self.mox.StubOutWithMock(self.driver, '_id_to_vol')

        self.driver._id_to_vol(vol['volume_id']).AndReturn(vol)

        self.mox.ReplayAll()

        svol = vol.copy()

        svol['volume_size'] = svol['size']

        loc = self.driver.create_snapshot(svol)

        self.assertIsNotNone(loc)

        svol['provider_location'] = loc['provider_location']

        return svol

**** CubicPower OpenStack Study ****

    def test_delete_snapshot(self):

        """Delete a snapshot (test).

        Note: this API call should not expect any exception:

        This driver will silently accept a delete request, because

        the DB can be out of sync, and Cinder manager will keep trying

        to delete, even though the snapshot has been wiped out of the

        Array. We don't want to have a dangling snapshot entry in the

        customer dashboard.

        """

        svol = self.test_create_snapshot()

        num_luns_before = len(SimulatedHusBackend.alloc_lun)

        self.driver.delete_snapshot(svol)

        num_luns_after = len(SimulatedHusBackend.alloc_lun)

        self.assertGreater(num_luns_before, num_luns_after)

**** CubicPower OpenStack Study ****

    def test_create_volume_from_snapshot(self):

        svol = self.test_create_snapshot()

        vol = self.driver.create_volume_from_snapshot(_VOLUME, svol)

        self.assertIsNotNone(vol)

        return vol

**** CubicPower OpenStack Study ****

    def test_initialize_connection(self):

        connector = {}

        connector['initiator'] = 'iqn.1993-08.org.debian:01:11f90746eb2'

        connector['host'] = 'dut_1.lab.hds.com'

        vol = self.test_create_volume()

        self.mox.StubOutWithMock(self.driver, '_update_vol_location')

        conn = self.driver.initialize_connection(vol, connector)

        self.assertIn('hitachi', conn['data']['target_iqn'])

        self.assertIn('3260', conn['data']['target_portal'])

        vol['provider_location'] = conn['data']['provider_location']

        return (vol, connector)

**** CubicPower OpenStack Study ****

    def test_terminate_connection(self):

        """Terminate a connection (test).

        Note: this API call should not expect any exception:

        This driver will silently accept a terminate_connection request

        because an error/exception return will only jeopardize the

        connection tear down at a host.

        """

        (vol, conn) = self.test_initialize_connection()

        num_conn_before = len(SimulatedHusBackend.connections)

        self.driver.terminate_connection(vol, conn)

        num_conn_after = len(SimulatedHusBackend.connections)

        self.assertGreater(num_conn_before, num_conn_after)