Skip to content
Snippets Groups Projects
Commit def6b3ff authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

nvmet,nvmetcli: support referrals


Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 69dad8a2
Branches
No related tags found
No related merge requests found
...@@ -659,8 +659,18 @@ class Port(CFSNode): ...@@ -659,8 +659,18 @@ class Port(CFSNode):
self._check_self() self._check_self()
for s in self.subsystems: for s in self.subsystems:
self.remove_subsystem(s) self.remove_subsystem(s)
for r in self.referrals:
r.delete()
super(Port, self).delete() super(Port, self).delete()
def _list_referrals(self):
self._check_self()
for d in os.listdir("%s/referrals/" % self._path):
yield Referral(self, d, 'lookup')
referrals = property(_list_referrals,
doc="Get the list of Referrals for this Port.")
@classmethod @classmethod
def setup(cls, root, n, err_func): def setup(cls, root, n, err_func):
''' '''
...@@ -682,11 +692,65 @@ class Port(CFSNode): ...@@ -682,11 +692,65 @@ class Port(CFSNode):
port._setup_attrs(n, err_func) port._setup_attrs(n, err_func)
for s in n.get('subsystems', []): for s in n.get('subsystems', []):
port.add_subsystem(s) port.add_subsystem(s)
for r in n.get('referrals', []):
Referral.setup(port, r, err_func)
def dump(self): def dump(self):
d = super(Port, self).dump() d = super(Port, self).dump()
d['portid'] = self.portid d['portid'] = self.portid
d['subsystems'] = self.subsystems d['subsystems'] = self.subsystems
d['referrals'] = [r.dump() for r in self.referrals]
return d
class Referral(CFSNode):
'''
This is an interface to a NVMe Referral in configFS.
'''
def __repr__(self):
return "<Referral %d>" % self.name
def __init__(self, port, name, mode='any'):
super(Referral, self).__init__()
if not isinstance(port, Port):
raise CFSError("Invalid parent class")
self.attr_groups = ['addr']
self.port = port
self._name = name
self._path = "%s/referrals/%s" % (self.port.path, self._name)
self._create_in_cfs(mode)
def _get_name(self):
return self._name
name = property(_get_name, doc="Get the Referral name.")
@classmethod
def setup(cls, port, n, err_func):
'''
Set up a Referral based upon n dict, from saved config.
Guard against missing or bad dict items, but keep going.
Call 'err_func' for each error.
'''
if 'name' not in n:
err_func("'name' not defined for Referral")
return
try:
r = Referral(port, n['name'])
except CFSError as e:
err_func("Could not create Referral object: %s" % e)
return
r._setup_attrs(n, err_func)
def dump(self):
d = super(Referral, self).dump()
d['name'] = self.name
return d return d
......
...@@ -283,6 +283,89 @@ class TestNvmet(unittest.TestCase): ...@@ -283,6 +283,89 @@ class TestNvmet(unittest.TestCase):
h.delete() h.delete()
self.assertEqual(len(list(root.hosts)), 0) self.assertEqual(len(list(root.hosts)), 0)
def test_referral(self):
root = nvme.Root()
root.clear_existing()
# create port
p = nvme.Port(root, mode='create')
self.assertEqual(len(list(p.referrals)), 0)
# create mode
r1 = nvme.Referral(p, name="1", mode='create')
self.assertIsNotNone(r1)
self.assertEqual(len(list(p.referrals)), 1)
# any mode, should create
r2 = nvme.Referral(p, name="2", mode='any')
self.assertIsNotNone(r2)
self.assertEqual(len(list(p.referrals)), 2)
# duplicate
self.assertRaises(nvme.CFSError, nvme.Referral,
p, name="2", mode='create')
self.assertEqual(len(list(p.referrals)), 2)
# lookup using any, should not create
r = nvme.Referral(p, name="1", mode='any')
self.assertEqual(r1, r)
self.assertEqual(len(list(p.referrals)), 2)
# lookup only
r = nvme.Referral(p, name="2", mode='lookup')
self.assertEqual(r2, r)
self.assertEqual(len(list(p.referrals)), 2)
# non-existant lookup
self.assertRaises(nvme.CFSError, nvme.Referral, p, name="foo",
mode='lookup')
# basic state
self.assertTrue('addr' in r.attr_groups)
self.assertFalse(r.get_enable())
# now set trtype to loop and other attrs and enable
r.set_attr('addr', 'trtype', 'loop')
r.set_attr('addr', 'adrfam', 'ipv4')
r.set_attr('addr', 'traddr', '192.168.0.1')
r.set_attr('addr', 'treq', 'not required')
r.set_attr('addr', 'trsvcid', '1023')
r.set_enable(1)
# test double enable
r.set_enable(1)
# test that we can't write to attrs while enabled
self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'trtype',
'rdma')
self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'adrfam',
'ipv6')
self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'traddr',
'10.0.0.1')
self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'treq',
'required')
self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'trsvcid',
'21')
# disable: once and twice
r.set_enable(0)
r.set_enable(0)
# check that the attrs haven't been tampered with
self.assertEqual(r.get_attr('addr', 'trtype'), 'loop')
self.assertEqual(r.get_attr('addr', 'adrfam'), 'ipv4')
self.assertEqual(r.get_attr('addr', 'traddr'), '192.168.0.1')
self.assertEqual(r.get_attr('addr', 'treq'), 'not required')
self.assertEqual(r.get_attr('addr', 'trsvcid'), '1023')
# enable again, and try to remove while enabled
r.set_enable(1)
r.delete()
# remove the other one while disabled:
r1.delete()
self.assertEqual(len(list(p.referrals)), 0)
def test_allowed_hosts(self): def test_allowed_hosts(self):
root = nvme.Root() root = nvme.Root()
......
...@@ -340,6 +340,7 @@ class UIPortNode(UINode): ...@@ -340,6 +340,7 @@ class UIPortNode(UINode):
def __init__(self, parent, cfnode): def __init__(self, parent, cfnode):
UINode.__init__(self, str(cfnode.portid), parent, cfnode) UINode.__init__(self, str(cfnode.portid), parent, cfnode)
UIPortSubsystemsNode(self) UIPortSubsystemsNode(self)
UIReferralsNode(self)
def status(self): def status(self):
if self.cfnode.get_enable(): if self.cfnode.get_enable():
...@@ -408,6 +409,85 @@ class UIPortSubsystemNode(UINode): ...@@ -408,6 +409,85 @@ class UIPortSubsystemNode(UINode):
UINode.__init__(self, nqn, parent) UINode.__init__(self, nqn, parent)
class UIReferralsNode(UINode):
def __init__(self, parent):
UINode.__init__(self, 'referrals', parent)
def refresh(self):
self._children = set([])
for r in self.parent.cfnode.referrals:
UIReferralNode(self, r)
def ui_command_create(self, name):
'''
Creates a new referral.
SEE ALSO
========
B{delete}
'''
r = nvme.Referral(self.parent.cfnode, name, mode='create')
UIReferralNode(self, r)
def ui_command_delete(self, name):
'''
Deletes the referral with the specified I{name}.
SEE ALSO
========
B{create}
'''
r = nvme.Referral(self.parent.cfnode, name, mode='lookup')
r.delete()
self.refresh()
class UIReferralNode(UINode):
def __init__(self, parent, cfnode):
UINode.__init__(self, cfnode.name, parent, cfnode)
def status(self):
if self.cfnode.get_enable():
return "enabled"
return "disabled"
def ui_command_enable(self):
'''
Enables the current Referral.
SEE ALSO
========
B{disable}
'''
if self.cfnode.get_enable():
self.shell.log.info("The Referral is already enabled.")
else:
try:
self.cfnode.set_enable(1)
self.shell.log.info("The Referral has been enabled.")
except Exception as e:
raise configshell.ExecutionError(
"The Referral could not be enabled.")
def ui_command_disable(self):
'''
Disables the current Referral.
SEE ALSO
========
B{enable}
'''
if not self.cfnode.get_enable():
self.shell.log.info("The Referral is already disabled.")
else:
try:
self.cfnode.set_enable(0)
self.shell.log.info("The Referral has been disabled.")
except Exception as e:
raise configshell.ExecutionError(
"The Referral could not be disabled.")
class UIHostsNode(UINode): class UIHostsNode(UINode):
def __init__(self, parent): def __init__(self, parent):
UINode.__init__(self, 'hosts', parent) UINode.__init__(self, 'hosts', parent)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment