Discussion:
[Libstoragemgmt-devel] [PATCH 0/6] TargetPort + fixes
Tony Asleson
2014-06-19 22:24:16 UTC
Permalink
Merged target port patch from Gris and patch to
support on NetApp.

Looking into nstor docs, but I haven't had any luck
getting anything to work at the moment.

Please review.

Regards,
Tony

Gris Ge (1):
Simulator Plugin: Add lsm.TargetPort support (v2)

Tony Asleson (5):
plugin_test.py: Make sure pool has some free space
ontap.py: Remove optional data references
tools/netapp/netapp.py: Update imports
ontap.py: Add TargetPort listing support
nstor.py: Remove references to missing constants

plugin/nstor/nstor.py | 5 ----
plugin/ontap/na.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
plugin/ontap/ontap.py | 40 ++++++++++++++++++++++++++----
plugin/sim/simarray.py | 56 ++++++++++++++++++++++++++++++++++++++++-
plugin/sim/simulator.py | 8 ++++++
test/plugin_test.py | 7 +++---
tools/netapp/netapp.py | 9 ++++---
7 files changed, 173 insertions(+), 18 deletions(-)
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:22 UTC
Permalink
Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/nstor/nstor.py | 5 -----
1 file changed, 5 deletions(-)

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index 4c23b03..3b835ea 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -289,11 +289,6 @@ class NexentaStor(INfs, IStorageAreaNetwork):
c.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
c.set(Capabilities.VOLUME_CHILD_DEPENDENCY)
c.set(Capabilities.VOLUME_CHILD_DEPENDENCY_RM)
- c.set(Capabilities.INITIATORS)
- c.set(Capabilities.INITIATORS_GRANTED_TO_VOLUME)
- c.set(Capabilities.VOLUME_INITIATOR_GRANT)
- c.set(Capabilities.VOLUME_INITIATOR_REVOKE)
- c.set(Capabilities.VOLUME_ACCESSIBLE_BY_INITIATOR)

#tasleson, not working at the moment for me.
#c.set(Capabilities.VOLUME_ISCSI_CHAP_AUTHENTICATION)
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:18 UTC
Permalink
Some test arrays have pools that have too little free space
to be usable.

Signed-off-by: Tony Asleson <***@redhat.com>
---
test/plugin_test.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/test/plugin_test.py b/test/plugin_test.py
index e76b184..865363e 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -253,7 +253,8 @@ class TestPlugin(unittest.TestCase):

def _get_pool_by_usage(self, system_id, element_type):
for p in self.pool_by_sys_id[system_id]:
- if p.element_type & element_type:
+ if p.element_type & element_type and \
+ p.free_space > mb_in_bytes(250):
return p
return None

@@ -313,7 +314,7 @@ class TestPlugin(unittest.TestCase):
lsm.Pool.ELEMENT_TYPE_VOLUME)

if p:
- vol_size = min(p.free_space / 10, mb_in_bytes(512))
+ vol_size = min(p.free_space / 5, mb_in_bytes(30))

vol = self.c.volume_create(p, rs('volume'), vol_size,
lsm.Volume.PROVISION_DEFAULT)[1]
@@ -328,7 +329,7 @@ class TestPlugin(unittest.TestCase):
for p in pools:
if p.free_space > mb_in_bytes(250) and \
p.element_type & lsm.Pool.ELEMENT_TYPE_FS:
- fs_size = min(p.free_space / 10, mb_in_bytes(512))
+ fs_size = min(p.free_space / 5, mb_in_bytes(30))
fs = self.c.fs_create(p, rs('fs'), fs_size)[1]
self.assertTrue(self._fs_exists(fs.id))
return fs, p
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:20 UTC
Permalink
Code move missed updates to this file.

Signed-off-by: Tony Asleson <***@redhat.com>
---
tools/netapp/netapp.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/tools/netapp/netapp.py b/tools/netapp/netapp.py
index efeb712..c86a50f 100755
--- a/tools/netapp/netapp.py
+++ b/tools/netapp/netapp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python

-# Copyright (C) 2012-2013 Red Hat, Inc.
+# Copyright (C) 2012-2014 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
@@ -19,7 +19,8 @@

import pprint
import sys
-import lsm.na
+from lsm.plugin.ontap.na import netapp_filer
+import lsm.plugin.ontap.na
import os
from optparse import OptionParser

@@ -62,9 +63,9 @@ if __name__ == '__main__':
(options, args) = parser.parse_args()
if options.command and options.host:
if options.xmlfile:
- lsm.na.xml_debug = options.xmlfile
+ lsm.plugin.ontap.na.xml_debug = options.xmlfile

- result = lsm.na.netapp_filer(options.host, user, password, 30,
+ result = netapp_filer(options.host, user, password, 30,
options.command,
process_params(options.params),
options.ssl)
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:19 UTC
Permalink
This was missed when we removed optional data.

Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/ontap/ontap.py | 3 ---
1 file changed, 3 deletions(-)

diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 62835b0..6d9d21d 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -402,7 +402,6 @@ class Ontap(IStorageAreaNetwork, INfs):
cap = Capabilities()
cap.set(Capabilities.BLOCK_SUPPORT)
cap.set(Capabilities.FS_SUPPORT)
- cap.set(Capabilities.INITIATORS)
cap.set(Capabilities.VOLUMES)
cap.set(Capabilities.VOLUME_CREATE)
cap.set(Capabilities.VOLUME_RESIZE)
@@ -462,8 +461,6 @@ class Ontap(IStorageAreaNetwork, INfs):
na_disks = []
# We do extra flags check in order to save self.f.disks() calls
# in case we have multiple aggregates.
- if flags & Pool.FLAG_RETRIEVE_FULL_INFO:
- na_disks = self.f.disks()
for na_aggr in na_aggrs:
pools.extend([self._pool_from_na_aggr(na_aggr, na_disks, flags)])
na_vols = self.f.volumes()
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:17 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Add support of target port query.
* Version dump to 2.5

v2: Merged to latest changes.

Signed-off-by: Gris Ge <***@redhat.com>
Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/sim/simarray.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-
plugin/sim/simulator.py | 8 +++++++
2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index bfab3b1..4d8dba0 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -27,7 +27,7 @@ import time

from lsm import (size_human_2_size_bytes, size_bytes_2_size_human)
from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup,
- FsSnapshot, NfsExport, md5, LsmError,
+ FsSnapshot, NfsExport, md5, LsmError, TargetPort,
ErrorNumber, JobStatus)

# Used for format width for disks
@@ -377,6 +377,18 @@ class SimArray(object):
return self.data.iscsi_chap_auth(init_id, in_user, in_pass, out_user,
out_pass, flags)

+ @staticmethod
+ def _sim_tgt_2_lsm(sim_tgt):
+ return TargetPort(
+ sim_tgt['tgt_id'], sim_tgt['port_type'],
+ sim_tgt['service_address'], sim_tgt['network_address'],
+ sim_tgt['physical_address'], sim_tgt['physical_name'],
+ sim_tgt['sys_id'])
+
+ def target_ports(self):
+ sim_tgts = self.data.target_ports()
+ return [SimArray._sim_tgt_2_lsm(t) for t in sim_tgts]
+

class SimData(object):
"""
@@ -652,6 +664,45 @@ class SimData(object):
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
}

+ self.tgt_dict = {
+ 'TGT_PORT_ID_01': {
+ 'tgt_id': 'TGT_PORT_ID_01',
+ 'port_type': TargetPort.PORT_TYPE_FC,
+ 'service_address': '50:0a:09:86:99:4b:8d:c5',
+ 'network_address': '50:0a:09:86:99:4b:8d:c5',
+ 'physical_address': '50:0a:09:86:99:4b:8d:c5',
+ 'physical_name': 'FC_a_0b',
+ 'sys_id': SimData.SIM_DATA_SYS_ID,
+ },
+ 'TGT_PORT_ID_02': {
+ 'tgt_id': 'TGT_PORT_ID_02',
+ 'port_type': TargetPort.PORT_TYPE_FCOE,
+ 'service_address': '50:0a:09:86:99:4b:8d:c6',
+ 'network_address': '50:0a:09:86:99:4b:8d:c6',
+ 'physical_address': '00:1b:21:3f:a1:b4',
+ 'physical_name': 'FCoE_b_0c',
+ 'sys_id': SimData.SIM_DATA_SYS_ID,
+ },
+ 'TGT_PORT_ID_03': {
+ 'tgt_id': 'TGT_PORT_ID_03',
+ 'port_type': TargetPort.PORT_TYPE_ISCSI,
+ 'service_address': 'iqn.1986-05.com.example:sim-tgt-03',
+ 'network_address': 'sim-iscsi-tgt-3.example.com:3260',
+ 'physical_address': 'a4:4e:31:47:f4:e0',
+ 'physical_name': 'iSCSI_c_0d',
+ 'sys_id': SimData.SIM_DATA_SYS_ID,
+ },
+ 'TGT_PORT_ID_04': {
+ 'tgt_id': 'TGT_PORT_ID_04',
+ 'port_type': TargetPort.PORT_TYPE_ISCSI,
+ 'service_address': 'iqn.1986-05.com.example:sim-tgt-03',
+ 'network_address': '10.0.0.1:3260',
+ 'physical_address': 'a4:4e:31:47:f4:e1',
+ 'physical_name': 'iSCSI_c_0e',
+ 'sys_id': SimData.SIM_DATA_SYS_ID,
+ },
+ }
+
return

def pool_free_space(self, pool_id):
@@ -1743,3 +1794,6 @@ class SimData(object):

del(self.pool_dict[pool_id])
return None
+
+ def target_ports(self):
+ return self.tgt_dict.values()
diff --git a/plugin/sim/simulator.py b/plugin/sim/simulator.py
index b98ecb8..cf03a0a 100644
--- a/plugin/sim/simulator.py
+++ b/plugin/sim/simulator.py
@@ -84,6 +84,8 @@ class SimPlugin(INfs, IStorageAreaNetwork):
rc.set(Capabilities.ACCESS_GROUPS_QUICK_SEARCH,
Capabilities.UNSUPPORTED)
rc.set(Capabilities.NFS_EXPORTS_QUICK_SEARCH, Capabilities.UNSUPPORTED)
+ rc.set(Capabilities.TARGET_PORTS_QUICK_SEARCH,
+ Capabilities.UNSUPPORTED)
return rc

def plugin_info(self, flags=0):
@@ -301,3 +303,9 @@ class SimPlugin(INfs, IStorageAreaNetwork):

def export_remove(self, export, flags=0):
return self.sim_array.fs_unexport(export.id, flags)
+
+ def target_ports(self, search_key=None, search_value=None, flags=0):
+ sim_tgts = self.sim_array.target_ports()
+ return search_property(
+ [SimPlugin._sim_data_2_lsm(t) for t in sim_tgts],
+ search_key, search_value)
--
1.8.2.1
Tony Asleson
2014-06-19 22:24:21 UTC
Permalink
Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/ontap/na.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
plugin/ontap/ontap.py | 37 +++++++++++++++++++++++++++--
2 files changed, 101 insertions(+), 2 deletions(-)

diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py
index 214cc0d..98ad03e 100644
--- a/plugin/ontap/na.py
+++ b/plugin/ontap/na.py
@@ -743,6 +743,72 @@ class Filer(object):

return result

+ def fcp_list(self):
+ fcp_list = []
+
+ try:
+
+ rc = self._invoke('fcp-adapter-list-info')
+
+ if 'fcp-config-adapters' in rc:
+ if 'fcp-config-adapter-info' in rc['fcp-config-adapters']:
+
+ adapters = rc['fcp-config-adapters']['fcp-config-adapter-info']
+ for f in adapters:
+ fcp_list.append(dict(addr=f['port-name'],
+ adapter=f['adapter']))
+ except FilerError as na:
+ if na.errno != Filer.EAPILICENSE:
+ raise na
+
+ return fcp_list
+
+ def iscsi_node_name(self):
+ try:
+ rc = self._invoke('iscsi-node-get-name')
+ if 'node-name' in rc:
+ return rc['node-name']
+ except FilerError as na:
+ if na.errno != Filer.EAPILICENSE:
+ raise na
+ return None
+
+ def interface_get_infos(self):
+ i_info = {}
+
+ rc = self._invoke('net-ifconfig-get')
+
+ if 'interface-config-info' in rc:
+ if 'interface-config-info' in rc['interface-config-info']:
+ tmp = to_list(rc['interface-config-info']['interface-config-info'])
+ for i in tmp:
+ i_info[i['interface-name']] = i
+
+ return i_info
+
+ def iscsi_list(self):
+ i_list = []
+
+ # Get interface information
+ i_info = self.interface_get_infos()
+
+ try:
+ rc = self._invoke('iscsi-portal-list-info')
+
+ if 'iscsi-portal-list-entries' in rc:
+ if 'iscsi-portal-list-entry-info' in rc['iscsi-portal-list-entries']:
+ tmp = rc['iscsi-portal-list-entries']['iscsi-portal-list-entry-info']
+ portals = to_list(tmp)
+ for p in portals:
+ i_list.append(dict(interface=p['interface-name'],
+ ip=p['ip-address'],
+ port=p['ip-port'],
+ mac=i_info[p['interface-name']]['mac-address']))
+ except FilerError as na:
+ if na.errno != Filer.EAPILICENSE:
+ raise na
+
+ return i_list

if __name__ == '__main__':
try:
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 6d9d21d..11cbf58 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -27,7 +27,7 @@ from lsm import (Volume, FileSystem, FsSnapshot, NfsExport,
AccessGroup, System, Capabilities, Disk, Pool,
IStorageAreaNetwork, INfs, LsmError, ErrorNumber, JobStatus,
md5, Error, VERSION, common_urllib2_error_handler,
- search_property)
+ search_property, TargetPort)

#Maps na to lsm, this is expected to expand over time.
e_map = {
@@ -353,7 +353,7 @@ class Ontap(IStorageAreaNetwork, INfs):
status = self._status_of_na_aggr(na_aggr)

element_type = (Pool.ELEMENT_TYPE_POOL | Pool.ELEMENT_TYPE_FS |
- Pool.ELEMENT_TYPE_VOLUME)
+ Pool.ELEMENT_TYPE_VOLUME)

# The system aggregate can be used to create both FS and volumes, but
# you can't take it offline or delete it.
@@ -442,6 +442,7 @@ class Ontap(IStorageAreaNetwork, INfs):
cap.set(Capabilities.EXPORT_FS)
cap.set(Capabilities.EXPORT_REMOVE)
cap.set(Capabilities.EXPORT_CUSTOM_PATH)
+ cap.set(Capabilities.TARGET_PORTS)
return cap

@handle_ontap_errors
@@ -1066,3 +1067,35 @@ class Ontap(IStorageAreaNetwork, INfs):
self.f.volume_split_clone(c)
return "%s@%s" % (Ontap.SPLIT_JOB, ",".join(children))
return None
+
+ @handle_ontap_errors
+ def target_ports(self, search_key=None, search_value=None, flags=0):
+ tp = []
+
+ #Get all FC
+ fcp = self.f.fcp_list()
+
+ for f in fcp:
+ a = f['addr']
+ adapter = f['adapter']
+ tp.append(TargetPort(md5(a), TargetPort.PORT_TYPE_FC, a, a, a,
+ adapter, self.sys_info.id))
+
+ node_name = self.f.iscsi_node_name()
+ iscsi = self.f.iscsi_list()
+ for i in iscsi:
+ #Get all iSCSI
+ service_address = node_name
+ network_address = "%s:%s" % (i['ip'], i['port'])
+ physical_address = i['mac']
+ physical_name = i['interface']
+ tid = md5(service_address + network_address + physical_address +
+ physical_name)
+ tp.append(TargetPort(tid, TargetPort.PORT_TYPE_ISCSI,
+ service_address,
+ network_address,
+ physical_address,
+ physical_name,
+ self.sys_info.id))
+
+ return search_property(tp, search_key, search_value)
--
1.8.2.1
Loading...